Riferimento completo degli endpoint REST dell'API di East Agile Tracker: autenticazione e ruoli, progetti, story, epic, iterazioni, eventi, importazione ed esportazione.
Il riferimento completo degli endpoint REST. Per tutorial ed esempi, vedi la Guida API.
Tutto ciò che un member del progetto può fare nell’interfaccia web è disponibile qui — la SPA consuma questa stessa API. Le operazioni che richiedono il ruolo manager sono contrassegnate (manager); tutto il resto richiede solo l’appartenenza al progetto (o, per le letture contrassegnate (viewer), qualsiasi livello di accesso). Le tabelle qui sotto nominano ogni gruppo di route che il server monta; quelli riassunti in una sola riga sono descritti per intero nell’openapi.json live.
https://api.eastagiletracker.com/api/v1L’API ha un proprio host: eastagiletracker.com serve l’app web e risponde a /api/v1/… con 404. Tutte le richieste e le risposte sono JSON, eccetto alcuni endpoint di upload file che accettano multipart.
Due gruppi stanno un livello più su, sotto /api anziché /api/v1: la superficie di autenticazione (/api/auth/*) e il modulo di contatto pubblico (/api/contact). Le loro grafie /api/v1/… restituiscono 404.
Autenticazione
Sezione intitolata “Autenticazione”Ogni richiesta autenticata invia una credenziale tramite uno di:
X-TrackerToken: <key>Authorization: Bearer <key>
Le chiavi utente iniziano con ea_user_, le chiavi agente con ea_agent_ e i token di accesso MCP con ea_mcp_. Vedi Guida API → Tre tipi di credenziali.
Endpoint non autenticati: /openapi.json, /docs, gli endpoint /api/auth/* e i lookup dei dati di riferimento (/story_types, /story_states, /effort_scales, /priority_scales). /meta è autenticato — funziona qualsiasi chiave valida, ma non ha ambito di progetto (raggiungibile anche da una chiave agente vincolata a un progetto).
Quattro livelli regolano gli endpoint con ambito di progetto:
| Level | Who passes | Typical operations |
|---|---|---|
| public viewer | chiunque, su un progetto la cui visibilità è pubblica | letture della board: storie, iterazioni, ricerca, attività di storie ed epic (con i dettagli dell’attore oscurati) |
| viewer | viewer, member, manager | letture (elenco/get di storie, ricerca, metriche, elenco dei formati di export) |
| member | member, manager | tutte le scritture di work-item (storie, task, commenti, …), lo stream di eventi |
| manager | solo manager | impostazioni progetto, gestione appartenenze, chiavi agente, eliminazione, importazione, download degli export, backup, audit log |
Gli agenti hanno gli stessi ruoli dei membri — viewer, member o manager — con un tetto pari al ruolo del membro che ha generato la chiave. Un non-membro riceve 404 unfound_resource (non 403) sui path dei progetti privati, così gli ID dei progetti non sono enumerabili.
Endpoint auto-descrittivi
Sezione intitolata “Endpoint auto-descrittivi”| Method | Path | Description |
|---|---|---|
| GET | /openapi.json | La spec OpenAPI 3 live, request body inclusi. Non autenticato. |
| GET | /docs | Swagger UI. Non autenticato. |
| GET | /meta | Identità del chiamante (auth.kind/key_id/agent_id/project_id) + il grafo delle transizioni per tipo di storia. Autenticato (qualsiasi chiave valida; non con ambito di progetto). Chiamalo per primo. |
| GET | /api/health · /api/config | Liveness, e la configurazione pubblica del deployment (modalità organizzazione singola, funzionalità opzionali attive, nome dell’istanza). Non autenticati, fuori da /v1. |
Auth (/api/auth/*, fuori da /v1)
Sezione intitolata “Auth (/api/auth/*, fuori da /v1)”Endpoint di sessione, non autenticati salvo diversa indicazione. Li pilota la SPA; gli script di norma usano invece una chiave API.
| Method | Path | Description |
|---|---|---|
| POST | /auth/register | Registra un nuovo account — protetto da reCAPTCHA; l’account supera poi la verifica SMS |
| POST | /auth/sms/challenge · /auth/sms/status · /auth/sms/bypass | Invia / controlla il codice SMS di registrazione (il bypass è riservato all’operatore) |
| GET | /auth/config | Quali metodi di accesso offre il deployment |
| POST | /auth/login | Accedi con email + password; restituisce un JWT di sessione, oppure una sfida TOTP |
| POST | /auth/login/totp | Completa un accesso con un codice dell’app authenticator o un codice di recupero |
| POST | /auth/passkey/login/start · /auth/passkey/login/finish | Accesso WebAuthn senza password |
| GET | /auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchange | Accesso OAuth con GitHub o Google |
| POST | /auth/refresh · /auth/refresh/revoke | Ruota il refresh token / revocalo |
| POST | /auth/logout | Esci (autenticato; revoca il refresh token di questa sessione) |
| POST | /auth/forgot-password · /auth/reset-password | Richiedi un’email di reimpostazione / usa il token di reset |
| POST | /auth/accept-invite/lookup · /auth/accept-invite | Risolvi un token di invito → email / accetta l’invito al progetto (dopo l’autenticazione) |
| POST | /auth/oauth/link/preview · …/link/confirm · /auth/oauth/merge/preview · …/merge/confirm | Collega un account GitHub o Google a uno esistente, oppure unisci due account |
| POST | /auth/email_addresses/primary/preview · …/primary/confirm | Completa un cambio dell’email principale dal link di conferma ricevuto via email |
Account / identità
Sezione intitolata “Account / identità”Queste agiscono sul chiamante e non richiedono alcun ruolo di progetto. Richiedono un’identità di membro — una chiave agente riceve 401 (gli agenti usano /agent/me). Le chiamate che modificano le credenziali — password, TOTP, passkey, eliminazione dell’account, un cambio di email, rigenerazione del token — richiedono una sessione del browser; una chiave API riceve 403.
| Method | Path | Description |
|---|---|---|
| GET | /me | Profilo dell’utente corrente |
| PUT | /me | Aggiorna il profilo |
| DELETE | /me | Elimina l’account — rifiutato finché sei l’unico owner di un’organizzazione o di un progetto con altri membri |
| GET | /me/deletion-impact | Cosa rimuoverebbe l’eliminazione dell’account e cosa la blocca |
| PUT | /me/password | Cambia password |
| PUT | /me/settings | Aggiorna le impostazioni (tema, preferenze di notifica) |
| POST / DELETE | /me/avatar | Carica (multipart) / rimuovi il tuo avatar |
| POST | /me/api-token/regenerate | Disconnetti ogni sessione e restituisci un nuovo token di sessione; le chiavi API non sono interessate |
| GET / POST | /me/email_addresses · GET …/email_addresses/offers · PUT …/email_addresses/primary | I tuoi indirizzi email; adotta l’indirizzo di un provider collegato come alternativo; richiedi un cambio dell’indirizzo principale (confermato via email) |
| GET | /me/oauth_identities · DELETE …/oauth_identities/{provider} · POST …/oauth_identities/{provider}/link | Account di accesso collegati (GitHub, Google): elenca, scollega, avvia un collegamento |
| GET | /me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id} | Gestisci le chiavi API utente (ea_user_) |
| GET | /me/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disable | Registrazione a due fattori (TOTP); verify restituisce i codici di recupero una sola volta |
| GET | /me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id} | Registrazione e rimozione delle passkey |
| GET | /me/oauth_grants · DELETE /me/oauth_grants/{grant_id} | App connesse — i client MCP e le app OAuth che hai autorizzato |
| GET | /me/activity | La tua attività in tutti i progetti |
| GET | /me/stories | Le storie di cui sei owner, che hai richiesto o che segui in ogni progetto raggiungibile dal token — role=owned|requested|following, state=, cursor= / limit= (max 200) |
| GET | /me/mentions · POST /me/mentions/{mention_id}/ack | La casella delle @-menzioni (unacked=true per filtrare) e la conferma di lettura — confluisce anche nel feed di notifiche più sotto |
| GET | /me/data-export | Auto-esportazione GDPR dei tuoi dati |
| GET | /me/consent · POST /me/consent | Leggi / registra il consenso ({ consent_type, granted }) |
| GET | /legal/pending · POST /legal/accept | Documenti clickwrap in sospeso / registra l’accettazione |
| GET / PUT | /agent/me | L’identità e il profilo di una chiave agente, leggibili e modificabili dall’agente stesso (la controparte lato agente di /me) |
| POST | /api/contact · /api/v1/feedback · /api/v1/feedback/with-screenshot | Contatto + feedback in-app; a frequenza limitata per IP |
Dati di riferimento (non autenticati)
Sezione intitolata “Dati di riferimento (non autenticati)”Lookup di seed usati quando si creano/stimano storie. ID stabili.
| Method | Path | Description |
|---|---|---|
| GET | /story_types | feature, bug, chore, release (+ allow_points) |
| GET | /story_states | unstarted … accepted, rejected |
| GET | /effort_scales | scale di stima disponibili |
| GET | /effort_scales/{scale_id}/values | i valori di punti in una scala |
| GET | /priority_scales · /priority_scales/{scale_id}/values | le scale di priorità e i loro valori (il priority_id di una storia si risolve qui) |
Organizzazioni
Sezione intitolata “Organizzazioni”Solo servizio hosted — un’installazione self-hosted gira in modalità organizzazione singola e non monta questi endpoint (tranne l’elenco delle organizzazioni). I ruoli sono ruoli di organizzazione: owner, admin, member.
| Method | Path | Description |
|---|---|---|
| GET / POST | /organizations | Elenca le tue organizzazioni / creane una |
| GET / PUT / DELETE | /organizations/{oid} | Leggi, rinomina (nome + slug; owner o admin), elimina |
| GET / POST | /organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id} | Membri e inviti; gli inviti hanno un tetto di ruolo (mai sopra quello del chiamante; il ruolo owner non si invita mai) |
| POST | /organizations/{oid}/memberships/bulk-role · …/memberships/bulk-remove | Cambia il ruolo di un massimo di 200 membri in una volta o rimuovili. Tutto o niente: un batch che rimuoverebbe l’ultimo owner o lascerebbe un progetto senza proprietario viene rifiutato per intero; con reassign_confirmed diventi invece proprietario di quei progetti |
| DELETE | /organizations/{oid}/invitations/{invitation_id} | Revoca un invito in sospeso |
| POST | /organizations/{oid}/transfer-ownership | Passa il ruolo owner a un altro membro |
| GET | /organization-invitations/{token} · POST …/{token}/accept | Risolvi / accetta un invito all’organizzazione ricevuto via email |
| GET | /organizations/{oid}/export · POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/download | Export dell’organizzazione riservato all’owner: uno zip con un dump SQL e ogni allegato, eseguito come job |
Progetti
Sezione intitolata “Progetti”| Method | Path | Description |
|---|---|---|
| GET | /projects | Elenca i tuoi progetti (limit ≤ 200) |
| POST | /projects | Crea un progetto |
| GET | /projects/{id} | Ottieni i dettagli del progetto (viewer) |
| PUT | /projects/{id} | Aggiorna le impostazioni del progetto (manager) |
| DELETE | /projects/{id} | Elimina un progetto (manager) |
| POST / DELETE | /projects/{id}/pin | Fissa / sblocca il progetto nel tuo elenco progetti |
| POST | /projects/{id}/transfer-organization | Sposta il progetto in un’altra organizzazione — il chiamante deve essere Responsabile del progetto e owner o admin dell’organizzazione di destinazione |
| POST | /projects/{id}/slack/test | Invia un messaggio di prova al feed Slack del progetto (manager) |
| GET / POST | /projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seed | Progetti vetrina pubblici: verifica se puoi rivendicarne uno, rivendicalo, popolalo (il popolamento è riservato agli admin del prodotto; chiunque altro riceve 404) |
| GET | /projects/{id}/audit-log | Lettura dell’audit log — cronologia del progetto più attività per storia / per epic tramite surface=; l’accesso varia in base al surface, vedi sotto |
| GET | /projects/{id}/events | Stream di eventi paginato a cursore (member) — vedi Events |
Parametri di query dell’audit log: event_type= (un tipo o elenco separato da virgole), limit= (default 50, limitato a 1000), before= (cursore keyset <ISO-8601>|<audit_id> — passa il next_cursor della pagina precedente), surface= (project_history, story_activities, epic_activities), target_id= (l’id della storia/epic — richiesto quando surface=story_activities o epic_activities). Accesso: il log non filtrato è (manager); surface=project_history è (viewer), con le email dei membri oscurate quando il progetto le nasconde; story_activities / epic_activities sono leggibili da qualsiasi membro del progetto, e in forma anonima sui progetti pubblici con i dati personali dell’attore oscurati.
Membri, agenti e chiavi agente
Sezione intitolata “Membri, agenti e chiavi agente”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/memberships | Elenca i membri (viewer) |
| POST | /projects/{id}/memberships | Invita un membro via email (manager) |
| PUT | /projects/{id}/memberships/{mid} | Aggiorna il ruolo (manager) |
| DELETE | /projects/{id}/memberships/{mid} | Rimuovi un membro (manager) |
| POST | /projects/{id}/memberships/bulk-role · …/memberships/bulk-remove | Cambia il ruolo di molti membri in una volta, o rimuovili (manager) |
| GET | /projects/{id}/addable-members · POST /projects/{id}/members/add-existing | Membri dell’organizzazione non ancora nel progetto / aggiungine uno senza invito via email — (manager) e owner o admin dell’organizzazione |
| POST | /projects/{id}/members/join | Un owner o admin dell’organizzazione entra come manager in un progetto della sua organizzazione, o si promuove a manager (l’azione Make me owner nell’elenco progetti) |
| GET / POST | /projects/{id}/agent_keys | Elenca (manager) / genera chiavi agente — le persone il cui ruolo rientra nella policy dei ruoli creatori del progetto; le chiavi agente non possono generarne |
| PUT / DELETE | /projects/{id}/agent_keys/{kid} | Modifica nome, ruolo o suggerimenti di risposta di una chiave / revocala (manager) |
| GET | /projects/{id}/agent_keys/onboarding | Il bundle di onboarding: prompt e file di configurazione per i client agente più comuni |
| GET | /projects/{id}/agents · GET / PUT / DELETE /projects/{id}/agents/{aid} | Gli agenti del progetto e i loro profili (nome, iniziali, descrizione, colore); DELETE revoca l’agente e tutte le sue chiavi — un manager o il creatore dell’agente |
| POST | /projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatar | Ruota la chiave di un agente (identità e cronologia conservate) / carica il suo avatar |
Tutte le scritture sulle storie richiedono il ruolo member. Creare una storia con date retrodatate, provenienza da importazione (import_source / import_external_id), oppure owner o requester esterni richiede (manager).
| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/stories | Elenca le storie (paginato, filtrabile) (viewer) |
| POST | /projects/{id}/stories | Crea una storia |
| GET | /projects/{id}/stories/{sid} | Ottieni una storia (viewer) |
| PUT | /projects/{id}/stories/{sid} | Aggiorna una storia |
| DELETE | /projects/{id}/stories/{sid} | Elimina una storia |
| POST | /projects/{id}/stories/{sid}/transitions | Cambia stato con validazione |
| POST | /projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restart | Rifiuta una storia delivered / riporta una storia rifiutata a started (rejected è terminale per /transitions) |
| POST | /projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchive | Archivia / rimuovi dall’archivio una storia |
| POST | /projects/{id}/stories/bulk-unarchive | Rimuovi dall’archivio molte storie |
| POST | /projects/{id}/stories/bulk_transition | Fai transitare molte storie (1–100) in una volta |
| POST | /projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-move | Archivia, elimina, duplica o sposta (su un pannello / in una posizione) molte storie |
| POST | /projects/{id}/stories/{sid}/duplicate | Duplica una storia |
| POST / DELETE | /projects/{id}/stories/{sid}/epics · …/epics/{eid} | L’appartenenza della storia agli epic |
| GET | /short-links/{code} · /story-references | Risolvi uno short link /s/<code> nella sua storia / risolvi fino a 100 riferimenti — codes= (codici di short link separati da virgola) e ids= (project_id:story_id separati da virgola) — nelle storie leggibili dal chiamante |
Parametri di query dell’elenco storie: archived= (exclude default / include / only — il filtro degli archiviati a tre stati; sostituisce il deprecato include_archived=true, che ora è un alias di archived=include), include_done=true (ammette le storie del pannello Done congelate su iterazioni passate, escluse per default). La paginazione (cursor= / limit= / offset=) e i set di campi parziali (fields=) seguono Paginazione e Proiezione dei campi.
Create (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. estimate è l’etichetta del valore della scala, come stringa ("3", "13"); un numero JSON viene rifiutato. labels accetta ["auth"] o [{ "name": "auth" }]; le label sconosciute vengono create. Default: story_type=feature, current_state=unstarted.
Update (PUT …/stories/{sid}): stessi campi, tutti opzionali, più "position" (float), "force_state_change" (bool) e "expected_version" (intero, la version della storia — il salvataggio di una descrizione viene rifiutato con 409 stale_write se la descrizione è cambiata dopo quella versione). Il vecchio "expected_updated_at" (RFC 3339) è deprecato e funziona ancora per una release: inviato con una descrizione e senza expected_version, il salvataggio viene rifiutato con 409 stale_write a meno che non corrisponda all’updated_at della storia. Le scritture sulle storie onorano anche If-Match rispetto all’ETag della storia; una discrepanza dà 412 precondition_failed.
Transition (POST …/transitions): { "to": "<state>" }. Il campo è to. Restituisce { story_id, state }. Movimento illegale → 422 invalid_transition con details: { from, to, allowed }.
Bulk transition (POST …/bulk_transition): { "story_ids": [int,…] (1–100), "to": "<state>" }. Ogni storia è giudicata indipendentemente; restituisce { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.
Sotto-risorse della storia
Sezione intitolata “Sotto-risorse della storia”Tutte member. List/GET sulla maggior parte è (viewer). Eliminare un allegato o un link allegato richiede chi lo ha caricato oppure (manager).
| Method | Path | Body / notes |
|---|---|---|
| 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) } oppure { comment_emoji }. GET accetta fields= (allowlist: comment_id, story_comment_id, story_id, comment_text, comment_emoji, member, created) più 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} | Creazione: { url, link_type?, title? }; aggiornamento: { url, title? } — link_type ∈ relates_to, duplicates, blocks, is_blocked_by, pull_request, branch, other; gli URL GitHub /pull/ e /tree/ vengono tipizzati automaticamente |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | Creazione: { reviewer_id? / reviewer_agent_id?, comment? } — ometti entrambi per assegnare te stesso. Aggiornamento: { status, comment? } |
| GET / POST | /projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid} | { member_id? / agent_id? } — ometti entrambi per aggiungere il chiamante |
| 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 } — una label di progetto esistente; crea le label con POST /projects/{id}/labels, oppure invia labels nel PUT della storia |
| GET / POST | /projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid} | upload multipart — video ≤ 200 MB, PDF / Word / Excel ≤ 25 MB, immagini / CSV / testo ≤ 10 MB; l’elenco è (viewer) |
| GET / POST | /projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid} | Allegati-link — un URL esterno tenuto accanto agli allegati file anziché come link al codice |
| GET | /attachments/{token} · /api/v1/avatars/{token} | Letture indirizzate da token di un allegato o di un avatar — gli URL che l’API restituisce; nessun X-TrackerToken necessario |
Stessa forma delle storie, senza la macchina a stati. member per le scritture e per gli elenchi di commenti, owner e follower; (viewer) per l’elenco degli epic, un singolo epic e gli elenchi degli allegati.
| Method | Path | Description |
|---|---|---|
| GET / POST | /projects/{id}/epics · GET / PUT / DELETE …/epics/{eid} | Gli epic hanno un nome, una descrizione Markdown e una label di supporto che unisce le loro storie |
| GET / POST / PUT / DELETE | …/epics/{eid}/comments · …/comments/{cid} | Commenti agli epic |
| GET / POST / DELETE | …/epics/{eid}/owners · …/followers (+ varianti /agents/{aid}) | Owner e follower, membri o agenti — gli owner di un epic si propagano alle sue storie |
| GET / POST / DELETE | …/epics/{eid}/attachments (+ /json) · …/link-attachments | Allegati, stessi limiti delle storie |
| GET | /projects/{id}/analytics/epics · …/analytics/epics/{eid} | Avanzamento per epic: burnup, throughput, salute, previsione (viewer) |
member per le scritture, (viewer) per le letture.
| Method | Path | Description |
|---|---|---|
| GET / POST | /projects/{id}/labels | Elenca / crea una label |
| GET / PUT / DELETE | /projects/{id}/labels/{lid} | Leggi / aggiorna / elimina una label |
| POST | /projects/{id}/labels/{lid}/archive | Archivia (nascondi in modo soft) una label |
Iterazioni
Sezione intitolata “Iterazioni”Le letture sono aperte a qualsiasi ruolo di progetto, e anonime su un progetto pubblico.
| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/iterations | Elenca le iterazioni (≤ 500 per pagina; porta un ETag e gli header di continuazione X-Tracker-Pagination-* quando è troncato) |
| GET | /projects/{id}/iterations/{itid} | Una singola iterazione |
| GET | /projects/{id}/iterations/first-preview | La finestra, la velocity prevista e il riempimento dal Backlog dell’iterazione che una scrittura di avvio creerebbe, o dell’iterazione corrente quando esiste (member) |
| POST | /projects/{id}/iterations | Crea un’iterazione manuale (manager) |
| DELETE | /projects/{id}/iterations/{itid} | Elimina un’iterazione (manager) |
| PUT | /projects/{id}/iterations/{itid}/velocity | Sovrascrivi la velocity di una singola iterazione senza cambiare la strategia del progetto (manager) |
| GET | /projects/{id}/iterations/{itid}/done-stories | Le storie accettate di un’iterazione chiusa, paginate |
Ricerca, metriche, preferenze
Sezione intitolata “Ricerca, metriche, preferenze”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/search?q=… | Ricerca potente — full-text + qualificatori di faccetta / intervallo di date / persone (DSL in stile GitHub); restituisce { results, total, limit, offset }. query è alias di q; limit= (default 50, max 1000) / offset= paginano; sort= ordina per relevance (default), created, created_asc, state o updated. (viewer) — vedi la Guida |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types,contributors} | Le serie della pagina Metrics (viewer); le metriche degli epic sono sotto /analytics/epics, più sopra |
| GET | /projects/{id}/backlog/grouping | I gruppi di iterazioni proiettati dal Backlog (viewer) |
| GET / PUT | /projects/{id}/preferences | Le tue preferenze di board per questo progetto — qualsiasi ruolo di progetto, solo la tua riga |
| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/events | Stream di eventi paginato a cursore (member) — i viewer ricevono 403 |
Parametri di query: since_id=<event_id> (since è l’alias più vecchio; since_id prevale quando vengono inviati entrambi), types=story.created,story.transitioned,comment.added,…, limit= (default 100, ≤ 500), cursor=. La risposta è { items, next_since_id, next_cursor }: memorizza next_since_id e restituiscilo come since_id per riprendere; next_cursor è null sull’ultima pagina.
Notifiche
Sezione intitolata “Notifiche”Il feed unificato delle notifiche in-app: righe di notifica di prima classe (richieste di review, attività delle storie, inviti, …) unite alla casella delle @-menzioni in un unico flusso, dal più recente. Gli id del feed hanno un prefisso di origine (nt-… / sc-… / ec-…). Le sessioni membro e le chiavi ea_user_* leggono le proprie righe lato membro; le chiavi ea_agent_* le righe lato agente.
| Method | Path | Description |
|---|---|---|
| GET | /me/notifications | Il tuo feed di notifiche. Filtri: unread=true, since_id=, kind= (mentions / reviews / stories / invitations); pagina con cursor= / limit= |
| GET | /me/notifications/unread-count | Totali non letti — { unread_count, by_category: { mentions, reviews, stories, invitations } } |
| POST | /me/notifications/read-all | Segna tutto come letto; restituisce i contatori aggiornati |
| POST | /me/notifications/{id}/ack | Segna un elemento come letto (idempotente) |
| POST | /me/notifications/{id}/accept | Accetta un invito a un progetto / organizzazione dal feed (solo token membro) |
| POST | /me/notifications/{id}/decline | Rifiuta un invito a un progetto / organizzazione (solo token membro) |
| GET | /me/notifications/resolve-invite?token=… | Risolvi un token di invito ricevuto via email nell’id della tua notifica — { "id": "nt-…" } oppure { "id": null } |
| GET | /me/notifications/stream | Push live — Server-Sent Events (text/event-stream); vedi sotto |
L’endpoint di stream non è un endpoint JSON e quindi non è nella specifica OpenAPI: tiene la connessione aperta ed emette un frame senza payload ({"type":"notification","kind":…}) ogni volta che arriva qualcosa di nuovo, segnalando al client di ricaricare il feed. Le connessioni hanno un tetto lato server di 45 minuti — riconnettiti e ri-autenticati. Solo sessioni membro e chiavi ea_user_*; le chiavi ea_agent_* ricevono 403.
Importazione (manager)
Sezione intitolata “Importazione (manager)”| Method | Path | Description |
|---|---|---|
| POST | /projects/{id}/import | Sorgenti da file: source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json, eat. Multipart file=. Sincrono — risponde con i conteggi del risultato. |
| POST | /projects/{id}/import/json | Body JSON; source=github non richiede file — owner, repo, token opzionale, e i flag opt-in include_pull_requests / include_milestones / include_releases / include_dependencies, e include_comments (predefinito true); le sorgenti da file inviano file_base64. Asincrono: restituisce 202 { import_id, status }. Il server recupera tramite l’API GraphQL di GitHub, che rifiuta i chiamanti anonimi, quindi a GitHub arriva sempre un token — il tuo, o quello condiviso del deployment. Vedi la Guida. |
| GET | /projects/{id}/imports/{import_id} | Interroga un job: status percorre pending → fetching → writing → done | failed, con progress_current / progress_total durante il recupero e i conteggi del risultato su done |
Per ogni progetto gira una sola importazione JSON alla volta; un secondo POST …/import/json mentre una è in corso dà 409 import_already_running. Con check_unpointed_estimates: true (sorgenti file; ignorato per github), un file con stime di bug o chore che il progetto non valuta a punti viene rifiutato con 409 import_unpointed_estimates e details.count prima che parta qualsiasi job; senza il flag l’importazione scarta quelle stime e riporta { code: "estimates_unpointed_dropped", count } nei warnings del risultato. dry_run: true (body JSON oppure dry_run=true multipart) fa l’anteprima di qualsiasi sorgente: analizza, risolve, deduplica, restituisce gli stessi conteggi { imported, skipped, errors, unmatched }, poi annulla tutto — non viene scritto nulla. Limiti: un file di 10 MiB (400 import_too_large) e 5.000 storie per importazione per le sorgenti a file (400 import_too_many_records); non viene scritto nulla. Un request body oltre i 16 MiB viene rifiutato prima con 413 request_too_large. La sorgente GitHub non ha tetto — scrive a blocchi anziché in un’unica transazione. La reimportazione è idempotente per id di origine — le righe già importate vengono saltate, non duplicate.
Esportazione
Sezione intitolata “Esportazione”| Method | Path | Description |
|---|---|---|
| GET | /projects/{id}/export/formats | Formati registrati: { id, name, content_type, drops, includes_archived }. Qualsiasi ruolo di progetto. |
| GET | /projects/{id}/export/{format} | Scarica uno (manager). Interscambio: eat (piena fedeltà), jira, pivotal, shortcut, trello, asana, gitlab, linear, plane, plane_json; documenti: pdf, docx. |
| GET | /projects/{id}/export/attachments | Ogni allegato come un unico zip navigabile (i file conservano i nomi originali; manifest JSON + CSV) (manager). |
Le esportazioni di documenti (pdf, docx) accettano parametri di query aggiuntivi: page_size= (letter default / a4 / legal / folio), from= / to= (estremi della finestra di storie — RFC 3339 oppure semplice YYYY-MM-DD; una storia è nell’intervallo quando il suo created o completed_at vi cade dentro), include_icebox= / include_backlog= (entrambi false per default, così un’esportazione condivisibile mostra solo il lavoro pianificato / in corso). I formati CSV di interscambio li ignorano.
Backup e ripristini (manager)
Sezione intitolata “Backup e ripristini (manager)”| Method | Path | Description |
|---|---|---|
| GET / POST | /projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/health | Elenca gli snapshot, creane uno subito, leggine uno, e il riepilogo dello stato di ritenzione |
| POST | /projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id} | Ripristina uno snapshot intero, o tabelle selezionate da uno, e interroga il ripristino |
Questi POST stanno sul livello di limitazione di frequenza sensitive (più sotto).
MCP e provider OAuth
Sezione intitolata “MCP e provider OAuth”East Agile Tracker è un provider OAuth 2.1 per i client MCP. Un client lo scopre su /.well-known/oauth-authorization-server e /.well-known/oauth-protected-resource/mcp, ti manda su /oauth/authorize (la pagina di consenso), scambia il codice su /oauth/token, e poi parla MCP su /mcp con il token ea_mcp_* ottenuto. Le autorizzazioni si elencano e si revocano su /me/oauth_grants. Gli endpoint del provider hanno un proprio livello di limitazione di frequenza.
Idempotenza
Sezione intitolata “Idempotenza”Gli endpoint di scrittura (POST, PUT, DELETE) accettano un header Idempotency-Key. Stessa chiave + stesso body riproduce la risposta in cache (finestra di 24 ore); stessa chiave + un body diverso restituisce 409 idempotency_conflict. La chiave ha come ambito la credenziale che l’ha inviata. Non applicata a GET/HEAD/OPTIONS, /openapi.json e /docs, /api/auth/*, /mcp, qualsiasi path che contiene /attachments o qualsiasi richiesta multipart/*; una richiesta senza credenziale non viene mai messa in cache. Le risposte che si sono fermate prima di una risposta di dominio non vengono mai messe in cache — 401, 403, 404, 429 e ogni 5xx — così un retry dopo una qualsiasi di esse raggiunge l’handler; 400, 409, 412 e 422 sono la risposta del dominio e vengono riprodotte come un successo.
Paginazione
Sezione intitolata “Paginazione”Gli endpoint di elenco accettano cursor=<opaque> e limit=<n>. Quando impostato, la risposta è { "items": [...], "next_cursor": "<str|null>" }; ripassa next_cursor per paginare. Il tetto di limit è per endpoint: 200 su storie, commenti e progetti; 500 sugli eventi; 1000 sull’audit log. La ricerca pagina con limit (≤ 1000) e offset invece di un cursore e restituisce { results, total, limit, offset }.
Un elenco semplice (senza cursor/limit) che ha dovuto troncare la risposta lo dichiara negli header — X-Tracker-Pagination-Truncated, X-Tracker-Pagination-Limit, X-Tracker-Pagination-Offset e X-Tracker-Pagination-Next-Offset; restituisci l’ultimo come offset= per la pagina successiva. Non esiste un header con il conteggio totale.
Proiezione dei campi
Sezione intitolata “Proiezione dei campi”Gli elenchi di storie, commenti e progetti accettano fields= (separati da virgola) per restituire solo campi specifici. L’id della risorsa è sempre incluso (story_id, story_comment_id e comment_id, project_id); un nome di campo sconosciuto restituisce 400 validation_failed con i nomi offendenti in details.fields.
GET /projects/123/stories?fields=story_id,name,current_state,ownersFormato degli errori
Sezione intitolata “Formato degli errori”Ogni errore JSON ha code ed error; alcuni aggiungono details:
{ "code": "invalid_transition", "error": "Cannot move story from `unstarted` to `accepted`", "details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }| Status | code | When |
|---|---|---|
| 400 | invalid_parameter | input errato; messaggio in error. La validazione dei campi (vuoto/lunghezza/null-byte/email) aggiunge details.fields e details.constraint; solo un semplice errore di richiesta non valida omette details |
| 400 | validation_failed | errore di input strutturato; details.fields è un array di nomi di campo offendenti |
| 400 | codici di dominio | un rifiuto specifico della route con un proprio codice e senza details — ad es. unsupported_export_format, import_too_large, import_unknown_source |
| 401 | unauthenticated | token mancante/non valido |
| 403 | unauthorized_operation | autenticato ma con ruolo insufficiente |
| 404 | unfound_resource | non trovato — restituito anche ai non-membri |
| 409 | conflict | conflitto di risorsa (es. duplicato) |
| 409 | idempotency_conflict | Idempotency-Key riutilizzato con un body diverso |
| 409 | stale_write · import_already_running · import_unpointed_estimates | la descrizione è cambiata dopo il tuo expected_version (oppure expected_updated_at non corrisponde più) · un’importazione è già in corso · il file contiene stime di bug o chore che il progetto non valuta a punti (details.count) |
| 412 | precondition_failed | If-Match non corrispondeva all’ETag attuale della risorsa; details porta expected e current |
| 413 | request_too_large | il body supera il limite di dimensione della route |
| 422 | invalid_transition | movimento di stato illegale; details porta { from, to, allowed } |
| 429 | rate_limited | troppe richieste da questo IP su una route a frequenza limitata; header Retry-After |
| 500 | internal_error | guasto del server — messaggio generico; sicuro da riprovare |
| 502 | upstream_error | un servizio da cui dipende la route (ad es. GitHub) ha fallito |
| 503 | not_configured | al deployment manca l’integrazione richiesta da questa route (SMS, object storage, …) |
details.fields è un array JSON di nomi di campo (es. ["to"]), a volte con chiavi extra come max. Non esiste una mappa campo→messaggio.
{ "code": "validation_failed", "error": "unknown field(s): foo", "details": { "fields": ["foo"] } }Limiti di frequenza
Sezione intitolata “Limiti di frequenza”Per IP client, su una manciata di route; il restante traffico API autenticato non è a frequenza limitata. Default (ogni coppia è la frequenza sostenuta e il burst, regolabili dall’operatore):
- 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/feedbacke/api/v1/feedback/with-screenshot: tre livelli sovrapposti — un invio ogni 15 s, 10 all’ora, 36 al giorno. - Avatars — il redirect non autenticato degli avatar: 20 req/s, burst 200.
- Sensitive — i
POSTdi backup e ripristino: ~0.002 req/s, burst 5.
Un limite superato restituisce 429 con un header Retry-After e l’envelope di errore JSON standard, code: "rate_limited".