La referencia completa de endpoints REST. Para tutoriales y ejemplos, consulta la Guía de la API.
Todo lo que un miembro de un proyecto puede hacer en la interfaz web está disponible aquí — la SPA consume esta misma API. Las operaciones que requieren el rol de manager están marcadas con (manager); todo lo demás solo necesita la membresía del proyecto (o, para las lecturas marcadas con (viewer), cualquier nivel de acceso). Las tablas de abajo nombran todos los grupos de rutas que monta el servidor; los que se resumen en una sola línea están descritos por completo en el openapi.json en vivo.
https://eastagiletracker.com/api/v1https://api.eastagiletracker.com/api/v1 sirve la API idéntica. Todas las solicitudes y respuestas son JSON, salvo unos pocos endpoints de subida de archivos que aceptan multipart.
Dos grupos quedan un nivel más arriba, bajo /api en lugar de /api/v1: la superficie de autenticación (/api/auth/*) y los formularios públicos (/api/contact, /api/feedback). Sus grafías /api/v1/… devuelven 404.
Autenticación
Sección titulada «Autenticación»Cada solicitud autenticada envía una credencial mediante una de:
X-TrackerToken: <key>Authorization: Bearer <key>
Las claves de usuario empiezan por ea_user_, las de agente por ea_agent_ y los tokens de acceso MCP por ea_mcp_. Consulta Guía de la API → Tres tipos de credenciales.
Endpoints sin autenticación: /openapi.json, /docs, los endpoints /api/auth/* y las búsquedas de datos de referencia (/story_types, /story_states, /effort_scales, /priority_scales). /meta está autenticado — cualquier clave válida funciona, pero no tiene alcance de proyecto (una clave de agente atada a un proyecto también lo alcanza).
Cuatro niveles condicionan los endpoints con alcance de proyecto:
| Nivel | Quién pasa | Operaciones típicas |
|---|---|---|
| public viewer | cualquiera, en un proyecto cuya visibilidad sea pública | lecturas del tablero: historias, iteraciones, búsqueda, actividad de historias y epics (con los detalles del actor censurados) |
| viewer | viewer, member, manager | lecturas (listar/obtener historias, búsqueda, métricas, lista de formatos de exportación) |
| member | member, manager | todas las escrituras de elementos de trabajo (historias, tareas, comentarios, …), el flujo de eventos |
| manager | solo manager | configuración del proyecto, gestión de membresía, claves de agente, eliminación, importación, descargas de exportación, copias de seguridad, registro de auditoría |
Los agentes tienen los mismos roles que los miembros — viewer, member o manager — con el tope del rol del miembro que emitió la clave. Un no miembro recibe 404 unfound_resource (no 403) en las rutas de proyectos privados, de modo que los IDs de proyecto no son enumerables.
Endpoints autodescriptivos
Sección titulada «Endpoints autodescriptivos»| Método | Ruta | Descripción |
|---|---|---|
| GET | /openapi.json | La especificación OpenAPI 3 en vivo, con los cuerpos de las solicitudes incluidos. Sin autenticación. |
| GET | /docs | Swagger UI. Sin autenticación. |
| GET | /meta | Identidad del que llama (auth.kind/key_id/agent_id/project_id) + el grafo de transiciones por tipo de historia. Autenticado (cualquier clave válida; sin alcance de proyecto). Llama a esto primero. |
| GET | /api/health · /api/config | Comprobación de vida, y la configuración pública del despliegue (modo de organización única, funciones opcionales activadas, nombre de la instancia). Sin autenticación, fuera de /v1. |
Auth (/api/auth/*, fuera de /v1)
Sección titulada «Auth (/api/auth/*, fuera de /v1)»Endpoints de sesión, sin autenticación salvo que se indique lo contrario. La SPA es quien los usa; los scripts normalmente usan una clave de API en su lugar.
| Método | Ruta | Descripción |
|---|---|---|
| POST | /auth/register | Registrar una cuenta nueva — protegido por reCAPTCHA; después la cuenta pasa el desafío por SMS |
| POST | /auth/sms/challenge · /auth/sms/status · /auth/sms/bypass | Enviar / comprobar el código SMS del registro (el bypass está restringido al operador) |
| GET | /auth/config | Qué métodos de inicio de sesión ofrece el despliegue |
| POST | /auth/login | Iniciar sesión con correo electrónico + contraseña; devuelve un JWT de sesión o un desafío TOTP |
| POST | /auth/login/totp | Completar un inicio de sesión con un código del autenticador o un código de recuperación |
| POST | /auth/passkey/login/start · /auth/passkey/login/finish | Inicio de sesión WebAuthn sin contraseña |
| GET | /auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchange | Inicio de sesión OAuth con GitHub o Google |
| POST | /auth/refresh · /auth/refresh/revoke | Rotar el refresh token / revocarlo |
| POST | /auth/logout | Cerrar sesión (revoca el refresh token) |
| POST | /auth/forgot-password · /auth/reset-password | Solicitar un correo de restablecimiento / usar el token de restablecimiento |
| POST | /auth/accept-invite/lookup · /auth/accept-invite | Resolver un token de invitación → correo electrónico / aceptar la invitación al proyecto (tras autenticarse) |
Cuenta / identidad
Sección titulada «Cuenta / identidad»Estos actúan sobre el que llama y solo necesitan una clave válida (sin rol de proyecto).
| Método | Ruta | Descripción |
|---|---|---|
| GET | /me | Perfil del usuario actual |
| PUT | /me | Actualizar el perfil |
| DELETE | /me | Eliminar la cuenta — se rechaza mientras seas el único owner de una organización o de un proyecto con otros miembros |
| GET | /me/deletion-impact | Qué eliminaría borrar la cuenta y qué lo impide |
| PUT | /me/password | Cambiar la contraseña |
| PUT | /me/settings | Actualizar la configuración (tema, preferencias de notificación) |
| POST | /me/avatar | Subir avatar (multipart) |
| POST | /me/api-token/regenerate | Rotar tu token de API — invalida las sesiones/claves existentes |
| GET | /me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id} | Gestionar las claves de API de usuario (ea_user_) |
| GET | /me/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disable | Alta del doble factor (TOTP); verify devuelve los códigos de recuperación una sola vez |
| GET | /me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id} | Alta y eliminación de passkeys |
| GET | /me/oauth_grants · DELETE /me/oauth_grants/{grant_id} | Aplicaciones conectadas — los clientes MCP y las aplicaciones OAuth que has autorizado |
| GET | /me/activity | Tu actividad en todos los proyectos |
| GET | /me/stories | Historias de las que eres owner, que solicitaste o que sigues, en todos los proyectos a los que llega el token — role=owned|requested|following, state=, cursor= / limit= (máx. 200) |
| GET | /me/mentions · POST /me/mentions/{mention_id}/ack | La bandeja de @-menciones (unacked=true para filtrar) y su confirmación de lectura — también incorporada al feed de notificaciones de más abajo |
| GET | /me/data-export | Autoexportación RGPD de tus datos |
| GET | /me/consent · POST /me/consent | Leer / registrar el consentimiento ({ consent_type, granted }) |
| GET | /legal/pending · POST /legal/accept | Documentos de clickwrap pendientes / registrar la aceptación |
| GET / PUT | /agent/me | La identidad y el perfil propios de una clave de agente, que el agente puede leer y editar (la contraparte de /me del lado del agente) |
| POST | /api/contact · /api/feedback · /api/feedback/with-screenshot | Contacto + feedback en la aplicación. Fuera de /v1; con límite de tasa por IP |
Datos de referencia (sin autenticación)
Sección titulada «Datos de referencia (sin autenticación)»Búsquedas de datos semilla usadas al crear/estimar historias. IDs estables.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /story_types | feature, bug, chore, release (+ allow_points) |
| GET | /story_states | unstarted … accepted, rejected |
| GET | /effort_scales | escalas de estimación disponibles |
| GET | /effort_scales/{scale_id}/values | los valores de puntos de una escala |
| GET | /priority_scales · /priority_scales/{scale_id}/values | las escalas de prioridad y sus valores (el priority_id de una historia se resuelve aquí) |
Organizaciones
Sección titulada «Organizaciones»Solo en el servicio alojado — una instalación autoalojada funciona en modo de organización única y no los monta (salvo la lista de organizaciones). Los roles son roles de organización: owner, admin, member.
| Método | Ruta | Descripción |
|---|---|---|
| GET / POST | /organizations | Listar tus organizaciones / crear una |
| GET / PUT / DELETE | /organizations/{oid} | Leer, renombrar (nombre + slug; owner o admin), eliminar |
| GET / POST | /organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id} | Miembros e invitaciones; las invitaciones llevan un tope de rol (nunca por encima del de quien invita; el owner nunca se invita) |
| POST | /organizations/{oid}/memberships/bulk-role · …/memberships/bulk-remove | Cambia el rol de hasta 200 miembros a la vez o elimínalos. Todo o nada: un lote que eliminaría al último owner o dejaría un proyecto sin propietario se rechaza entero; con reassign_confirmed pasas a ser propietario de esos proyectos |
| DELETE | /organizations/{oid}/invitations/{invitation_id} | Revocar una invitación pendiente |
| POST | /organizations/{oid}/transfer-ownership | Ceder el rol de owner a otro miembro |
| PUT | /organizations/{oid}/memberships/{member_id}/anonymization | Enmascarar el nombre / correo / avatar de un miembro en toda la organización |
| GET | /organization-invitations/{token} · POST …/{token}/accept | Resolver / aceptar una invitación de organización recibida por correo |
| POST | /organizations/{oid}/export · GET / POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/download | Exportación de la organización, solo para el owner: un zip con un volcado SQL y todos los adjuntos, ejecutada como un job |
Proyectos
Sección titulada «Proyectos»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects | Listar tus proyectos (limit ≤ 200) |
| POST | /projects | Crear un proyecto |
| GET | /projects/{id} | Obtener los detalles del proyecto (viewer) |
| PUT | /projects/{id} | Actualizar la configuración del proyecto (manager) |
| DELETE | /projects/{id} | Eliminar un proyecto (manager) |
| POST | /projects/{id}/pin | Fijar / desfijar el proyecto en tu lista de proyectos |
| POST | /projects/{id}/transfer-organization | Mover el proyecto a otra organización (manager) |
| POST | /projects/{id}/slack/test | Enviar un mensaje de prueba al feed de Slack del proyecto (manager) |
| GET / POST | /projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seed | Proyectos públicos de muestra: comprobar si puedes reclamar uno, reclamarlo, sembrarlo |
| GET | /projects/{id}/audit-log | Lectura del audit log — historial del proyecto más actividad por historia / por epic vía surface=; el acceso varía según el surface, ver abajo |
| GET | /projects/{id}/events | Flujo de eventos paginado por cursor (member) — consulta Eventos |
Parámetros de consulta del audit log: event_type= (un tipo o lista separada por comas), limit= (≤ 1000), before= (cursor keyset, created_at ISO-8601), surface= (project_history, story_activities, epic_activities), target_id= (el id de la historia/epic — requerido cuando surface=story_activities o epic_activities). Acceso: el log sin filtrar y surface=project_history son (manager); story_activities / epic_activities puede leerlos cualquier miembro del proyecto, y de forma anónima en proyectos públicos con la PII del actor censurada.
Miembros, agentes y claves de agente
Sección titulada «Miembros, agentes y claves de agente»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/memberships | Listar miembros (viewer) |
| POST | /projects/{id}/memberships | Invitar a un miembro por correo electrónico (manager) |
| PUT | /projects/{id}/memberships/{mid} | Actualizar el rol (manager) |
| DELETE | /projects/{id}/memberships/{mid} | Eliminar a un miembro (manager) |
| GET | /projects/{id}/addable-members · POST /projects/{id}/members/add-existing | Miembros de la organización que aún no están en el proyecto / añadir uno sin invitación por correo (manager) |
| POST | /projects/{id}/members/join | Un owner o admin de la organización se une a un proyecto de su organización como manager, o se asciende a sí mismo a manager (la acción Make me owner de la lista de proyectos) |
| PUT | /projects/{id}/members/{mid}/anonymization | Enmascarar el nombre / correo / avatar de un miembro en este proyecto (manager) |
| GET / POST | /projects/{id}/agent_keys | Listar / emitir claves de agente — los managers, o los roles que admita la política de roles creadores del proyecto |
| DELETE | /projects/{id}/agent_keys/{kid} | Revocar una clave de agente |
| GET | /projects/{id}/agent_keys/onboarding | El paquete de incorporación: prompts y archivos de configuración para los clientes de agentes más comunes |
| GET | /projects/{id}/agents · GET / PUT /projects/{id}/agents/{aid} | Los agentes del proyecto y sus perfiles (nombre, iniciales, descripción, color) |
| POST | /projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatar | Rotar la clave de un agente (se conservan su identidad y su historial) / subir su avatar |
Historias
Sección titulada «Historias»Todas las escrituras de historias necesitan el rol member.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/stories | Listar historias (paginadas, filtrables) (viewer) |
| POST | /projects/{id}/stories | Crear una historia |
| GET | /projects/{id}/stories/{sid} | Obtener una historia (viewer) |
| PUT | /projects/{id}/stories/{sid} | Actualizar una historia |
| DELETE | /projects/{id}/stories/{sid} | Eliminar una historia |
| POST | /projects/{id}/stories/{sid}/transitions | Cambiar de estado con validación |
| POST | /projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restart | Rechazar una historia entregada / devolver una rechazada a started (rejected es terminal para /transitions) |
| POST | /projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchive | Archivar / desarchivar una historia |
| POST | /projects/{id}/stories/bulk_transition | Transicionar muchas historias (1–100) a la vez |
| POST | /projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-move | Archivar, eliminar, duplicar o mover (a un panel / una posición) muchas historias |
| POST | /projects/{id}/stories/{sid}/duplicate | Duplicar una historia |
| GET / POST / DELETE | /projects/{id}/stories/{sid}/epics · …/epics/{eid} | La pertenencia de la historia a epics |
| GET | /short-links/{code} · /story-references | Resolver un enlace corto /s/<code> a su historia / resolver hasta 100 referencias a historias (#id, URLs) a las historias que el que llama puede leer |
Parámetros de query para listas de historias: archived= (exclude por defecto / include / only — el filtro de archivado de tres estados; sustituye al obsoleto include_archived=true, que ahora es un alias de archived=include), include_done=true (admite historias del panel Done congeladas en iteraciones pasadas, excluidas por defecto). La paginación (cursor= / limit= / offset=) y los conjuntos reducidos de campos (fields=) siguen Paginación y Proyección de campos.
Crear (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. estimate es la etiqueta del valor de la escala, como cadena ("3", "13"); un número JSON se rechaza. labels acepta ["auth"] o [{ "name": "auth" }]; las etiquetas desconocidas se crean. Predeterminados: story_type=feature, current_state=unstarted.
Actualizar (PUT …/stories/{sid}): los mismos campos, todos opcionales, más "position" (float), "force_state_change" (bool) y "expected_updated_at" (RFC 3339 — el guardado de una descripción se rechaza con 409 stale_write si la historia cambió desde que la leíste). Las escrituras de historias también respetan If-Match frente al ETag de la historia; una discrepancia es 412 precondition_failed.
Transicionar (POST …/transitions): { "to": "<state>" }. El campo es to. Devuelve { story_id, state }. Movimiento ilegal → 422 invalid_transition con details: { from, to, allowed }.
Transición en bloque (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>" }. Cada historia se juzga de forma independiente; devuelve { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.
Subrecursos de la historia
Sección titulada «Subrecursos de la historia»Todos member. List/GET en la mayoría es (viewer).
| Método | Ruta | Cuerpo / notas |
|---|---|---|
| GET / POST | /projects/{id}/stories/{sid}/tasks · PUT/DELETE …/tasks/{tid} | { description (or task_desc), complete?, task_order? } |
| GET / POST | /projects/{id}/stories/{sid}/comments · PUT/DELETE …/comments/{cid} | { text (or comment_text) } o { comment_emoji }. GET acepta fields= (lista permitida: comment_id, story_comment_id, story_id, comment_text, comment_emoji, member, created) además de cursor= / limit= (≤ 200) / order=asc|desc |
| GET / POST | /projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid} | { blocker_desc, resolved? } |
| GET / POST | /projects/{id}/stories/{sid}/links · PUT/DELETE …/links/{lid} | { url, link_type?, title? } — link_type ∈ relates_to, duplicates, blocks, is_blocked_by, pull_request, branch, other; las URLs /pull/ y /tree/ de GitHub se tipifican automáticamente |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | Crear: { reviewer_id? / reviewer_agent_id?, comment? } — omite ambos para asignarte a ti mismo. Actualizar: { status, comment? } |
| GET / POST | /projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid} | { member_id? / agent_id? } — omite ambos para añadir al que llama |
| GET / POST | /projects/{id}/stories/{sid}/followers · DELETE …/followers/{mid} · DELETE …/followers/agents/{aid} | { member_id? / agent_id? } |
| GET / POST | /projects/{id}/stories/{sid}/labels · DELETE …/labels/{lid} | { name } |
| GET / POST | /projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid} | subida multipart — vídeo ≤ 200 MB, PDF / Word / Excel ≤ 25 MB, imágenes / CSV / texto ≤ 10 MB; el listado es (viewer) |
| GET / POST | /projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid} | Adjuntos de enlace — una URL externa que se guarda junto a los adjuntos de archivo, en lugar de como enlace de código |
| GET | /attachments/{token} · /api/avatars/{token} | Lecturas direccionadas por token de un adjunto o de un avatar — las URLs que entrega la API; no se necesita X-TrackerToken |
La misma forma que las historias, sin la máquina de estados. member para escrituras, (viewer) para lecturas.
| Método | Ruta | Descripción |
|---|---|---|
| GET / POST | /projects/{id}/epics · GET / PUT / DELETE …/epics/{eid} | Los epics tienen un nombre, una descripción en Markdown y una etiqueta de respaldo que agrupa sus historias |
| GET / POST / PUT / DELETE | …/epics/{eid}/comments · …/comments/{cid} | Comentarios de epics |
| GET / POST / DELETE | …/epics/{eid}/owners · …/followers (+ variantes /agents/{aid}) | Owners y followers, miembros o agentes — los owners de un epic se propagan a sus historias |
| GET / POST / DELETE | …/epics/{eid}/attachments (+ /json) · …/link-attachments | Adjuntos, con los mismos límites que las historias |
| GET | /projects/{id}/analytics/epics · …/analytics/epics/{eid} | Progreso por epic: burnup, rendimiento, salud, pronóstico (viewer) |
Etiquetas
Sección titulada «Etiquetas»member para escrituras, (viewer) para lecturas.
| Método | Ruta | Descripción |
|---|---|---|
| GET / POST | /projects/{id}/labels | Listar / crear una etiqueta |
| PUT / DELETE | /projects/{id}/labels/{lid} | Actualizar / eliminar una etiqueta |
| POST | /projects/{id}/labels/{lid}/archive | Archivar (ocultar de forma suave) una etiqueta |
Iteraciones
Sección titulada «Iteraciones»Las lecturas están abiertas a cualquier rol del proyecto, y son anónimas en un proyecto público.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/iterations | Listar iteraciones (≤ 500 por página; lleva un ETag y las cabeceras de continuación X-Tracker-Pagination-* cuando se trunca) |
| GET | /projects/{id}/iterations/{itid} | Una iteración |
| GET | /projects/{id}/iterations/first-preview | Las fechas que recibiría la primera iteración, mostradas en la confirmación de siembra |
| POST | /projects/{id}/iterations | Crear una iteración manual (member) |
| DELETE | /projects/{id}/iterations/{itid} | Eliminar una iteración (manager) |
| PUT | /projects/{id}/iterations/{itid}/velocity | Anular la velocidad de una iteración sin cambiar la estrategia del proyecto (manager) |
| GET | /projects/{id}/iterations/{itid}/done-stories | Las historias aceptadas de una iteración cerrada, paginadas |
Búsqueda, métricas, preferencias
Sección titulada «Búsqueda, métricas, preferencias»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/search?q=… | Búsqueda potente — texto completo + calificadores de facetas / rangos de fechas / personas (DSL al estilo de GitHub); devuelve { results, total, limit, offset }. query es un alias de q; limit= (50 por defecto, máx. 1000) / offset= paginan; sort= ordena por relevance (por defecto), created, created_asc, state o updated. (viewer) — consulta la Guía |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types,contributors} | Las series de la página Metrics (viewer); las métricas de epics están bajo /analytics/epics, más arriba |
| GET | /projects/{id}/backlog/grouping | Los grupos de iteraciones proyectados del Backlog (viewer) |
| GET / PUT | /projects/{id}/preferences | Tus preferencias de tablero para este proyecto — cualquier rol del proyecto, solo tu propia fila |
Eventos
Sección titulada «Eventos»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/events | Flujo de eventos paginado por cursor (member) — los viewers reciben 403 |
Parámetros de consulta: since=<event_id>, types=story.created,story.transitioned,comment.added,…, limit= (≤ 500), cursor=. La respuesta incluye next_cursor. Pasa el último event_id que viste como since para reanudar.
Notificaciones
Sección titulada «Notificaciones»El feed unificado de notificaciones in-app: filas de notificación de primera clase (solicitudes de revisión, actividad de stories, invitaciones, …) fusionadas con la bandeja de @-menciones en un único flujo, de más reciente a más antiguo. Los ids del feed llevan prefijo de origen (nt-… / sc-… / ec-…). Las sesiones de miembro y las claves ea_user_* leen sus filas de miembro; las claves ea_agent_* sus filas de agente.
| Método | Ruta | Descripción |
|---|---|---|
| GET | /me/notifications | Tu feed de notificaciones. Filtros: unread=true, since_id=, kind= (mentions / reviews / stories / invitations); pagina con cursor= / limit= |
| GET | /me/notifications/unread-count | Totales sin leer — { unread_count, by_category: { mentions, reviews, stories, invitations } } |
| POST | /me/notifications/read-all | Marcar todo como leído; devuelve los contadores actualizados |
| POST | /me/notifications/{id}/ack | Marcar un elemento como leído (idempotente) |
| POST | /me/notifications/{id}/accept | Aceptar una invitación a un proyecto / organización desde el feed (solo tokens de miembro) |
| POST | /me/notifications/{id}/decline | Rechazar una invitación a un proyecto / organización (solo tokens de miembro) |
| GET | /me/notifications/resolve-invite?token=… | Resolver un token de invitación enviado por correo al id de tu notificación — { "id": "nt-…" } o { "id": null } |
| GET | /me/notifications/stream | Push en vivo — Server-Sent Events (text/event-stream); ver abajo |
El endpoint de stream no es un endpoint JSON y por eso no está en la especificación OpenAPI: mantiene la conexión abierta y emite un frame sin payload ({"type":"notification","kind":…}) cada vez que llega algo nuevo, indicando al cliente que recargue el feed. Las conexiones se cortan en el servidor a los 45 minutos — reconecta y vuelve a autenticarte. Solo sesiones de miembro y claves ea_user_*; las claves ea_agent_* reciben 403.
Importación (manager)
Sección titulada «Importación (manager)»| Método | Ruta | Descripción |
|---|---|---|
| POST | /projects/{id}/import | Fuentes de archivo: source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json, eat. Multipart file=. Síncrona — responde con los recuentos del resultado. |
| POST | /projects/{id}/import/json | Cuerpo JSON; source=github no necesita archivo — owner, repo, token opcional, y las banderas opcionales include_pull_requests / include_milestones / include_releases / include_dependencies; las fuentes de archivo envían file_base64. Asíncrona: devuelve 202 { import_id, status }. El servidor descarga por la API GraphQL de GitHub, que rechaza a los llamantes anónimos, así que siempre llega un token a GitHub: el tuyo o el compartido del despliegue. Consulta la Guía. |
| GET | /projects/{id}/imports/{import_id} | Consultar un job: status avanza pending → fetching → writing → done | failed, con progress_current / progress_total durante la descarga y los recuentos del resultado en done |
Solo se ejecuta una importación por proyecto a la vez; un segundo POST mientras hay otra en curso es 409 import_already_running. dry_run: true (cuerpo JSON o dry_run=true multipart) hace una vista previa de cualquier fuente: analiza, resuelve, de-duplica, devuelve los mismos recuentos { imported, skipped, errors, unmatched } y luego revierte — no se escribe nada. Límites: cuerpo de 10 MiB y 5.000 historias por importación para las fuentes de archivo (superar cualquiera → 400, sin escribir nada). La fuente GitHub no tiene tope — confirma por bloques en lugar de en una sola transacción. La reimportación es idempotente por id de origen — las filas ya importadas se saltan, no se duplican.
Exportación
Sección titulada «Exportación»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/export/formats | Formatos registrados: { id, name, content_type, drops, includes_archived }. Cualquier rol del proyecto. |
| GET | /projects/{id}/export/{format} | Descargar uno (manager). Intercambio: eat (fidelidad completa), jira, pivotal, shortcut, trello, asana, gitlab, linear, plane, plane_json; documentos: pdf, docx. |
| GET | /projects/{id}/export/attachments | Todos los adjuntos como un único zip navegable (los archivos conservan sus nombres originales; manifiesto en JSON + CSV) (manager). |
Las exportaciones de documentos (pdf, docx) toman parámetros de query adicionales: page_size= (letter por defecto / a4 / legal / folio), from= / to= (límites de la ventana de historias — RFC 3339 o YYYY-MM-DD a secas; una historia está en rango cuando su created o completed_at cae dentro), include_icebox= / include_backlog= (ambos false por defecto, de modo que una exportación compartible muestra solo trabajo planificado / en curso). Los formatos CSV de intercambio los ignoran.
Copias de seguridad y restauraciones (manager)
Sección titulada «Copias de seguridad y restauraciones (manager)»| Método | Ruta | Descripción |
|---|---|---|
| GET / POST | /projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/health | Listar snapshots, tomar uno ahora, leer uno, y el resumen de salud de la retención |
| GET / POST | /projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id} | Restaurar un snapshot completo, o tablas seleccionadas de uno, y consultar el estado de la restauración |
Los POST están en el nivel de límite de tasa sensitive (abajo).
MCP y proveedor OAuth
Sección titulada «MCP y proveedor OAuth»East Agile Tracker es un proveedor OAuth 2.1 para clientes MCP. Un cliente lo descubre en /.well-known/oauth-authorization-server y /.well-known/oauth-protected-resource/mcp, te envía a /oauth/authorize (la página de consentimiento), canjea el código en /oauth/token y luego habla MCP en /mcp con el token ea_mcp_* resultante. Las autorizaciones se listan y se revocan en /me/oauth_grants. Los endpoints del proveedor tienen su propio nivel de límite de tasa.
WebSocket
Sección titulada «WebSocket»wss://eastagiletracker.com/ws/control?token=<session JWT>Para control remoto interactivo de la interfaz ({ "action": "get_state", "id": "req-1" }). El token es un JWT de sesión del navegador — una clave de API se rechaza con 401 antes del upgrade. No es un canal de datos — todas las lecturas/escrituras pasan por REST. Solo de instancia única; no se distribuye entre réplicas.
Idempotencia
Sección titulada «Idempotencia»Los endpoints de escritura (POST, PUT, DELETE) aceptan una cabecera Idempotency-Key. La misma clave + el mismo cuerpo reproduce la respuesta en caché (ventana de 24 horas); la misma clave + un cuerpo distinto devuelve 409 idempotency_conflict. La clave está acotada a la credencial que la envió. No se aplica a GET/HEAD/OPTIONS, a /openapi.json y /docs, a /api/auth/* ni a las subidas multipart en rutas /attachments. Las respuestas que no llegaron a dar una respuesta del dominio nunca se cachean — 401, 403, 404, 429 y todos los 5xx —, de modo que un reintento tras cualquiera de ellas llega al manejador; 400, 409, 412 y 422 son la respuesta del dominio y se reproducen igual que un éxito.
Paginación
Sección titulada «Paginación»Los endpoints de listado aceptan cursor=<opaque> y limit=<n>. Cuando se establecen, la respuesta es { "items": [...], "next_cursor": "<str|null>" }; pasa next_cursor de vuelta para paginar. El tope de limit depende del endpoint: 200 en historias, comentarios y proyectos; 500 en eventos; 1000 en búsqueda y en el audit log.
Una lista simple (sin cursor/limit) que tuvo que truncar su respuesta lo indica en cabeceras — X-Tracker-Pagination-Truncated, X-Tracker-Pagination-Limit, X-Tracker-Pagination-Offset y X-Tracker-Pagination-Next-Offset; pasa esta última de vuelta como offset= para la página siguiente. No hay cabecera de recuento total.
Proyección de campos
Sección titulada «Proyección de campos»Los endpoints de listado aceptan fields= (separados por comas) para devolver solo campos específicos. story_id siempre se incluye; un nombre de campo desconocido devuelve 400 validation_failed con los nombres infractores en details.fields.
GET /projects/123/stories?fields=story_id,name,current_state,ownersFormato de errores
Sección titulada «Formato de errores»Cada error JSON tiene code y error; algunos añaden details:
{ "code": "invalid_transition", "error": "Cannot move story from `unstarted` to `accepted`", "details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }| Estado | code | Cuándo |
|---|---|---|
| 400 | invalid_parameter | entrada incorrecta; mensaje en error, sin details (la mayoría de las validaciones: en blanco/longitud/byte nulo/email) |
| 400 | validation_failed | error de entrada estructurado; details.fields es un array de los nombres de los campos infractores |
| 401 | unauthenticated | token ausente/inválido |
| 403 | unauthorized_operation | autenticado pero con rol insuficiente |
| 404 | unfound_resource | no encontrado — también se devuelve a los no miembros |
| 409 | conflict | conflicto de recurso (p. ej., duplicado) |
| 409 | idempotency_conflict | Idempotency-Key reutilizado con un cuerpo distinto |
| 409 | stale_write · import_already_running | la historia cambió desde tu expected_updated_at · ya hay una importación en curso |
| 412 | precondition_failed | If-Match no coincidió con el ETag actual del recurso; details lleva expected y current |
| 413 | request_too_large | el cuerpo supera el límite de tamaño de la ruta |
| 422 | invalid_transition | movimiento de estado ilegal; details lleva { from, to, allowed } |
| 429 | rate_limited | demasiadas solicitudes desde esta IP en una ruta con límite de tasa; cabecera Retry-After |
| 500 | internal_error | fallo del servidor — mensaje genérico; seguro reintentar |
| 503 | not_configured | al despliegue le falta la integración que necesita esta ruta (SMS, almacenamiento de objetos, …) |
details.fields es un array JSON de nombres de campos (p. ej., ["to"]), a veces con claves adicionales como max. No hay un mapa campo→mensaje.
{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }Límites de tasa
Sección titulada «Límites de tasa»Por IP de cliente, en un puñado de rutas; el resto del tráfico autenticado de la API no tiene límite de tasa. Valores por defecto (cada par es la tasa sostenida y la ráfaga, ajustables por el operador):
- Auth —
/api/auth/*: 0.5 req/s, ráfaga 20. - OAuth provider —
/oauth/*: 1 req/s, ráfaga 60. - Public —
/api/contact: 0.2 req/s, ráfaga 10. - Feedback —
/api/feedback: tres niveles apilados — un envío cada 15 s, 10 por hora, 36 por día. - Avatars — la redirección de avatares sin autenticación: 20 req/s, ráfaga 200.
- Sensitive — los
POSTde copia de seguridad y restauración: ~0.002 req/s, ráfaga 5.
Un límite superado devuelve 429 con una cabecera Retry-After y el sobre de error JSON estándar, code: "rate_limited".