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 propietario (owner) están marcadas con (owner); todo lo demás solo necesita la membresía del proyecto (o, para las lecturas marcadas con (viewer), cualquier nivel de acceso).
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.
Autenticación
Sección titulada «Autenticación»Cada solicitud autenticada envía una clave de API mediante una de:
X-TrackerToken: <key>Authorization: Bearer <key>
Las claves de usuario empiezan por ea_user_. Las claves de agente empiezan por ea_agent_. Consulta Guía de la API → Dos tipos de claves.
Endpoints sin autenticación: /openapi.json, /docs, los endpoints /auth/* y las búsquedas de datos de referencia (/story_types, /story_states, /effort_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).
Tres niveles condicionan los endpoints con alcance de proyecto:
| Nivel | Quién pasa | Operaciones típicas |
|---|---|---|
| viewer | viewer, member, owner | lecturas (listar/obtener historias, búsqueda, analíticas) |
| member | member, owner | todas las escrituras de elementos de trabajo (historias, tareas, comentarios, …) |
| owner | solo owner | configuración del proyecto, gestión de membresía, claves de agente, eliminación, importación, registro de auditoría |
Un no miembro recibe 404 unfound_resource (no 403) en las rutas de proyecto, 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. 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. |
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 |
|---|---|---|
| POST | /auth/register | Registrar una cuenta nueva |
| POST | /auth/login | Iniciar sesión, devuelve un token de sesión |
| POST | /auth/logout | Cerrar sesión |
| POST | /auth/forgot-password | Solicitar un correo de restablecimiento de contraseña |
| POST | /auth/reset-password | Usar un token de restablecimiento para establecer una contraseña nueva |
| GET | /auth/verify-email | Verificar una dirección de correo electrónico |
| POST | /auth/accept-invite/lookup | Resolver un token de invitación → correo electrónico (sin autenticación) |
| POST | /auth/accept-invite | Aceptar una invitación a un proyecto (tras autenticarse) |
| GET | /me | Perfil del usuario actual |
| PUT | /me | Actualizar el perfil |
| DELETE | /me | Eliminar la cuenta |
| 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/activity | Tu actividad en todos los proyectos |
| 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 |
| POST | /contact · POST /feedback · POST /feedback/with-screenshot | Contacto + feedback en la aplicación |
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 |
Proyectos
Sección titulada «Proyectos»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects | Listar tus proyectos |
| POST | /projects | Crear un proyecto |
| GET | /projects/{id} | Obtener los detalles del proyecto (viewer) |
| PUT | /projects/{id} | Actualizar la configuración del proyecto (owner) |
| DELETE | /projects/{id} | Eliminar un proyecto (owner) |
| GET | /projects/{id}/audit-log | Flujo de actividad del proyecto (owner) |
| GET | /projects/{id}/events | Flujo de eventos paginado por cursor (viewer) — consulta Eventos |
Miembros y claves de agente
Sección titulada «Miembros 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 (owner) |
| PUT | /projects/{id}/memberships/{mid} | Actualizar el rol (owner) |
| DELETE | /projects/{id}/memberships/{mid} | Eliminar a un miembro (owner) |
| GET / POST | /projects/{id}/agent_keys | Listar / generar claves de agente (owner) |
| DELETE | /projects/{id}/agent_keys/{kid} | Revocar una clave de agente (owner) |
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/bulk_transition | Transicionar muchas historias (1–100) a la vez |
| POST | /projects/{id}/stories/bulk-delete | Eliminar muchas historias |
| POST | /projects/{id}/stories/bulk-duplicate | Duplicar muchas historias |
| POST | /projects/{id}/stories/{sid}/duplicate | Duplicar una historia |
Crear (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. 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) y "force_state_change" (bool).
Transicionar (POST …/transitions): { "to": "<state>", "reason"? }. 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>", "reason"? }. 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 / POST | /projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid} | { blocker_desc, resolved? } |
| GET / POST | /projects/{id}/stories/{sid}/links · DELETE …/links/{lid} | { url, link_type?, title? } |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | { reviewer_id? / reviewer_agent_id?, 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 (≤ 2 GB cada uno); el listado es (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»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/iterations | Listar iteraciones (member) |
| POST | /projects/{id}/iterations | Crear una iteración manual (owner) |
| DELETE | /projects/{id}/iterations/{itid} | Eliminar una iteración (owner) |
Búsqueda, analíticas, métricas, preferencias
Sección titulada «Búsqueda, analíticas, métricas, preferencias»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/search?query=… | Búsqueda con sintaxis de filtros (viewer) — consulta la Guía |
| GET | /projects/{id}/analytics/{overview,iteration,releases,activity,cycle-time,projections} | Analíticas (viewer). El desglose por iteración toma ?iteration_id= |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types} | Métricas (viewer) |
| GET / PUT | /projects/{id}/preferences | Tus preferencias de tablero para este proyecto (member) |
Eventos
Sección titulada «Eventos»| Método | Ruta | Descripción |
|---|---|---|
| GET | /projects/{id}/events | Flujo de eventos paginado por cursor (viewer) |
Parámetros de consulta: since=<event_id>, types=story.created,story.transitioned,comment.created,…, limit=, cursor=. La respuesta incluye next_cursor. Pasa el último event_id que viste como since para reanudar.
Importación (owner)
Sección titulada «Importación (owner)»| Método | Ruta | Descripción |
|---|---|---|
| POST | /projects/{id}/import (+ /json) | Subida multipart. source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json. |
WebSocket
Sección titulada «WebSocket»wss://eastagiletracker.com/ws/control?token=<key>Para control remoto interactivo de la interfaz ({ "action": "get_state", "id": "req-1" }). 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. No se aplica a GET/HEAD/OPTIONS, /auth/* ni a las rutas /attachments. Las respuestas 5xx nunca se cachean — un reintento llega al manejador.
Paginación
Sección titulada «Paginación»Los endpoints de listado aceptan cursor=<opaque> y limit=<n≤200>. Cuando se establece, la respuesta es { "items": [...], "next_cursor": "<str|null>" }; pasa next_cursor de vuelta para paginar. Algunas listas también devuelven una cabecera X-Tracker-Pagination-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 |
| 422 | invalid_transition | movimiento de estado ilegal; details lleva { from, to, allowed } |
| 500 | internal_error | fallo del servidor — mensaje genérico; seguro reintentar |
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 clave (por IP para los endpoints sin autenticación), cubo de tokens GCRA:
- Auth —
/auth/*: 0.5 req/s, ráfaga 20. - Public —
/contact,/feedback: 0.2 req/s, ráfaga 10. - Sensitive — restablecimiento de contraseña: ~0.002 req/s, ráfaga 5.
Un límite superado devuelve 429 Too Many Requests con una cabecera Retry-After y un cuerpo en texto plano (no el sobre de error JSON).