Pular para o conteúdo

Especificação da API

Referência completa dos endpoints REST da API do East Agile Tracker: autenticação e papéis, projetos, histórias, épicos, iterações, eventos, importação e exportação.

A referência completa de endpoints REST. Para tutoriais e exemplos, veja o Guia da API.

Tudo o que um member do projeto pode fazer na interface web está disponível aqui — o SPA consome esta mesma API. As operações que exigem o papel de manager são marcadas com (manager); todo o resto precisa apenas de associação ao projeto (ou, para leituras marcadas com (viewer), qualquer nível de acesso). As tabelas abaixo nomeiam cada grupo de rotas que o servidor monta; os resumidos em uma única linha estão descritos por completo no openapi.json ao vivo.

https://api.eastagiletracker.com/api/v1

A API tem seu próprio host: eastagiletracker.com serve o app web e responde a /api/v1/… com 404. Todas as requisições e respostas são JSON, exceto alguns endpoints de upload de arquivo que aceitam multipart.

Dois grupos ficam um nível acima, em /api em vez de /api/v1: a superfície de autenticação (/api/auth/*) e o formulário público de contato (/api/contact). As variantes /api/v1/… deles retornam 404.

Toda requisição autenticada envia uma credencial por uma das opções:

  • X-TrackerToken: <key>
  • Authorization: Bearer <key>

As chaves de usuário começam com ea_user_, as chaves de agente com ea_agent_ e os tokens de acesso MCP com ea_mcp_. Veja Guia da API → Três tipos de credenciais.

Endpoints não autenticados: /openapi.json, /docs, os endpoints /api/auth/* e as consultas de dados de referência (/story_types, /story_states, /effort_scales, /priority_scales). /meta é autenticado — qualquer chave válida funciona, mas não tem escopo de projeto (uma chave de agente vinculada a um projeto também o alcança).

Quatro níveis controlam os endpoints com escopo de projeto:

NívelQuem passaOperações típicas
public viewerqualquer pessoa, em um projeto com visibilidade públicaleituras do quadro: histórias, iterações, busca, atividade de histórias e épicos (com os detalhes do ator censurados)
viewerviewer, member, managerleituras (listar/obter histórias, buscar, métricas, lista de formatos de exportação)
membermember, managertodas as escritas de item de trabalho (histórias, tarefas, comentários, …), o fluxo de eventos
managerapenas managerconfigurações do projeto, gerenciamento de associação, chaves de agente, exclusão, importação, downloads de exportação, backups, audit log

Os agentes têm os mesmos papéis que os membros — viewer, member ou manager — limitados ao papel do membro que emitiu a chave. Um não-membro recebe 404 unfound_resource (não 403) em caminhos de projetos privados, então os IDs de projeto não são enumeráveis.

MétodoCaminhoDescrição
GET/openapi.jsonA especificação OpenAPI 3 ao vivo, com os corpos de requisição. Não autenticado.
GET/docsSwagger UI. Não autenticado.
GET/metaIdentidade do chamador (auth.kind/key_id/agent_id/project_id) + o grafo de transições por tipo de história. Autenticado (qualquer chave válida; sem escopo de projeto). Chame isto primeiro.
GET/api/health · /api/configVerificação de disponibilidade e a configuração pública do deployment (modo de organização única, recursos opcionais ativados, nome da instância). Não autenticados, fora de /v1.

Endpoints de sessão, não autenticados salvo indicação em contrário. O SPA os aciona; scripts normalmente usam uma chave de API.

MétodoCaminhoDescrição
POST/auth/registerRegistra uma nova conta — protegido por reCAPTCHA; a conta depois passa pela verificação por SMS
POST/auth/sms/challenge · /auth/sms/status · /auth/sms/bypassEnvia / verifica o código SMS do cadastro (o bypass é restrito ao operador)
GET/auth/configQuais métodos de login o deployment oferece
POST/auth/loginLogin com e-mail + senha; retorna um JWT de sessão ou um desafio TOTP
POST/auth/login/totpConclui um login com um código do app autenticador ou um código de recuperação
POST/auth/passkey/login/start · /auth/passkey/login/finishLogin WebAuthn sem senha
GET/auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchangeLogin OAuth com GitHub ou Google
POST/auth/refresh · /auth/refresh/revokeRotaciona o refresh token / revoga-o
POST/auth/logoutFaz logout (autenticado; revoga o refresh token desta sessão)
POST/auth/forgot-password · /auth/reset-passwordSolicita um e-mail de redefinição / usa o token de redefinição
POST/auth/accept-invite/lookup · /auth/accept-inviteResolve um token de convite → e-mail / aceita o convite de projeto (após autenticar)
POST/auth/oauth/link/preview · …/link/confirm · /auth/oauth/merge/preview · …/merge/confirmConecta uma conta GitHub ou Google a uma conta existente, ou mescla duas contas
POST/auth/email_addresses/primary/preview · …/primary/confirmConclui uma mudança de e-mail principal a partir do link de confirmação enviado por e-mail

Estes atuam sobre o chamador e não precisam de papel de projeto. Precisam de uma identidade de membro — uma chave de agente recebe 401 (agentes usam /agent/me). Chamadas que alteram credenciais — senha, TOTP, passkeys, exclusão da conta, uma mudança de e-mail, regeneração de token — precisam de uma sessão de navegador; uma chave de API recebe 403.

MétodoCaminhoDescrição
GET/mePerfil do usuário atual
PUT/meAtualiza o perfil
DELETE/meExclui a conta — recusado enquanto você for o único owner de uma organização ou de um projeto com outros membros
GET/me/deletion-impactO que a exclusão da conta removeria e o que a impede
PUT/me/passwordAltera a senha
PUT/me/settingsAtualiza as configurações (tema, preferências de notificação)
POST / DELETE/me/avatarFaz upload (multipart) / remove o seu avatar
POST/me/api-token/regenerateEncerra todas as sessões e retorna um novo token de sessão; as chaves de API não são afetadas
GET / POST/me/email_addresses · GET …/email_addresses/offers · PUT …/email_addresses/primarySeus endereços de e-mail; adota o endereço de um provedor conectado como alternativo; solicita uma mudança do principal (confirmada por e-mail)
GET/me/oauth_identities · DELETE …/oauth_identities/{provider} · POST …/oauth_identities/{provider}/linkContas de login conectadas (GitHub, Google): lista, desconecta, inicia uma vinculação
GET/me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id}Gerencia chaves de API de usuário (ea_user_)
GET/me/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disableAtivação da autenticação em dois fatores (TOTP); verify retorna os códigos de recuperação uma única vez
GET/me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id}Cadastro e remoção de passkeys
GET/me/oauth_grants · DELETE /me/oauth_grants/{grant_id}Apps conectados — os clientes MCP e apps OAuth que você autorizou
GET/me/activitySua atividade em todos os projetos
GET/me/storiesHistórias das quais você é owner, que solicitou ou que segue, em todos os projetos que o token alcança — role=owned|requested|following, state=, cursor= / limit= (máx. 200)
GET/me/mentions · POST /me/mentions/{mention_id}/ackA caixa de @-menções (unacked=true para filtrar) e a confirmação de leitura — também incorporada ao feed de notificações abaixo
GET/me/data-exportAutoexportação GDPR dos seus dados
GET/me/consent · POST /me/consentLê / registra consentimento ({ consent_type, granted })
GET/legal/pending · POST /legal/acceptDocumentos clickwrap pendentes / registra aceitação
GET / PUT/agent/meA identidade e o perfil de uma chave de agente, legíveis e editáveis pelo próprio agente (a contraparte de /me do lado do agente)
POST/api/contact · /api/v1/feedback · /api/v1/feedback/with-screenshotContato + feedback no aplicativo; com limite de taxa por IP

Consultas de seed usadas ao criar/estimar histórias. IDs estáveis.

MétodoCaminhoDescrição
GET/story_typesfeature, bug, chore, release (+ allow_points)
GET/story_statesunstarted … accepted, rejected
GET/effort_scalesescalas de estimativa disponíveis
GET/effort_scales/{scale_id}/valuesos valores de pontos em uma escala
GET/priority_scales · /priority_scales/{scale_id}/valuesas escalas de prioridade e seus valores (o priority_id de uma história é resolvido aqui)

Somente no serviço hospedado — uma instalação self-hosted roda em modo de organização única e não monta estes endpoints (exceto a lista de organizações). Os papéis são papéis de organização: owner, admin, member.

MétodoCaminhoDescrição
GET / POST/organizationsLista suas organizações / cria uma
GET / PUT / DELETE/organizations/{oid}Lê, renomeia (nome + slug; owner ou admin), exclui
GET / POST/organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id}Membros e convites; os convites têm um teto de papel (nunca acima do papel do chamador; o owner nunca é convidado)
POST/organizations/{oid}/memberships/bulk-role · …/memberships/bulk-removeAltere o papel de até 200 membros de uma vez ou remova-os. Tudo ou nada: um lote que removeria o último owner ou deixaria um projeto sem proprietário é recusado por inteiro; com reassign_confirmed você passa a ser proprietário desses projetos
DELETE/organizations/{oid}/invitations/{invitation_id}Revoga um convite pendente
POST/organizations/{oid}/transfer-ownershipPassa o papel de owner para outro membro
GET/organization-invitations/{token} · POST …/{token}/acceptResolve / aceita um convite de organização recebido por e-mail
GET/organizations/{oid}/export · POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/downloadExportação da organização exclusiva do owner: um zip com um dump SQL e todos os anexos, executada como job
MétodoCaminhoDescrição
GET/projectsLista seus projetos (limit ≤ 200)
POST/projectsCria um projeto
GET/projects/{id}Obtém detalhes do projeto (viewer)
PUT/projects/{id}Atualiza as configurações do projeto (manager)
DELETE/projects/{id}Exclui um projeto (manager)
POST / DELETE/projects/{id}/pinFixa / desafixa o projeto na sua lista de projetos
POST/projects/{id}/transfer-organizationMove o projeto para outra organização — o chamador precisa ser Gerente do projeto e owner ou admin da organização de destino
POST/projects/{id}/slack/testEnvia uma mensagem de teste ao feed do Slack do projeto (manager)
GET / POST/projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seedProjetos de vitrine públicos: verifica se você pode reivindicar um, reivindica, popula (popular é para administradores do produto; qualquer outra pessoa recebe 404)
GET/projects/{id}/audit-logLeitura do audit log — histórico do projeto mais atividade por história / por épico via surface=; o acesso varia conforme o surface, veja abaixo
GET/projects/{id}/eventsFluxo de eventos paginado por cursor (member) — veja Eventos

Parâmetros de consulta do audit log: event_type= (um tipo ou lista separada por vírgulas), limit= (padrão 50, limitado a 1000), before= (cursor keyset <ISO-8601>|<audit_id> — passe o next_cursor da página anterior), surface= (project_history, story_activities, epic_activities), target_id= (o id da história/épico — obrigatório quando surface=story_activities ou epic_activities). Acesso: o log sem filtro é (manager); surface=project_history é (viewer), com os e-mails dos membros censurados quando o projeto os oculta; story_activities / epic_activities podem ser lidos por qualquer membro do projeto, e anonimamente em projetos públicos com a PII do ator censurada.

MétodoCaminhoDescrição
GET/projects/{id}/membershipsLista membros (viewer)
POST/projects/{id}/membershipsConvida um membro por e-mail (manager)
PUT/projects/{id}/memberships/{mid}Atualiza o papel (manager)
DELETE/projects/{id}/memberships/{mid}Remove um membro (manager)
POST/projects/{id}/memberships/bulk-role · …/memberships/bulk-removeAltera o papel de vários membros de uma vez, ou os remove (manager)
GET/projects/{id}/addable-members · POST /projects/{id}/members/add-existingMembros da organização que ainda não estão no projeto / adiciona um sem convite por e-mail — (manager) e owner ou admin da organização
POST/projects/{id}/members/joinUm owner ou admin da organização entra como manager em um projeto da sua organização, ou se promove a manager (a ação Make me owner na lista de projetos)
GET / POST/projects/{id}/agent_keysLista (manager) / emite chaves de agente — pessoas cujo papel está na política de papéis criadores do projeto; chaves de agente não podem emitir
PUT / DELETE/projects/{id}/agent_keys/{kid}Edita o nome, o papel ou as response hints de uma chave / revoga-a (manager)
GET/projects/{id}/agent_keys/onboardingO pacote de onboarding: prompts e arquivos de configuração para os clientes de agente mais comuns
GET/projects/{id}/agents · GET / PUT / DELETE /projects/{id}/agents/{aid}Os agentes do projeto e seus perfis (nome, iniciais, descrição, cor); DELETE revoga o agente e todas as suas chaves — um manager ou o criador do agente
POST/projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatarRotaciona a chave de um agente (identidade e histórico mantidos) / faz upload do avatar dele

Todas as escritas de história precisam do papel member. Criar uma história com datas retroativas, procedência de importação (import_source / import_external_id) ou owners ou solicitante externos precisa de (manager).

MétodoCaminhoDescrição
GET/projects/{id}/storiesLista histórias (paginadas, filtráveis) (viewer)
POST/projects/{id}/storiesCria uma história
GET/projects/{id}/stories/{sid}Obtém uma história (viewer)
PUT/projects/{id}/stories/{sid}Atualiza uma história
DELETE/projects/{id}/stories/{sid}Exclui uma história
POST/projects/{id}/stories/{sid}/transitionsAltera o estado com validação
POST/projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restartRejeita uma história delivered / devolve uma rejeitada a started (rejected é terminal para /transitions)
POST/projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchiveArquiva / desarquiva uma história
POST/projects/{id}/stories/bulk-unarchiveDesarquiva várias histórias
POST/projects/{id}/stories/bulk_transitionTransiciona muitas histórias (1–100) de uma vez
POST/projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-moveArquiva, exclui, duplica ou move (para um painel / posição) muitas histórias
POST/projects/{id}/stories/{sid}/duplicateDuplica uma história
POST / DELETE/projects/{id}/stories/{sid}/epics · …/epics/{eid}A associação da história a épicos
GET/short-links/{code} · /story-referencesResolve um link curto /s/<code> para a sua história / resolve até 100 referências — codes= (códigos de link curto separados por vírgula) e ids= (project_id:story_id separados por vírgula) — para as histórias que o chamador pode ler

Parâmetros de consulta da lista de histórias: archived= (exclude padrão / include / only — o filtro de arquivamento de três estados; substitui o obsoleto include_archived=true, agora um alias de archived=include), include_done=true (admite histórias do painel Done congeladas em iterações passadas, excluídas por padrão). Paginação (cursor= / limit= / offset=) e conjuntos esparsos de campos (fields=) seguem Paginação e Projeção de campos.

Criar (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. estimate é o rótulo do valor da escala, como string ("3", "13"); um número JSON é rejeitado. labels aceita ["auth"] ou [{ "name": "auth" }]; labels desconhecidas são criadas. Padrões: story_type=feature, current_state=unstarted.

Atualizar (PUT …/stories/{sid}): os mesmos campos, todos opcionais, mais "position" (float), "force_state_change" (bool) e "expected_version" (inteiro, a version da história — salvar uma descrição é recusado com 409 stale_write se a descrição mudou depois dessa versão). O antigo "expected_updated_at" (RFC 3339) está obsoleto e funciona por mais uma versão: enviado com uma descrição e sem expected_version, salvar é recusado com 409 stale_write a menos que seja igual ao updated_at da história. As escritas de história também respeitam If-Match contra o ETag da história; uma divergência resulta em 412 precondition_failed.

Transição (POST …/transitions): { "to": "<state>" }. O campo é to. Retorna { story_id, state }. Movimento ilegal → 422 invalid_transition com details: { from, to, allowed }.

Transição em massa (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>" }. Cada história é julgada de forma independente; retorna { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.

Todos member. Listar/GET na maioria é (viewer). Excluir um anexo ou anexo de link exige quem o enviou ou (manager).

MétodoCaminhoCorpo / observações
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) } ou { comment_emoji }. GET recebe fields= (lista de permitidos: comment_id, story_comment_id, story_id, comment_text, comment_emoji, member, created) mais 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}Criar: { url, link_type?, title? }; atualizar: { url, title? } — link_type ∈ relates_to, duplicates, blocks, is_blocked_by, pull_request, branch, other; URLs /pull/ e /tree/ do GitHub recebem o tipo automaticamente
GET / POST/projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid}Criar: { reviewer_id? / reviewer_agent_id?, comment? } — omita ambos para atribuir a você mesmo. Atualizar: { status, comment? }
GET / POST/projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid}{ member_id? / agent_id? } — omita ambos para adicionar o chamador
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}{ label_id } — uma label existente do projeto; crie labels com POST /projects/{id}/labels, ou envie labels no PUT da história
GET / POST/projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid}upload multipart — vídeo ≤ 200 MB, PDF / Word / Excel ≤ 25 MB, imagens / CSV / texto ≤ 10 MB; listar é (viewer)
GET / POST/projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid}Anexos de link — uma URL externa mantida junto aos anexos de arquivo, e não como link de código
GET/attachments/{token} · /api/v1/avatars/{token}Leituras endereçadas por token de um anexo ou avatar — as URLs que a API entrega; não precisam de X-TrackerToken

Mesmo formato das histórias, sem a máquina de estados. member para escritas e para as listas de comentários, owners e seguidores; (viewer) para a lista de épicos, um único épico e as listas de anexos.

MétodoCaminhoDescrição
GET / POST/projects/{id}/epics · GET / PUT / DELETE …/epics/{eid}Os épicos têm um nome, uma descrição em Markdown e uma label de apoio que reúne suas histórias
GET / POST / PUT / DELETE…/epics/{eid}/comments · …/comments/{cid}Comentários de épicos
GET / POST / DELETE…/epics/{eid}/owners · …/followers (+ variantes /agents/{aid})Owners e seguidores, membros ou agentes — os owners de um épico se propagam para suas histórias
GET / POST / DELETE…/epics/{eid}/attachments (+ /json) · …/link-attachmentsAnexos, com os mesmos limites das histórias
GET/projects/{id}/analytics/epics · …/analytics/epics/{eid}Progresso por épico: burnup, vazão, saúde, previsão (viewer)

member para escritas, (viewer) para leituras.

MétodoCaminhoDescrição
GET / POST/projects/{id}/labelsLista / cria uma label
GET / PUT / DELETE/projects/{id}/labels/{lid}Lê / atualiza / exclui uma label
POST/projects/{id}/labels/{lid}/archiveArquiva (oculta suavemente) uma label

As leituras são abertas a qualquer papel de projeto, e anônimas em um projeto público.

MétodoCaminhoDescrição
GET/projects/{id}/iterationsLista iterações (≤ 500 por página; traz um ETag e os cabeçalhos de continuação X-Tracker-Pagination-* quando truncada)
GET/projects/{id}/iterations/{itid}Uma iteração
GET/projects/{id}/iterations/first-previewA janela, a velocidade projetada e o preenchimento a partir do Backlog da iteração que uma escrita inicial criaria, ou da iteração atual quando ela existe (member)
POST/projects/{id}/iterationsCria uma iteração manual (manager)
DELETE/projects/{id}/iterations/{itid}Exclui uma iteração (manager)
PUT/projects/{id}/iterations/{itid}/velocitySubstitui a velocidade de uma iteração sem alterar a estratégia do projeto (manager)
GET/projects/{id}/iterations/{itid}/done-storiesAs histórias aceitas de uma iteração encerrada, paginadas
MétodoCaminhoDescrição
GET/projects/{id}/search?q=…Busca poderosa — texto completo + qualificadores de faceta / intervalo de datas / pessoas (DSL no estilo do GitHub); retorna { results, total, limit, offset }. query é um alias de q; limit= (padrão 50, máx. 1000) / offset= paginam; sort= ordena por relevance (padrão), created, created_asc, state ou updated. (viewer) — veja o Guia
GET/projects/{id}/metrics/{velocity,burndown,story-types,contributors}As séries da página Metrics (viewer); as métricas de épicos ficam em /analytics/epics, acima
GET/projects/{id}/backlog/groupingOs grupos de iterações projetados do Backlog (viewer)
GET / PUT/projects/{id}/preferencesSuas preferências de quadro para este projeto — qualquer papel de projeto, apenas a sua própria linha
MétodoCaminhoDescrição
GET/projects/{id}/eventsFluxo de eventos paginado por cursor (member) — viewers recebem 403

Parâmetros de consulta: since_id=<event_id> (since é o alias mais antigo; since_id prevalece quando ambos são enviados), types=story.created,story.transitioned,comment.added,…, limit= (padrão 100, ≤ 500), cursor=. A resposta é { items, next_since_id, next_cursor }: guarde next_since_id e passe-o de volta como since_id para retomar; next_cursor é null na última página.

O feed unificado de notificações no app: linhas de notificação de primeira classe (pedidos de review, atividade de histórias, convites, …) mescladas com a caixa de @-menções em um único fluxo, do mais recente para o mais antigo. Os ids do feed têm prefixo de origem (nt-… / sc-… / ec-…). Sessões de membro e chaves ea_user_* leem suas linhas de membro; chaves ea_agent_* suas linhas de agente.

MétodoCaminhoDescrição
GET/me/notificationsSeu feed de notificações. Filtros: unread=true, since_id=, kind= (mentions / reviews / stories / invitations); pagine com cursor= / limit=
GET/me/notifications/unread-countTotais não lidos — { unread_count, by_category: { mentions, reviews, stories, invitations } }
POST/me/notifications/read-allMarcar tudo como lido; devolve os contadores atualizados
POST/me/notifications/{id}/ackMarcar um item como lido (idempotente)
POST/me/notifications/{id}/acceptAceitar um convite de projeto / organização a partir do feed (apenas tokens de membro)
POST/me/notifications/{id}/declineRecusar um convite de projeto / organização (apenas tokens de membro)
GET/me/notifications/resolve-invite?token=…Resolver um token de convite recebido por e-mail para o id da sua notificação — { "id": "nt-…" } ou { "id": null }
GET/me/notifications/streamPush ao vivo — Server-Sent Events (text/event-stream); veja abaixo

O endpoint de stream não é um endpoint JSON e, portanto, não está na especificação OpenAPI: ele mantém a conexão aberta e emite um frame sem payload ({"type":"notification","kind":…}) sempre que algo novo chega, sinalizando ao cliente que recarregue o feed. As conexões são encerradas no servidor após 45 minutos — reconecte e autentique-se novamente. Apenas sessões de membro e chaves ea_user_*; chaves ea_agent_* recebem 403.

MétodoCaminhoDescrição
POST/projects/{id}/importFontes de arquivo: source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json, eat. Multipart file=. Síncrono — responde com as contagens do resultado.
POST/projects/{id}/import/jsonCorpo JSON; source=github não precisa de arquivo — owner, repo, token opcional e as flags opt-in include_pull_requests / include_milestones / include_releases / include_dependencies, e include_comments (padrão true); as fontes de arquivo enviam file_base64. Assíncrono: retorna 202 { import_id, status }. O servidor busca pela API GraphQL do GitHub, que rejeita chamadores anônimos, então um token sempre chega ao GitHub — o seu, ou o compartilhado do deployment. Veja o Guia.
GET/projects/{id}/imports/{import_id}Consulta um job: status avança por pending → fetching → writing → done | failed, com progress_current / progress_total durante a busca e as contagens do resultado em done

Só uma importação JSON roda por projeto de cada vez; um segundo POST …/import/json enquanto outra está em andamento dá 409 import_already_running. Com check_unpointed_estimates: true (fontes de arquivo; ignorado para github), um arquivo com estimativas de bugs ou tarefas que o projeto não pontua é recusado com 409 import_unpointed_estimates e details.count antes de qualquer job começar; sem a flag, a importação descarta essas estimativas e reporta { code: "estimates_unpointed_dropped", count } nos warnings do resultado. dry_run: true (corpo JSON ou dry_run=true multipart) faz a prévia de qualquer fonte: analisa, resolve, remove duplicatas, retorna as mesmas contagens { imported, skipped, errors, unmatched } e então reverte — nada é escrito. Limites: um arquivo de 10 MiB (400 import_too_large) e 5.000 histórias por importação para as fontes de arquivo (400 import_too_many_records); nada é escrito. Um corpo de requisição acima de 16 MiB é recusado antes, com 413 request_too_large. A fonte GitHub não tem teto — ela grava em blocos em vez de uma única transação. A reimportação é idempotente por id de origem — linhas já importadas são ignoradas, não duplicadas.

MétodoCaminhoDescrição
GET/projects/{id}/export/formatsFormatos registrados: { id, name, content_type, drops, includes_archived }. Qualquer papel de projeto.
GET/projects/{id}/export/{format}Baixa um (manager). Intercâmbio: eat (fidelidade total), jira, pivotal, shortcut, trello, asana, gitlab, linear, plane, plane_json; documentos: pdf, docx.
GET/projects/{id}/export/attachmentsTodo anexo como um único zip navegável (os arquivos mantêm os nomes originais; manifesto JSON + CSV) (manager).

Exportações de documentos (pdf, docx) recebem parâmetros de consulta extras: page_size= (letter padrão / a4 / legal / folio), from= / to= (limites da janela de histórias — RFC 3339 ou apenas YYYY-MM-DD; uma história está no intervalo quando seu created ou completed_at cai dentro dele), include_icebox= / include_backlog= (ambos padrão false, então uma exportação compartilhável mostra apenas trabalho agendado / em andamento). Os formatos CSV de intercâmbio os ignoram.

MétodoCaminhoDescrição
GET / POST/projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/healthLista snapshots, cria um agora, lê um, e o resumo de saúde da retenção
POST/projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id}Restaura um snapshot inteiro, ou tabelas selecionadas de um, e consulta o andamento da restauração

Esses POSTs ficam no nível de limite de taxa sensitive (abaixo).

East Agile Tracker é um provedor OAuth 2.1 para clientes MCP. Um cliente o descobre em /.well-known/oauth-authorization-server e /.well-known/oauth-protected-resource/mcp, envia você para /oauth/authorize (a página de consentimento), troca o código em /oauth/token e então fala MCP em /mcp com o token ea_mcp_* resultante. As autorizações são listadas e revogadas em /me/oauth_grants. Os endpoints do provedor têm seu próprio nível de limite de taxa.

Os endpoints de escrita (POST, PUT, DELETE) aceitam um cabeçalho Idempotency-Key. A mesma chave + o mesmo corpo reproduz a resposta em cache (janela de 24 horas); a mesma chave + um corpo diferente retorna 409 idempotency_conflict. A chave tem como escopo a credencial que a enviou. Não se aplica a GET/HEAD/OPTIONS, a /openapi.json e /docs, a /api/auth/*, a /mcp, a nenhum caminho que contenha /attachments nem a nenhuma requisição multipart/*; uma requisição sem credencial nunca é armazenada em cache. Respostas que pararam antes de uma resposta de domínio nunca são armazenadas em cache — 401, 403, 404, 429 e todo 5xx — então uma nova tentativa depois de qualquer uma delas alcança o handler; 400, 409, 412 e 422 são a resposta do domínio e são reproduzidas como um sucesso.

Os endpoints de listagem aceitam cursor=<opaque> e limit=<n>. Quando definidos, a resposta é { "items": [...], "next_cursor": "<str|null>" }; passe next_cursor de volta para paginar. O teto de limit é por endpoint: 200 em histórias, comentários e projetos; 500 em eventos; 1000 no audit log. A busca pagina com limit (≤ 1000) e offset em vez de um cursor e retorna { results, total, limit, offset }.

Uma lista simples (sem cursor/limit) que precisou truncar a resposta avisa nos cabeçalhos — X-Tracker-Pagination-Truncated, X-Tracker-Pagination-Limit, X-Tracker-Pagination-Offset e X-Tracker-Pagination-Next-Offset; passe o último de volta como offset= para a próxima página. Não há cabeçalho com a contagem total.

As listagens de histórias, comentários e projetos aceitam fields= (separados por vírgula) para retornar apenas campos específicos. O id do recurso é sempre incluído (story_id, story_comment_id e comment_id, project_id); um nome de campo desconhecido retorna 400 validation_failed com os nomes problemáticos em details.fields.

GET /projects/123/stories?fields=story_id,name,current_state,owners

Todo erro JSON tem code e error; alguns adicionam details:

{ "code": "invalid_transition",
"error": "Cannot move story from `unstarted` to `accepted`",
"details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }
StatuscodeQuando
400invalid_parameterentrada inválida; mensagem em error. A validação de campos (em branco/comprimento/byte nulo/e-mail) acrescenta details.fields e details.constraint; só um erro simples de requisição inválida omite details
400validation_failederro de entrada estruturado; details.fields é um array dos nomes dos campos problemáticos
400códigos de domíniouma recusa específica da rota, com código próprio e sem details — ex.: unsupported_export_format, import_too_large, import_unknown_source
401unauthenticatedtoken ausente/inválido
403unauthorized_operationautenticado, mas com papel insuficiente
404unfound_resourcenão encontrado — também retornado a não-membros
409conflictconflito de recurso (por exemplo, duplicata)
409idempotency_conflictIdempotency-Key reutilizado com um corpo diferente
409stale_write · import_already_running · import_unpointed_estimatesa descrição mudou depois do seu expected_version (ou expected_updated_at não corresponde mais) · uma importação já está em andamento · o arquivo tem estimativas de bugs ou tarefas que o projeto não pontua (details.count)
412precondition_failedIf-Match não corresponde ao ETag atual do recurso; details traz expected e current
413request_too_largeo corpo excede o limite de tamanho da rota
422invalid_transitionmovimento de estado ilegal; details carrega { from, to, allowed }
429rate_limitedrequisições demais deste IP em uma rota com limite de taxa; cabeçalho Retry-After
500internal_errorfalha do servidor — mensagem genérica; seguro para tentar novamente
502upstream_errorum serviço do qual a rota depende (ex.: GitHub) falhou
503not_configuredo deployment não tem a integração de que esta rota precisa (SMS, armazenamento de objetos, …)

details.fields é um array JSON de nomes de campos (por exemplo, ["to"]), às vezes com chaves extras como max. Não há um mapa de campo→mensagem.

{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }

Por IP de cliente, em um punhado de rotas; o restante do tráfego autenticado da API não tem limite de taxa. Padrões (cada par é a taxa sustentada e o burst, ajustáveis pelo operador):

  • Auth — /api/auth/*: 0,5 req/s, burst 20.
  • OAuth provider — /oauth/*: 1 req/s, burst 60.
  • Public — /api/contact: 0,2 req/s, burst 10.
  • Feedback — /api/v1/feedback e /api/v1/feedback/with-screenshot: três níveis sobrepostos — um envio a cada 15 s, 10 por hora, 36 por dia.
  • Avatars — o redirecionamento de avatar não autenticado: 20 req/s, burst 200.
  • Sensitive — os POSTs de backup e restauração: ~0,002 req/s, burst 5.

Um limite excedido retorna 429 com um cabeçalho Retry-After e o envelope de erro JSON padrão, code: "rate_limited".