Salta ai contenuti

Specifica API

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

L’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.

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:

LevelWho passesTypical operations
public viewerchiunque, su un progetto la cui visibilità è pubblicaletture della board: storie, iterazioni, ricerca, attività di storie ed epic (con i dettagli dell’attore oscurati)
viewerviewer, member, managerletture (elenco/get di storie, ricerca, metriche, elenco dei formati di export)
membermember, managertutte le scritture di work-item (storie, task, commenti, …), lo stream di eventi
managersolo managerimpostazioni 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.

MethodPathDescription
GET/openapi.jsonLa spec OpenAPI 3 live, request body inclusi. Non autenticato.
GET/docsSwagger UI. Non autenticato.
GET/metaIdentità 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/configLiveness, e la configurazione pubblica del deployment (modalità organizzazione singola, funzionalità opzionali attive, nome dell’istanza). Non autenticati, fuori da /v1.

Endpoint di sessione, non autenticati salvo diversa indicazione. Li pilota la SPA; gli script di norma usano invece una chiave API.

MethodPathDescription
POST/auth/registerRegistra un nuovo account — protetto da reCAPTCHA; l’account supera poi la verifica SMS
POST/auth/sms/challenge · /auth/sms/status · /auth/sms/bypassInvia / controlla il codice SMS di registrazione (il bypass è riservato all’operatore)
GET/auth/configQuali metodi di accesso offre il deployment
POST/auth/loginAccedi con email + password; restituisce un JWT di sessione, oppure una sfida TOTP
POST/auth/login/totpCompleta un accesso con un codice dell’app authenticator o un codice di recupero
POST/auth/passkey/login/start · /auth/passkey/login/finishAccesso WebAuthn senza password
GET/auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchangeAccesso OAuth con GitHub o Google
POST/auth/refresh · /auth/refresh/revokeRuota il refresh token / revocalo
POST/auth/logoutEsci (autenticato; revoca il refresh token di questa sessione)
POST/auth/forgot-password · /auth/reset-passwordRichiedi un’email di reimpostazione / usa il token di reset
POST/auth/accept-invite/lookup · /auth/accept-inviteRisolvi 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/confirmCollega un account GitHub o Google a uno esistente, oppure unisci due account
POST/auth/email_addresses/primary/preview · …/primary/confirmCompleta un cambio dell’email principale dal link di conferma ricevuto via email

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.

MethodPathDescription
GET/meProfilo dell’utente corrente
PUT/meAggiorna il profilo
DELETE/meElimina l’account — rifiutato finché sei l’unico owner di un’organizzazione o di un progetto con altri membri
GET/me/deletion-impactCosa rimuoverebbe l’eliminazione dell’account e cosa la blocca
PUT/me/passwordCambia password
PUT/me/settingsAggiorna le impostazioni (tema, preferenze di notifica)
POST / DELETE/me/avatarCarica (multipart) / rimuovi il tuo avatar
POST/me/api-token/regenerateDisconnetti 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/primaryI 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}/linkAccount 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/disableRegistrazione 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/activityLa tua attività in tutti i progetti
GET/me/storiesLe 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}/ackLa casella delle @-menzioni (unacked=true per filtrare) e la conferma di lettura — confluisce anche nel feed di notifiche più sotto
GET/me/data-exportAuto-esportazione GDPR dei tuoi dati
GET/me/consent · POST /me/consentLeggi / registra il consenso ({ consent_type, granted })
GET/legal/pending · POST /legal/acceptDocumenti clickwrap in sospeso / registra l’accettazione
GET / PUT/agent/meL’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-screenshotContatto + feedback in-app; a frequenza limitata per IP

Lookup di seed usati quando si creano/stimano storie. ID stabili.

MethodPathDescription
GET/story_typesfeature, bug, chore, release (+ allow_points)
GET/story_statesunstarted … accepted, rejected
GET/effort_scalesscale di stima disponibili
GET/effort_scales/{scale_id}/valuesi valori di punti in una scala
GET/priority_scales · /priority_scales/{scale_id}/valuesle scale di priorità e i loro valori (il priority_id di una storia si risolve qui)

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.

MethodPathDescription
GET / POST/organizationsElenca 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-removeCambia 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-ownershipPassa il ruolo owner a un altro membro
GET/organization-invitations/{token} · POST …/{token}/acceptRisolvi / accetta un invito all’organizzazione ricevuto via email
GET/organizations/{oid}/export · POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/downloadExport dell’organizzazione riservato all’owner: uno zip con un dump SQL e ogni allegato, eseguito come job
MethodPathDescription
GET/projectsElenca i tuoi progetti (limit ≤ 200)
POST/projectsCrea 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}/pinFissa / sblocca il progetto nel tuo elenco progetti
POST/projects/{id}/transfer-organizationSposta 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/testInvia un messaggio di prova al feed Slack del progetto (manager)
GET / POST/projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seedProgetti vetrina pubblici: verifica se puoi rivendicarne uno, rivendicalo, popolalo (il popolamento è riservato agli admin del prodotto; chiunque altro riceve 404)
GET/projects/{id}/audit-logLettura 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}/eventsStream 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.

