Copilot EFB · API pública

La API de Copilot EFB

Tu propio bolso de vuelo, leído desde un servicio tuyo: aeronaves, fichas de aeródromo, meteorología, notas, checklists, planes de vuelo, libro de vuelo y perfil del piloto. Y el único lugar donde el plugin RogerATC AI guarda las estadísticas de sus sesiones.

URL base
https://api.rogeratc.app
Autenticación
Clave personal de API
Formato
JSON sobre HTTPS
Versión
1.11.0
01

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.

02

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/weather

GET /v1/me es la forma más barata de comprobar que una clave funciona: indica a qué cuenta pertenece.

03

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.

MomentoQué ocurre
Cuenta confirmadaSe crea la clave. Una cuenta anterior a las claves la recibe en su próximo inicio de sesión.
Ajustes → Acceso a la APISe muestra la clave, con sus primeros caracteres (prefix) para distinguir claves sin revelarlas.
RotarUna 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 pausadaLa clave queda suspendida junto con la cuenta y responde 401. Al reactivar la cuenta, vuelve a funcionar.
Cuenta eliminadaLa 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.

04

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.

05

Solicitudes y respuestas

  • Métodos: GET, y PUT ú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 null o no está — nunca se inventa.
  • Las respuestas con datos llevan Cache-Control: no-store, private.
  • Toda respuesta lleva X-Request-Id, el mismo valor que meta.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.

06

Errores

{
  "error": { "code": "not_found", "message": "No aircraft with id \"x\" in this account." },
  "meta": { "requestId": "…", "generatedAt": "…" }
}
EstadocodeCuándo
400bad_requestUn parámetro o un campo está mal formado; el mensaje lo nombra.
401unauthorizedSin clave, clave mal formada o desconocida, clave rotada, cuenta pausada o eliminada.
404not_foundNo existe la ruta, o no existe el registro en esta cuenta.
405method_not_allowedUn método que la ruta no acepta. Allow enumera los que sí.
410goneUn PUT de una sesión del plugin que el piloto eliminó en el EFB. Deja de enviarla.
413payload_too_largeUn cuerpo de PUT de más de 512 KB.
415unsupported_media_typeUn cuerpo de PUT que no es application/json.
429rate_limitedPor encima del límite de la clave. Retry-After indica cuántos segundos esperar.
500internalFalla 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.

07

Paginación y seguimiento de cambios

Las colecciones aceptan:

ParámetroSignificado
limitDe 1 a 200, 50 por omisión. Una página puede traer menos cuando los registros son grandes: una nota puede llevar un dibujo.
cursorOpaco. Devuelve page.nextCursor para pedir la página siguiente; null significa que no hay más.
updatedSinceISO 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"
08

Límites de uso

  • Por clave: 120 solicitudes por minuto. Por encima, 429 rate_limited con Retry-After en 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; fetchedAt indica cuándo se obtuvo.
09

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étodoRutaClaveDevuelve
GET/v1/healthnoEstado del servicio
GET/v1/mesíLa cuenta y su clave
GET/v1/aerodromessí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/aircraftsí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/weathersíMETAR y TAF en cada aeródromo del piloto
GET/v1/weather/{ident}síMETAR y TAF en un aeródromo
GET/v1/notessíNotas (paginadas)
GET/v1/notes/{id}síUna nota
GET/v1/checklistssíChecklists (paginadas)
GET/v1/checklists/{id}síUna checklist
GET/v1/check-flightssíVuelos de checklists (paginados)
GET/v1/check-flights/{id}síUn vuelo
GET/v1/flight-planssíPlanes de vuelo (paginados)
GET/v1/flight-plans/{id}síUn plan de vuelo
GET/v1/planningssíPlanificaciones (paginadas)
GET/v1/plannings/{id}síUna planificación
GET/v1/logbooksíAsientos del libro de vuelo (paginados)
GET/v1/logbook/totalssíHoras sumadas, en minutos
GET/v1/logbook/{id}síUn asiento
GET/v1/pilotsíEl perfil del piloto
PUT/v1/plugin/sessions/{id}síGuarda una sesión de RogerATC AI — la única escritura
PUT/v1/plugin/livesíInforma el estado en vivo y recoge las instrucciones pendientes
GET/v1/plugin/sessionssíSesiones de RogerATC AI (paginadas)
GET/v1/plugin/sessions/{id}síUna sesión de RogerATC AI
GET/v1/plugin/statssí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ámetroSignificado
limit · cursor · updatedSincePaginació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ámetroSignificado
limit · cursor · updatedSincePaginació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": { … }
}
statusSignificado
okUn METAR, un TAF o ambos. Cada uno lleva su fecha; nada se descarta por viejo.
no_reportSe consultó a NOAA y no tiene nada para ese indicador.
no_icao_indicatorEl aeródromo se identifica con un código nacional; no hay estación a la cual consultar.
unavailableNo 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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/notes

