Qué es la API
La API pública de Copilot EFB da acceso de lectura a los datos propios de cada piloto — aeronaves, fichas de aeródromo con sus frecuencias, pistas y calles de rodaje, meteorología en sus aeródromos, notas, checklists, rutas planificadas en el mapa, planes de vuelo, libro de vuelo y perfil — para que un servicio propio aproveche lo que ya llevas en el bolso de vuelo.
Lee todo y escribe dos cosas, ambas del plugin RogerATC AI para X-Plane: los resúmenes de sesión en PUT /v1/plugin/sessions/{id} y el estado en vivo en PUT /v1/plugin/live. Nada de lo que un piloto cargó en el EFB se puede modificar ni borrar a través de ella, y cualquier otro método responde 405.
La clave lee todo lo que tiene la cuenta, perfil del piloto incluido: números de licencia, certificado médico, teléfono. Guárdala en un servidor. La API no envía encabezados CORS, a propósito, así que una página web no puede llamarla: nunca pongas la clave en una página web ni en una aplicación móvil.
La referencia en vivo, generada a partir del propio código de la API, está en api.rogeratc.app/docs, y la descripción OpenAPI 3.1, legible por máquina, en api.rogeratc.app/openapi.json. Esta página se contrasta con una copia de esa descripción cada vez que se genera el sitio.
Primeros pasos
Copia la clave desde Copilot EFB → Ajustes → Acceso a la API y pruébala:
export ROGER_API_KEY="rat_live_…"
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/me
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/aircraft
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/weatherGET /v1/me es la forma más barata de comprobar que una clave funciona: indica a qué cuenta pertenece.
Tu clave de API
Cada cuenta de Copilot EFB tiene una clave personal desde el momento en que se confirma: no hay que solicitar nada. Está en Ajustes → Acceso a la API, junto con su uso.
| Momento | Qué ocurre |
|---|---|
| Cuenta confirmada | Se crea la clave. Una cuenta anterior a las claves la recibe en su próximo inicio de sesión. |
| Ajustes → Acceso a la API | Se muestra la clave, con sus primeros caracteres (prefix) para distinguir claves sin revelarlas. |
| Rotar | Una clave nueva reemplaza a la anterior, que deja de funcionar en el instante en que termina la rotación. Cada integración que la usaba necesita la nueva. |
| Cuenta pausada | La clave queda suspendida junto con la cuenta y responde 401. Al reactivar la cuenta, vuelve a funcionar. |
| Cuenta eliminada | La clave se elimina con todo lo demás. |
Formato: rat_live_ seguido de 43 caracteres base64url (32 bytes aleatorios). La API nunca devuelve la clave: GET /v1/me muestra sólo su prefijo y sus fechas.
Si alguien pudo haber visto la clave — una captura, un documento compartido, un commit —, rótala. La rotación es inmediata y sólo exige actualizar tus integraciones.
Estadísticas de uso
Ajustes → Acceso a la API muestra también cómo se usó la clave: solicitudes por día y por endpoint, hasta 90 días, cuántas fueron errores y cuándo se usó por última vez. Los contadores son por día UTC y por plantilla de ruta, por ejemplo GET /v1/aircraft/{id}.
Se cuenta cada solicitud a una ruta existente hecha con una clave válida, cualquiera sea su estado — un 404 por un registro que no existe, un 400, un 429 —, porque para eso están las estadísticas. Una ruta que no existe, y cualquier solicitud sin una clave válida, no se pueden atribuir a una cuenta y no se cuentan.
Autenticación
Envía la clave en cada solicitud, en cualquiera de estos encabezados:
Authorization: Bearer rat_live_x3V…
X-API-Key: rat_live_x3V…Sólo GET /v1/health y la propia referencia — /docs y /openapi.json — responden sin clave.
Una clave ausente, mal formada, desconocida o rotada, o la clave de una cuenta pausada o eliminada, responde 401 unauthorized con WWW-Authenticate: Bearer. La API no dice cuál de esos casos fue.
Solicitudes y respuestas
- Métodos:
GET, yPUTúnicamente en/v1/plugin/sessions/{id}y/v1/plugin/live. Sólo HTTPS (TLS 1.2 o superior), sólo JSON. - Las horas están en UTC, ISO 8601. Las duraciones del libro de vuelo son minutos enteros.
- Un valor que la aplicación no conoce es
nullo no está — nunca se inventa. - Las respuestas con datos llevan
Cache-Control: no-store, private. - Toda respuesta lleva
X-Request-Id, el mismo valor quemeta.requestId. Cítalo cuando algo salga mal.
Un recurso:
{
"data": {
"id": "ac-1",
"registration": "LV-XXX",
"icaoType": "C172",
"updatedAt": "2026-09-17T11:16:29.900Z",
"…": "…"
},
"meta": { "requestId": "Q2a8vg…", "generatedAt": "2026-09-17T15:02:11.410Z" }
}Una colección:
{
"data": [ { "id": "…", "…": "…" } ],
"page": { "limit": 50, "total": 2, "nextCursor": null },
"meta": { "requestId": "…", "generatedAt": "…" }
}Qué es un registro
Un registro se devuelve completo: cada campo que guarda la aplicación, tal como lo sincronizó el EFB, más id y updatedAt, que siempre están. Los registros eliminados nunca se devuelven.
Un campo que la aplicación agrega aparece en la API el mismo día en que se sincroniza, sin versión nueva. Ignora los campos que no reconozcas. Los ejemplos de esta página están recortados; un registro real trae más.
Errores
{
"error": { "code": "not_found", "message": "No aircraft with id \"x\" in this account." },
"meta": { "requestId": "…", "generatedAt": "…" }
}| Estado | code | Cuándo |
|---|---|---|
400 | bad_request | Un parámetro o un campo está mal formado; el mensaje lo nombra. |
401 | unauthorized | Sin clave, clave mal formada o desconocida, clave rotada, cuenta pausada o eliminada. |
404 | not_found | No existe la ruta, o no existe el registro en esta cuenta. |
405 | method_not_allowed | Un método que la ruta no acepta. Allow enumera los que sí. |
410 | gone | Un PUT de una sesión del plugin que el piloto eliminó en el EFB. Deja de enviarla. |
413 | payload_too_large | Un cuerpo de PUT de más de 512 KB. |
415 | unsupported_media_type | Un cuerpo de PUT que no es application/json. |
429 | rate_limited | Por encima del límite de la clave. Retry-After indica cuántos segundos esperar. |
500 | internal | Falla nuestra. Cita meta.requestId. |
Los códigos son estables: apóyate en ellos. Los mensajes son texto en inglés para quien desarrolla y pueden cambiar.
Paginación y seguimiento de cambios
Las colecciones aceptan:
| Parámetro | Significado |
|---|---|
limit | De 1 a 200, 50 por omisión. Una página puede traer menos cuando los registros son grandes: una nota puede llevar un dibujo. |
cursor | Opaco. Devuelve page.nextCursor para pedir la página siguiente; null significa que no hay más. |
updatedSince | ISO 8601. Sólo los registros modificados después de ese instante. |
El cursor es un desplazamiento dentro de la colección ordenada, así que un registro escrito entre dos pedidos de página puede correr una página. Para seguir los cambios, usa updatedSince con el updatedAt más reciente que hayas visto: así recibes cada cambio exactamente una vez, sin importar el orden.
curl -s -H "X-API-Key: $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/aircraft?limit=100&updatedSince=2026-09-17T00:00:00Z"Límites de uso
- Por clave: 120 solicitudes por minuto. Por encima,
429 rate_limitedconRetry-Afteren segundos. - Toda la API: 25 solicitudes por segundo sostenidas, ráfagas de 50.
- La meteorología se guarda en caché hasta cinco minutos por aeródromo, sin importar cuántas veces la pidas;
fetchedAtindica cuándo se obtuvo.
Endpoints
Todas las rutas salvo GET /v1/health requieren la clave. Las colecciones están paginadas y ordenadas como se indica en cada una.
| Método | Ruta | Clave | Devuelve |
|---|---|---|---|
| GET | /v1/health | no | Estado del servicio |
| GET | /v1/me | sí | La cuenta y su clave |
| GET | /v1/aerodromes | sí | Fichas de aeródromo (paginadas) |
| GET | /v1/aerodromes/{id} | sí | Una ficha, por id o por identificador |
| GET | /v1/aerodromes/{id}/attachments/{attachmentId} | sí | Enlace de descarga de un adjunto de la ficha |
| GET | /v1/aircraft | sí | Aeronaves (paginadas) |
| GET | /v1/aircraft/{id} | sí | Una aeronave |
| GET | /v1/aircraft/{id}/attachments/{attachmentId} | sí | Enlace de descarga de un documento de la aeronave |
| GET | /v1/weather | sí | METAR y TAF en cada aeródromo del piloto |
| GET | /v1/weather/{ident} | sí | METAR y TAF en un aeródromo |
| GET | /v1/notes | sí | Notas (paginadas) |
| GET | /v1/notes/{id} | sí | Una nota |
| GET | /v1/checklists | sí | Checklists (paginadas) |
| GET | /v1/checklists/{id} | sí | Una checklist |
| GET | /v1/check-flights | sí | Vuelos de checklists (paginados) |
| GET | /v1/check-flights/{id} | sí | Un vuelo |
| GET | /v1/flight-plans | sí | Planes de vuelo (paginados) |
| GET | /v1/flight-plans/{id} | sí | Un plan de vuelo |
| GET | /v1/plannings | sí | Planificaciones (paginadas) |
| GET | /v1/plannings/{id} | sí | Una planificación |
| GET | /v1/logbook | sí | Asientos del libro de vuelo (paginados) |
| GET | /v1/logbook/totals | sí | Horas sumadas, en minutos |
| GET | /v1/logbook/{id} | sí | Un asiento |
| GET | /v1/pilot | sí | El perfil del piloto |
| PUT | /v1/plugin/sessions/{id} | sí | Guarda una sesión de RogerATC AI — la única escritura |
| PUT | /v1/plugin/live | sí | Informa el estado en vivo y recoge las instrucciones pendientes |
| GET | /v1/plugin/sessions | sí | Sesiones de RogerATC AI (paginadas) |
| GET | /v1/plugin/sessions/{id} | sí | Una sesión de RogerATC AI |
| GET | /v1/plugin/stats | sí | Totales de todas las sesiones de RogerATC AI |
Estado del servicio
- GET
/v1/healthEstado del servicio sin clave
Sin clave, sin datos y sin contar en las estadísticas de uso. Para monitores de disponibilidad.
curl -s https://api.rogeratc.app/v1/health{ "data": { "ok": true, "version": "1.0.0" }, "meta": { … } }Cuenta
- GET
/v1/meLa cuenta y su clave
A qué cuenta pertenece una clave. La clave nunca se devuelve: sólo su prefijo y sus fechas.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/me{
"data": {
"userId": "44080428-f051-7019-a08f-286b3c97b052",
"email": "…",
"displayName": "Martín",
"accountCreatedAt": "2026-09-08T18:15:14.171Z",
"apiKey": {
"prefix": "rat_live_x3V9",
"createdAt": "2026-09-17T15:00:00.000Z",
"rotatedAt": null
}
},
"meta": { … }
}Fichas de aeródromo
- GET
/v1/aerodromesFichas de aeródromo (paginadas) - GET
/v1/aerodromes/{id}Una ficha, por id o por identificador - GET
/v1/aerodromes/{id}/attachments/{attachmentId}Enlace de descarga de un adjunto de la ficha
Las fichas de aeródromo del piloto: frecuencias, contactos, VOR/DME, pistas, calles de rodaje, posición, elevación, notas y el texto de NOTAM y MADHEL que el piloto copió en la ficha. Ordenadas por code.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
{id} | El id de la ficha o el identificador del aeródromo, sin distinguir mayúsculas: /v1/aerodromes/SADF, /v1/aerodromes/len. |
El identificador es el indicador de lugar OACI cuando el aeródromo lo tiene, y el código nacional de tres letras cuando no — como en la mayoría de las pistas argentinas, por ejemplo LEN (Escobar) o SNY (San Nicolás).
taxiways es una lista de { id, designator, surface, widthM, lighted, notes } que el piloto carga desde la carta del aeródromo; nunca viene precargada. Una lista vacía o ausente significa que no se cargó ninguna en la ficha, y no dice nada sobre el aeródromo.
Son las fichas del propio piloto, datos de referencia cargados desde una carta. No son la AIP.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/aerodromes/SADF{
"data": {
"id": "7f0c…", "code": "SADF", "name": "San Fernando", "elevationFt": 10,
"frequencies": { "tower": "119.000", "ground": "121.850", "atis": null, "…": "…" },
"contacts": { "aroAisPhone": "…", "…": "…" },
"runways": [
{ "designator": "05/23", "lengthM": 1690, "widthM": 30, "surface": "ASP", "…": "…" }
],
"taxiways": [
{ "id": "…", "designator": "…", "surface": "…", "widthM": null,
"lighted": null, "notes": "…" }
],
"notam": "", "madhel": "", "notes": "",
"createdAt": "…", "updatedAt": "…"
},
"meta": { … }
}Adjuntos
attachments lista los diagramas, procedimientos de entrada y salida y fotos que el piloto adjuntó: { id, name, contentType, bytes, kind, createdAt }, con kind diagram, procedures, photo u other. La ficha sólo lleva esos datos; los archivos están en un almacenamiento privado. GET /v1/aerodromes/{id}/attachments/{attachmentId} devuelve uno con una URL HTTPS firmada, válida por 15 minutos: pídela directamente y sin la clave. 404 si la ficha no lista ese id o si el archivo todavía no se subió — un adjunto agregado sin señal se sube en la siguiente sincronización.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/aerodromes/SADF/attachments/0b7e…"{
"data": {
"id": "0b7e…", "name": "SADF diagrama.pdf", "contentType": "application/pdf",
"bytes": 812345, "kind": "diagram", "createdAt": "2026-09-18T12:00:00.000Z",
"url": "https://…/u/…?X-Amz-Signature=…",
"urlExpiresAt": "2026-09-18T12:15:00.000Z"
},
"meta": { … }
}Aeronaves
- GET
/v1/aircraftAeronaves (paginadas) - GET
/v1/aircraft/{id}Una aeronave - GET
/v1/aircraft/{id}/attachments/{attachmentId}Enlace de descarga de un documento de la aeronave
Cada perfil de aeronave con todos sus campos: matrícula, tipo OACI, códigos de equipamiento y de vigilancia, velocidades, combustible, pesos, brazos y envolvente. Ordenados por registration.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" "https://api.rogeratc.app/v1/aircraft?limit=20"Documentos
attachments lista el manual de vuelo, los documentos y las fotos de la aeronave, con la misma forma que los de una ficha y kind manual, document, photo u other. GET /v1/aircraft/{id}/attachments/{attachmentId} funciona igual que el de aeródromos: una URL firmada por 15 minutos, sin la clave, y 404 si no existe o todavía no se subió. Un archivo puede pesar hasta 100 MB.
Meteorología
- GET
/v1/weatherMETAR y TAF en cada aeródromo del piloto - GET
/v1/weather/{ident}METAR y TAF en un aeródromo
El último METAR y TAF, en crudo y decodificados, para cada aeródromo que tiene el piloto: cada ficha de aeródromo y cada aeródromo de su briefing meteorológico. sources indica de dónde sale (aerodromeCard, briefing). /v1/weather/{ident} responde para cualquier identificador, esté o no en las listas del piloto.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/weather{
"data": [
{
"ident": "SAEZ", "name": "Ezeiza", "sources": ["aerodromeCard", "briefing"],
"status": "ok",
"metar": {
"raw": "METAR SAEZ 171400Z 35009KT CAVOK 21/10 Q1023 NOSIG",
"observedAt": "2026-09-17T14:00:00.000Z",
"ageMinutes": 12,
"flightCategory": "VFR",
"decoded": { "wind": { … }, "ceilingAglFt": null, "unparsed": [], "…": "…" }
},
"taf": {
"raw": "TAF SAEZ 171100Z 1712/1812 …",
"issuedAt": "…", "validFrom": "…", "validTo": "…",
"decoded": { … }
},
"provider": "NOAA Aviation Weather Center (aviationweather.gov)",
"fetchedAt": "2026-09-17T14:12:03.000Z"
},
{
"ident": "LEN", "name": "Escobar", "sources": ["aerodromeCard"],
"status": "no_icao_indicator",
"metar": null, "taf": null, "provider": "…", "fetchedAt": null
}
],
"meta": { … }
}status | Significado |
|---|---|
ok | Un METAR, un TAF o ambos. Cada uno lleva su fecha; nada se descarta por viejo. |
no_report | Se consultó a NOAA y no tiene nada para ese indicador. |
no_icao_indicator | El aeródromo se identifica con un código nacional; no hay estación a la cual consultar. |
unavailable | No se pudo contactar a NOAA. No es lo mismo que no haya meteorología. |
Por qué nada se inventa
decoded es la salida del propio decodificador del EFB, así que la API y la pantalla no pueden discrepar sobre un techo. Los grupos que el decodificador no entiende se listan en unparsed; nunca se adivinan.
Un reporte nunca se descarta por viejo: cada uno trae su hora y ageMinutes, y decidir si es demasiado viejo te corresponde a ti. Los cuatro estados se mantienen separados a propósito: un aeródromo sin estación a la cual consultar, o un proveedor que no respondió, no son un aeródromo sin meteorología. provider nombra la fuente en cada elemento.
Notas
- GET
/v1/notesNotas (paginadas) - GET
/v1/notes/{id}Una nota
La tablilla de rodilla: cada nota con todos sus campos, incluida la imagen de una nota manuscrita como data URL PNG (imageDataUrl). Primero el cambio más reciente. Nada de una nota se interpreta.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/notesChecklists
- GET
/v1/checklistsChecklists (paginadas) - GET
/v1/checklists/{id}Una checklist
Cada checklist que el piloto armó a partir de la documentación de su aeronave, con sus secciones e ítems. Ordenadas por aeronave y luego por el orden que eligió el piloto. El EFB no trae checklists precargadas: cada una la escribió el piloto.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
aircraftId | Sólo las checklists de esa aeronave — un id de GET /v1/aircraft. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/checklists?aircraftId=ac-1"Vuelos de checklists
- GET
/v1/check-flightsVuelos de checklists (paginados) - GET
/v1/check-flights/{id}Un vuelo
Un registro por cada vuelo en el que se corrieron las checklists de una aeronave: startedAt, completedAt (ausente mientras el vuelo sigue abierto: muchas listas se corren en el aire), lists en el orden de ese día y summary: { total, done, missing: [{ checklist, section, challenge, critical }] }. El resumen se toma mientras transcurre el vuelo, así que sigue diciendo qué quedó sin tildar aunque después se edite o borre la lista. autoClosed: true marca un vuelo que cerró la app y no el piloto: uno abierto más de doce horas se cierra en su última actividad, nunca en el momento en que se lo notó.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
aircraftId | Sólo los vuelos de esa aeronave — un id de GET /v1/aircraft. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/check-flights?aircraftId=ac-1"Planes de vuelo
- GET
/v1/flight-plansPlanes de vuelo (paginados) - GET
/v1/flight-plans/{id}Un plan de vuelo
Cada plan de vuelo OACI con todos sus campos: casillas 7 a 19, los puntos de la ruta, la información suplementaria y la dirección de presentación. Primero la departureDate más reciente. Un plan hecho desde una planificación lleva planningId.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/flight-plansPlanificaciones
- GET
/v1/planningsPlanificaciones (paginadas) - GET
/v1/plannings/{id}Una planificación
Cada ruta que el piloto armó en el mapa: los puntos en orden con su posición, la aeronave, la salida prevista, la altitud, el combustible a bordo, la reserva y el viento elegido, y el plan de vuelo en que se convirtió (flightPlanId). departure, destination y waypoints repiten lo que dice points. Primero el cambio más reciente.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/planningsLibro de vuelo
- GET
/v1/logbookAsientos del libro de vuelo (paginados) - GET
/v1/logbook/totalsHoras sumadas, en minutos - GET
/v1/logbook/{id}Un asiento
Cada vuelo del libro. La línea del libro de vuelo de ANAC (RAAC 61.120) está en log: las ocho celdas de tiempo de vuelo, la discriminación, el tiempo de simulador, los aterrizajes, las aproximaciones y el código de finalidad. Primero la log.date más reciente.
Las duraciones son minutos enteros: nunca horas decimales ni hh:mm. 90 es una hora y media; dale el formato que necesite tu servicio.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación — ver Paginación y seguimiento de cambios. |
from | Sólo para los totales. Primera log.date que se cuenta, AAAA-MM-DD, inclusive. Opcional. |
to | Sólo para los totales. Última log.date que se cuenta, inclusive. Opcional. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" "https://api.rogeratc.app/v1/logbook?limit=100"Totales
curl -s -H "Authorization: Bearer $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/logbook/totals?from=2026-01-01&to=2026-12-31"{
"data": {
"unit": "minutes", "from": "2026-01-01", "to": "2026-12-31",
"totals": {
"flight": 5130, "pilot": 5130, "copilot": 0, "day": 4800, "night": 330,
"local": 1200, "crossCountry": 3930, "instructorGiven": 0,
"instrumentReal": 0, "instrumentHood": 60, "multiEngine": 0,
"simulator": 120, "landings": 61, "entries": 38
},
"logged": {
"unit": "tenths", "total": 856, "crossCountry": 656, "local": 200,
"pilot": 856, "copilot": 0, "day": 801, "night": 55, "simulator": 20,
"instructorGiven": 0, "instrumentReal": 0, "instrumentHood": 10,
"multiEngine": 0, "landings": 61, "entries": 38
}
},
"meta": { … }
}data.logged son las cifras que muestra la pantalla del libro: las horas decimales de cada vuelo — sus celdas redondeadas a la décima más cercana (1:50 es 1,8), salvo que el piloto haya escrito su propia cifra (loggedTenths en la línea) —, sumadas de modo que crossCountry + local, pilot + copilot y day + night den siempre total. Van en décimas de hora ("unit": "tenths", enteros: 18 es 1,8 h). simulator va aparte y no suma al total. data.totals, en minutos, no cambió.
Se calcula con la misma función que la pantalla Libro de vuelo del EFB, así que no pueden discrepar. Las celdas de la discriminación desglosan horas ya contadas en las celdas de tiempo de vuelo y nunca se suman a flight; el tiempo de simulador no es tiempo de vuelo. Un vuelo sin línea de libro no se cuenta — entries dice cuántos se contaron — y una celda vacía cuenta como cero.
Perfil del piloto
- GET
/v1/pilotEl perfil del piloto
Nombre, teléfono, licencias, habilitaciones con su vencimiento y certificado médico — o data: null si el piloto no creó un perfil. Es el mismo perfil que muestra el EFB, y lo más sensible que puede leer la clave.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/pilotPlugin RogerATC AI
RogerATC AI, el plugin de control aéreo por voz para X-Plane 12, puede guardar el historial de sus sesiones en la cuenta de Copilot EFB del piloto. Cuando el piloto activa la sincronización con el EFB en el plugin — viene desactivada, y permite elegir entre sólo estadísticas o estadísticas con el registro de eventos —, el plugin envía un resumen de cada sesión de simulador, autenticado con la clave del propio piloto. El EFB lo guarda en la cuenta, así que aparece en cada dispositivo donde el piloto tenga la sesión iniciada, y lo devuelve aquí.
Con la misma clave, el plugin lee lo que el piloto ya tiene en el EFB, a través de los endpoints anteriores: la flota, las fichas de aeródromo con sus frecuencias, pistas y calles de rodaje, las checklists y los planes de vuelo.
RogerATC AI está en desarrollo y todavía no se publicó. Esta sección es el contrato sobre el que se construye su sincronización con el EFB.
Guardar una sesión
- PUT
/v1/plugin/sessions/{id}Guarda una sesión de RogerATC AI — la única escritura
Un upsert idempotente de una sesión completa. Se envía al comenzar, en un punto de control cada pocos minutos si algo cambió, y una vez al terminar: siempre la sesión entera, siempre con el mismo id. Reintentar después de una conexión caída no causa ningún problema.
| Parámetro | Significado |
|---|---|
{id} | El id de sesión del plugin, estable durante todo el vuelo: de 3 a 128 caracteres entre A–Z a–z 0–9 . _ -, empezando por una letra o un dígito. |
PUT /v1/plugin/sessions/5f0c2a4e-7d1b-4c6a-9d0e-2b8f1c3a6e77 HTTP/1.1
Host: api.rogeratc.app
Authorization: Bearer rat_live_…
Content-Type: application/json{
"schema": 1,
"status": "completed",
"startedAt": "2026-09-17T18:02:11Z",
"endedAt": "2026-09-17T19:14:40Z",
"pluginVersion": "0.4.0",
"protocolVersion": "1",
"simulator": "X-Plane 12.1.4",
"language": "es",
"region": "AR",
"dataSource": "both",
"aircraft": { "registration": "LV-XXX", "icaoType": "C172" },
"departure": "SADF",
"arrival": "SAAR",
"aerodromesVisited": ["SADF", "SAAR"],
"stats": {
"transmissions": 42, "fastPath": 30, "modelCalls": 12, "sayAgain": 2,
"readbacksCorrect": 17, "readbacksIncorrect": 1, "positionCorrections": 0,
"unprompted": 4, "emergencies": 0, "instructorQuestions": 3,
"meanResponseMs": 1850, "p95ResponseMs": 3400,
"byStation": { "ground": 9, "tower": 14, "approach": 11, "centre": 8 },
"byIntent": { "request_taxi": 2, "ready_departure": 1, "position_report": 6 }
},
"events": [
{
"at": "2026-09-17T18:04:02Z", "kind": "turn",
"station": "San Fernando Superficie", "intent": "request_taxi", "template": "taxi-clearance",
"heard": "San Fernando superficie, LV-XXX en plataforma, solicito rodaje",
"said": "LV-XXX, ruede a punto de espera pista 05, QNH 1018"
}
]
}Campos del cuerpo
| Campo | Obligatorio | Reglas |
|---|---|---|
schema | sí | 1. |
startedAt | sí | ISO 8601. No más de un día en el futuro. |
endedAt | no | ISO 8601, o null mientras se vuela. |
status | no | in_progress, completed o aborted. Si falta: completed cuando hay endedAt, y si no in_progress. |
pluginVersion, protocolVersion, simulator, language, region | no | Cadenas cortas, sin espacios sobrantes. En language y region se normaliza el uso de mayúsculas. |
dataSource | no | sim, both o efb: de dónde tomó el plugin los datos de aeródromo. Cualquier otro valor se guarda como null. |
aircraft | no | { registration, icaoType }, en mayúsculas. |
departure, arrival | no | Un identificador de aeródromo: 3 o 4 caracteres A–Z 0–9 (OACI, o un código nacional cuando no hay). Cualquier otro valor se guarda como null. |
aerodromesVisited | no | Hasta 20 identificadores, sin repetidos. |
stats | no | Los diez contadores del ejemplo, enteros y no negativos (cualquier otro valor cuenta como 0); meanResponseMs y p95ResponseMs o null; byStation hasta 30 claves y byIntent hasta 60, con claves que cumplan [a-z0-9][a-z0-9_.-]{0,39}, conservando las mayores. |
events | no | Sólo con el registro de eventos activado. Hasta 200, se conservan los más recientes. kind: turn, unprompted, silence, error o instructor; at obligatorio; station, intent, template; heard se corta en 160 caracteres y said en 240. Los eventos de un tipo desconocido o sin un at válido se descartan. |
eventsDropped | no | Lo que el plugin ya descartó antes de enviar; se suma a la cuenta del servidor. |
Cualquier otra cosa en el cuerpo se ignora y no se guarda. En una sesión no va nada derivado del escenario ni de los datos de navegación de X-Plane, ni audio, ni claves de proveedores.
Límites
- El cuerpo pesa como máximo 512 KB; por encima,
413. - La sesión guardada ocupa como máximo 200 KB: se quitan los eventos más antiguos hasta que entre, y
eventsDroppedlos cuenta. - Un registro por sesión, nunca uno por cada comunicación.
Respuestas
| Estado | Cuerpo | Significado |
|---|---|---|
201 | { id, status, receivedAt, eventsStored, eventsDropped } | La primera vez que se guarda este id. |
200 | el mismo | Se reemplazó la copia guardada. createdAt se conserva desde la primera llegada. |
400 | error | Un campo no cumple una de las reglas anteriores; el mensaje lo nombra. |
410 | error gone | El piloto eliminó esta sesión en el EFB. Deja de enviarla: no se volverá a guardar. |
413 · 415 | error | Demasiado grande, o no es JSON. |
401 · 429 | error | La clave, o el límite de uso. Un PUT cada pocos minutos queda muy por debajo. |
curl -s -X PUT \
-H "Authorization: Bearer $ROGER_API_KEY" \
-H "Content-Type: application/json" \
--data @session.json \
https://api.rogeratc.app/v1/plugin/sessions/5f0c2a4e-7d1b-4c6a-9d0e-2b8f1c3a6e77HTTP/1.1 201 Created
{
"data": {
"id": "5f0c2a4e-7d1b-4c6a-9d0e-2b8f1c3a6e77",
"status": "completed",
"receivedAt": "2026-09-17T19:14:42.018Z",
"eventsStored": 1,
"eventsDropped": 0
},
"meta": { … }
}La parte del plugin en el contrato
- El simulador nunca espera a la API. Las solicitudes salen de una cola en disco, en segundo plano, con un tiempo de espera corto y reintentos espaciados, fuera de los hilos de audio y del simulador. Un error, un tiempo agotado o la falta de red son silencio; nunca un simulador detenido.
401significa que la clave se rotó o la cuenta se pausó: se deja de enviar y se avisa al piloto una sola vez.410significa que el piloto eliminó esa sesión: se quita de la cola y no se vuelve a enviar.429significa esperar lo que indicaRetry-Afterantes del próximo intento.
Enlace en vivo
- PUT
/v1/plugin/liveInforma el estado en vivo y recoge las instrucciones pendientes
Mientras el piloto vuela con el enlace en vivo activado en el plugin (efb_live = on, desactivado por defecto), el plugin llama a esta ruta cada pocos segundos con su estado medido — posición, altitud, velocidades, rumbo, en tierra o en vuelo, COM1, transpondedor, QNH, viento — y con el resultado de cada instrucción que atendió. La respuesta trae las instrucciones que el instructor dejó en la consola RogerATC del EFB, y cuánto esperar antes de volver a llamar (pollMs).
No es un registro sincronizado: el estado se sobrescribe en cada llamada y el servidor lo olvida a los diez minutos. Nunca se guarda una trayectoria. Las radioayudas, frecuencias y pistas no viajan: salen de los datos de navegación del simulador, cuya licencia prohíbe que dejen la máquina del piloto, y el EFB los calcula con su propia base pública.
Cada instrucción se entrega una sola vez. Una que el plugin no recogió en dos minutos caduca y nunca se entrega tarde. El plugin responde en el siguiente informe con spoken y el texto exacto que dijo el controlador, o con refused y un motivo (on_ground, unknown_navaid, no_dme…). El motor del plugin redacta cada palabra; el EFB sólo la pide.
curl -X PUT https://api.rogeratc.app/v1/plugin/live \
-H "Authorization: Bearer $COPILOT_EFB_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "schema": 1, "sessionId": "2026-10-03_1415", "sentAt": "2026-10-03T14:15:02Z",
"aircraft": { "registration": "LV-XXX", "icaoType": "C172" },
"sim": { "paused": false, "phase": "cruise", "onGround": false,
"latDeg": -34.6, "lonDeg": -58.7, "altitudeFt": 2500, "headingMagDeg": 270,
"groundspeedKt": 95, "verticalSpeedFpm": 0, "…": "…" },
"aerodrome": { "ident": "SADF", "activeRunway": "05" },
"transcript": [], "acks": [] }'{
"data": {
"commands": [
{ "id": "1759500902000-x7Kq2m9A", "createdAt": "2026-10-03T14:15:00Z",
"request": { "kind": "holding", "navaid": "SFD", "inboundCourseDeg": 50,
"turn": "right", "legMinutes": null, "altitudeFt": 2500 } }
],
"pollMs": 2000
}
}Leer sesiones
- GET
/v1/plugin/sessionsSesiones de RogerATC AI (paginadas) - GET
/v1/plugin/sessions/{id}Una sesión de RogerATC AI
Cada sesión guardada, primero el startedAt más reciente, tal como se guardó: los campos del cuerpo más id, source (rogeratc-plugin), durationMinutes (del inicio al fin, o hasta la última llegada mientras sigue en curso), eventsDropped, receivedAt, createdAt y updatedAt.
| Parámetro | Significado |
|---|---|
limit · cursor · updatedSince | Paginación. updatedSince es la forma de seguir las sesiones que siguen en curso. |
curl -s -H "Authorization: Bearer $ROGER_API_KEY" \
"https://api.rogeratc.app/v1/plugin/sessions?updatedSince=2026-09-17T18:00:00Z"Totales
- GET
/v1/plugin/statsTotales de todas las sesiones de RogerATC AI
Los mismos totales que muestra la pantalla RogerATC AI del EFB. minutes es la suma de durationMinutes de todas las sesiones. meanResponseMs se pondera por las transmisiones de cada sesión, y es null cuando no se midió nada.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/plugin/stats{
"data": {
"sessions": 12,
"byStatus": { "in_progress": 0, "completed": 11, "aborted": 1 },
"minutes": 842, "transmissions": 506,
"readbacksCorrect": 201, "readbacksIncorrect": 9,
"sayAgain": 14, "emergencies": 1, "instructorQuestions": 37,
"meanResponseMs": 1910,
"firstStartedAt": "…", "lastStartedAt": "…",
"byStation": { "tower": 180, "ground": 120, "approach": 110, "centre": 96 },
"aerodromes": [{ "ident": "SADF", "sessions": 9 }],
"aircraft": [{ "label": "LV-XXX", "sessions": 10 }]
},
"meta": { … }
}Versiones y cambios
Las rutas llevan la versión mayor. Las rutas nuevas, los campos nuevos y los valores nuevos de status se suman y quedan en /v1, así que un cliente debe ignorar lo que no reconoce. Todo lo que rompería a un cliente que sigue esta página va a una versión mayor nueva, y /v1 se mantiene hasta que sus usuarios hayan migrado.
| Versión | Fecha | Cambio |
|---|---|---|
1.11.0 | 2026-10-03 | GET /v1/plannings y GET /v1/plannings/{id}: las rutas planificadas en el mapa. Un plan de vuelo hecho desde una planificación lleva planningId. Aditivo. |
1.10.0 | 2026-10-03 | PUT /v1/plugin/live: el enlace en vivo de RogerATC AI — el estado medido del simulador y las instrucciones del instructor. La segunda escritura de la API, con estado que caduca y no se sincroniza. Aditivo. |
1.9.0 | 2026-09-24 | /v1/logbook/totals agrega data.logged, las horas decimales en décimas que muestra la pantalla del libro. Las líneas pueden llevar loggedTenths. Aditivo. |
1.8.0 | 2026-09-22 | Los planes de vuelo llevan signatureDataUrl, la firma de ese plan. Los vuelos de checklists llevan autoClosed. Aditivo. |
1.7.0 | 2026-09-19 | Las aeronaves llevan attachments — manuales, documentos y fotos — y GET /v1/aircraft/{id}/attachments/{attachmentId} da un enlace de descarga temporal. Límite por archivo: 100 MB. Aditivo. |
1.6.0 | 2026-09-18 | Vuelos de checklists: GET /v1/check-flights y GET /v1/check-flights/{id}. Aditivo. |
1.5.0 | 2026-09-18 | Las fichas de aeródromo llevan aids (radioayudas y ayudas visuales) y fuel.products (aceites y aditivos). Aditivo. |
1.4.0 | 2026-09-18 | Las fichas de aeródromo llevan attachments, y GET /v1/aerodromes/{id}/attachments/{attachmentId} da un enlace de descarga temporal. Aditivo. |
1.3.1 | 2026-09-17 | Revisión de seguridad: permisos mínimos para la API, un tope diario de sesiones nuevas del plugin, y reiniciar una cuenta rota su clave. |
1.3.0 | 2026-09-17 | Las fichas de aeródromo llevan fuel. Aditivo. |
1.2.0 | 2026-09-17 | Checklists: GET /v1/checklists y GET /v1/checklists/{id}. Sesiones del plugin RogerATC AI: PUT /v1/plugin/sessions/{id} (la primera escritura), GET /v1/plugin/sessions, GET /v1/plugin/sessions/{id} y GET /v1/plugin/stats. Nuevos códigos de error gone, payload_too_large y unsupported_media_type. 405 enumera los métodos permitidos. |
1.1.0 | 2026-09-17 | Las fichas de aeródromo incluyen taxiways. Aditivo: no cambió ninguna ruta ni ningún campo existente. |
1.0.0 | 2026-09-17 | Primera versión: la clave personal y rutas de sólo lectura para aeródromos, aeronaves, meteorología, notas, planes de vuelo, el libro de vuelo y sus totales, y el perfil del piloto. |