MethodPathDescription
GET/projects/{id}/membershipsElenca i membri (viewer)
POST/projects/{id}/membershipsInvita 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-removeCambia il ruolo di molti membri in una volta, o rimuovili (manager)
GET/projects/{id}/addable-members · POST /projects/{id}/members/add-existingMembri dell’organizzazione non ancora nel progetto / aggiungine uno senza invito via email — (manager) e owner o admin dell’organizzazione
POST/projects/{id}/members/joinUn 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_keysElenca (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/onboardingIl 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}/avatarRuota 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).

MethodPathDescription
GET/projects/{id}/storiesElenca le storie (paginato, filtrabile) (viewer)
POST/projects/{id}/storiesCrea 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}/transitionsCambia stato con validazione
POST/projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restartRifiuta una storia delivered / riporta una storia rifiutata a started (rejected è terminale per /transitions)
POST/projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchiveArchivia / rimuovi dall’archivio una storia
POST/projects/{id}/stories/bulk-unarchiveRimuovi dall’archivio molte storie
POST/projects/{id}/stories/bulk_transitionFai transitare molte storie (1–100) in una volta
POST/projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-moveArchivia, elimina, duplica o sposta (su un pannello / in una posizione) molte storie
POST/projects/{id}/stories/{sid}/duplicateDuplica una storia
POST / DELETE/projects/{id}/stories/{sid}/epics · …/epics/{eid}L’appartenenza della storia agli epic
GET/short-links/{code} · /story-referencesRisolvi 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 } ] }.

Tutte member. List/GET sulla maggior parte è (viewer). Eliminare un allegato o un link allegato richiede chi lo ha caricato oppure (manager).

MethodPathBody / 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.

MethodPathDescription
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-attachmentsAllegati, 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.

MethodPathDescription
GET / POST/projects/{id}/labelsElenca / crea una label
GET / PUT / DELETE/projects/{id}/labels/{lid}Leggi / aggiorna / elimina una label
POST/projects/{id}/labels/{lid}/archiveArchivia (nascondi in modo soft) una label

Le letture sono aperte a qualsiasi ruolo di progetto, e anonime su un progetto pubblico.

MethodPathDescription
GET/projects/{id}/iterationsElenca 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-previewLa 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}/iterationsCrea un’iterazione manuale (manager)
DELETE/projects/{id}/iterations/{itid}Elimina un’iterazione (manager)
PUT/projects/{id}/iterations/{itid}/velocitySovrascrivi la velocity di una singola iterazione senza cambiare la strategia del progetto (manager)
GET/projects/{id}/iterations/{itid}/done-storiesLe storie accettate di un’iterazione chiusa, paginate
MethodPathDescription
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/groupingI gruppi di iterazioni proiettati dal Backlog (viewer)
GET / PUT/projects/{id}/preferencesLe tue preferenze di board per questo progetto — qualsiasi ruolo di progetto, solo la tua riga
MethodPathDescription
GET/projects/{id}/eventsStream 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.

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.

MethodPathDescription
GET/me/notificationsIl tuo feed di notifiche. Filtri: unread=true, since_id=, kind= (mentions / reviews / stories / invitations); pagina con cursor= / limit=
GET/me/notifications/unread-countTotali non letti — { unread_count, by_category: { mentions, reviews, stories, invitations } }
POST/me/notifications/read-allSegna tutto come letto; restituisce i contatori aggiornati
POST/me/notifications/{id}/ackSegna un elemento come letto (idempotente)
POST/me/notifications/{id}/acceptAccetta un invito a un progetto / organizzazione dal feed (solo token membro)
POST/me/notifications/{id}/declineRifiuta 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/streamPush 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.

MethodPathDescription
POST/projects/{id}/importSorgenti 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/jsonBody 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.

MethodPathDescription
GET/projects/{id}/export/formatsFormati 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/attachmentsOgni 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.

MethodPathDescription
GET / POST/projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/healthElenca 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).

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.

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.

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.

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,owners

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"] } }
StatuscodeWhen
400invalid_parameterinput 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
400validation_failederrore di input strutturato; details.fields è un array di nomi di campo offendenti
400codici di dominioun rifiuto specifico della route con un proprio codice e senza details — ad es. unsupported_export_format, import_too_large, import_unknown_source
401unauthenticatedtoken mancante/non valido
403unauthorized_operationautenticato ma con ruolo insufficiente
404unfound_resourcenon trovato — restituito anche ai non-membri
409conflictconflitto di risorsa (es. duplicato)
409idempotency_conflictIdempotency-Key riutilizzato con un body diverso
409stale_write · import_already_running · import_unpointed_estimatesla 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)
412precondition_failedIf-Match non corrispondeva all’ETag attuale della risorsa; details porta expected e current
413request_too_largeil body supera il limite di dimensione della route
422invalid_transitionmovimento di stato illegale; details porta { from, to, allowed }
429rate_limitedtroppe richieste da questo IP su una route a frequenza limitata; header Retry-After
500internal_errorguasto del server — messaggio generico; sicuro da riprovare
502upstream_errorun servizio da cui dipende la route (ad es. GitHub) ha fallito
503not_configuredal 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"] } }

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/feedback e /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 POST di 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".