Checklists

  • 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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
aircraftIdSó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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
aircraftIdSó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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/flight-plans

Planificaciones

  • 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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
curl -s -H "Authorization: Bearer $ROGER_API_KEY" https://api.rogeratc.app/v1/plannings

Libro 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ámetroSignificado
limit · cursor · updatedSincePaginación — ver Paginación y seguimiento de cambios.
fromSólo para los totales. Primera log.date que se cuenta, AAAA-MM-DD, inclusive. Opcional.
toSó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/pilot
10

Plugin 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ámetroSignificado
{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.
Solicitud
PUT /v1/plugin/sessions/5f0c2a4e-7d1b-4c6a-9d0e-2b8f1c3a6e77 HTTP/1.1
Host: api.rogeratc.app
Authorization: Bearer rat_live_…
Content-Type: application/json
Cuerpo
{
  "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

CampoObligatorioReglas
schemasí1.
startedAtsíISO 8601. No más de un día en el futuro.
endedAtnoISO 8601, o null mientras se vuela.
statusnoin_progress, completed o aborted. Si falta: completed cuando hay endedAt, y si no in_progress.
pluginVersion, protocolVersion, simulator, language, regionnoCadenas cortas, sin espacios sobrantes. En language y region se normaliza el uso de mayúsculas.
dataSourcenosim, both o efb: de dónde tomó el plugin los datos de aeródromo. Cualquier otro valor se guarda como null.
aircraftno{ registration, icaoType }, en mayúsculas.
departure, arrivalnoUn 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.
aerodromesVisitednoHasta 20 identificadores, sin repetidos.
statsnoLos 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.
eventsnoSó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.
eventsDroppednoLo 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 eventsDropped los cuenta.
  • Un registro por sesión, nunca uno por cada comunicación.

Respuestas

EstadoCuerpoSignificado
201{ id, status, receivedAt, eventsStored, eventsDropped }La primera vez que se guarda este id.
200el mismoSe reemplazó la copia guardada. createdAt se conserva desde la primera llegada.
400errorUn campo no cumple una de las reglas anteriores; el mensaje lo nombra.
410error goneEl piloto eliminó esta sesión en el EFB. Deja de enviarla: no se volverá a guardar.
413 · 415errorDemasiado grande, o no es JSON.
401 · 429errorLa 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-2b8f1c3a6e77
HTTP/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.
  • 401 significa que la clave se rotó o la cuenta se pausó: se deja de enviar y se avisa al piloto una sola vez.
  • 410 significa que el piloto eliminó esa sesión: se quita de la cola y no se vuelve a enviar.
  • 429 significa esperar lo que indica Retry-After antes 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.

Solicitud
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": [] }'
Respuesta
{
  "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ámetroSignificado
limit · cursor · updatedSincePaginació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": { … }
}
11

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ónFechaCambio
1.11.02026-10-03GET /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.02026-10-03PUT /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.02026-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.02026-09-22Los planes de vuelo llevan signatureDataUrl, la firma de ese plan. Los vuelos de checklists llevan autoClosed. Aditivo.
1.7.02026-09-19Las 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.02026-09-18Vuelos de checklists: GET /v1/check-flights y GET /v1/check-flights/{id}. Aditivo.
1.5.02026-09-18Las fichas de aeródromo llevan aids (radioayudas y ayudas visuales) y fuel.products (aceites y aditivos). Aditivo.
1.4.02026-09-18Las fichas de aeródromo llevan attachments, y GET /v1/aerodromes/{id}/attachments/{attachmentId} da un enlace de descarga temporal. Aditivo.
1.3.12026-09-17Revisió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.02026-09-17Las fichas de aeródromo llevan fuel. Aditivo.
1.2.02026-09-17Checklists: 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.02026-09-17Las fichas de aeródromo incluyen taxiways. Aditivo: no cambió ninguna ruta ni ningún campo existente.
1.0.02026-09-17Primera 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.