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 owner sono contrassegnate (owner); tutto il resto richiede solo l’appartenenza al progetto (o, per le letture contrassegnate (viewer), qualsiasi livello di accesso).
https://eastagiletracker.com/api/v1https://api.eastagiletracker.com/api/v1 serve l’API identica. Tutte le richieste e le risposte sono JSON, eccetto alcuni endpoint di upload file che accettano multipart.
Autenticazione
Sezione intitolata “Autenticazione”Ogni richiesta autenticata invia una chiave API tramite uno di:
X-TrackerToken: <key>Authorization: Bearer <key>
Le chiavi utente iniziano con ea_user_. Le chiavi agente iniziano con ea_agent_. Vedi Guida API → Due tipi di chiavi.
Endpoint non autenticati: /openapi.json, /docs, gli endpoint /auth/* e i lookup dei dati di riferimento (/story_types, /story_states, /effort_scales, …). /meta è autenticato — funziona qualsiasi chiave valida, ma non ha ambito di progetto (raggiungibile anche da una chiave agente vincolata a un progetto).
Tre livelli regolano gli endpoint con ambito di progetto:
| Livello | Chi passa | Operazioni tipiche |
|---|---|---|
| viewer | viewer, member, owner | letture (elenco/get di storie, ricerca, analisi) |
| member | member, owner | tutte le scritture di work-item (storie, task, commenti, …) |
| owner | solo owner | impostazioni progetto, gestione appartenenze, chiavi agente, eliminazione, importazione, audit log |
Un non-membro riceve 404 unfound_resource (non 403) sui path di progetto, così gli ID dei progetti non sono enumerabili.
Endpoint auto-descrittivi
Sezione intitolata “Endpoint auto-descrittivi”| Metodo | Path | Descrizione |
|---|---|---|
| GET | /openapi.json | La spec OpenAPI 3 live. 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. |
Account / identità
Sezione intitolata “Account / identità”Queste agiscono sul chiamante e richiedono solo una chiave valida (nessun ruolo di progetto).
| Metodo | Path | Descrizione |
|---|---|---|
| POST | /auth/register | Registra un nuovo account |
| POST | /auth/login | Accedi, restituisce un token di sessione |
| POST | /auth/logout | Esci |
| POST | /auth/forgot-password | Richiedi un’email di reimpostazione password |
| POST | /auth/reset-password | Usa un token di reset per impostare una nuova password |
| GET | /auth/verify-email | Verifica un indirizzo email |
| POST | /auth/accept-invite/lookup | Risolvi un token di invito → email (non autenticato) |
| POST | /auth/accept-invite | Accetta un invito a un progetto (dopo l’autenticazione) |
| GET | /me | Profilo dell’utente corrente |
| PUT | /me | Aggiorna il profilo |
| DELETE | /me | Elimina l’account |
| PUT | /me/password | Cambia password |
| PUT | /me/settings | Aggiorna le impostazioni (tema, preferenze di notifica) |
| POST | /me/avatar | Carica l’avatar (multipart) |
| POST | /me/api-token/regenerate | Ruota il tuo token API — invalida sessioni/chiavi esistenti |
| GET | /me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id} | Gestisci le chiavi API utente (ea_user_) |
| GET | /me/activity | La tua attività in tutti i progetti |
| 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 |
| POST | /contact · POST /feedback · POST /feedback/with-screenshot | Contatto + feedback in-app |
Dati di riferimento (non autenticati)
Sezione intitolata “Dati di riferimento (non autenticati)”Lookup di seed usati quando si creano/stimano storie. ID stabili.
| Metodo | Path | Descrizione |
|---|---|---|
| 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 |
Progetti
Sezione intitolata “Progetti”| Metodo | Path | Descrizione |
|---|---|---|
| GET | /projects | Elenca i tuoi progetti |
| POST | /projects | Crea un progetto |
| GET | /projects/{id} | Ottieni i dettagli del progetto (viewer) |
| PUT | /projects/{id} | Aggiorna le impostazioni del progetto (owner) |
| DELETE | /projects/{id} | Elimina un progetto (owner) |
| GET | /projects/{id}/audit-log | Stream delle attività del progetto (owner) |
| GET | /projects/{id}/events | Stream di eventi paginato a cursore (viewer) — vedi Events |
Membri e chiavi agente
Sezione intitolata “Membri e chiavi agente”| Metodo | Path | Descrizione |
|---|---|---|
| GET | /projects/{id}/memberships | Elenca i membri (viewer) |
| POST | /projects/{id}/memberships | Invita un membro via email (owner) |
| PUT | /projects/{id}/memberships/{mid} | Aggiorna il ruolo (owner) |
| DELETE | /projects/{id}/memberships/{mid} | Rimuovi un membro (owner) |
| GET / POST | /projects/{id}/agent_keys | Elenca / genera chiavi agente (owner) |
| DELETE | /projects/{id}/agent_keys/{kid} | Revoca una chiave agente (owner) |
Tutte le scritture sulle storie richiedono il ruolo member.
| Metodo | Path | Descrizione |
|---|---|---|
| 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/bulk_transition | Fai transitare molte storie (1–100) in una volta |
| POST | /projects/{id}/stories/bulk-delete | Elimina molte storie |
| POST | /projects/{id}/stories/bulk-duplicate | Duplica molte storie |
| POST | /projects/{id}/stories/{sid}/duplicate | Duplica una storia |
Create (POST …/stories): { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. 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) e "force_state_change" (bool).
Transition (POST …/transitions): { "to": "<state>", "reason"? }. 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>", "reason"? }. 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).
| Metodo | Path | Body / note |
|---|---|---|
| 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) } or { comment_emoji } |
| GET / POST | /projects/{id}/stories/{sid}/blockers · PUT/DELETE …/blockers/{bid} | { blocker_desc, resolved? } |
| GET / POST | /projects/{id}/stories/{sid}/links · DELETE …/links/{lid} | { url, link_type?, title? } |
| GET / POST | /projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid} | { reviewer_id? / reviewer_agent_id?, status, comment? } |
| GET / POST | /projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid} | { member_id? / agent_id? } — 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} | { name } |
| GET / POST | /projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid} | upload multipart (≤ 2 GB ciascuno); l’elenco è (viewer) |
member per le scritture, (viewer) per le letture.
| Metodo | Path | Descrizione |
|---|---|---|
| GET / POST | /projects/{id}/labels | Elenca / crea una label |
| PUT / DELETE | /projects/{id}/labels/{lid} | Aggiorna / elimina una label |
| POST | /projects/{id}/labels/{lid}/archive | Archivia (nascondi in modo soft) una label |
Iterazioni
Sezione intitolata “Iterazioni”| Metodo | Path | Descrizione |
|---|---|---|
| GET | /projects/{id}/iterations | Elenca le iterazioni (member) |
| POST | /projects/{id}/iterations | Crea un’iterazione manuale (owner) |
| DELETE | /projects/{id}/iterations/{itid} | Elimina un’iterazione (owner) |
Ricerca, analisi, metriche, preferenze
Sezione intitolata “Ricerca, analisi, metriche, preferenze”| Metodo | Path | Descrizione |
|---|---|---|
| GET | /projects/{id}/search?query=… | Ricerca con sintassi di filtri (viewer) — vedi Guida |
| GET | /projects/{id}/analytics/{overview,iteration,releases,activity,cycle-time,projections} | Analisi (viewer). L’approfondimento per iterazione accetta ?iteration_id= |
| GET | /projects/{id}/metrics/{velocity,burndown,story-types} | Metriche (viewer) |
| GET / PUT | /projects/{id}/preferences | Le tue preferenze di board per questo progetto (member) |
| Metodo | Path | Descrizione |
|---|---|---|
| GET | /projects/{id}/events | Stream di eventi paginato a cursore (viewer) |
Parametri di query: since=<event_id>, types=story.created,story.transitioned,comment.created,…, limit=, cursor=. La risposta include next_cursor. Passa l’ultimo event_id che hai visto come since per riprendere.
Importazione (owner)
Sezione intitolata “Importazione (owner)”| Metodo | Path | Descrizione |
|---|---|---|
| POST | /projects/{id}/import (+ /json) | Upload multipart. source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json. |
WebSocket
Sezione intitolata “WebSocket”wss://eastagiletracker.com/ws/control?token=<key>Per il controllo remoto interattivo dell’interfaccia ({ "action": "get_state", "id": "req-1" }). Non è un canale dati — tutte le letture/scritture passano per REST. Solo istanza singola; non distribuito tra le repliche.
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. Non applicato a GET/HEAD/OPTIONS, ai path /auth/* o /attachments. Le risposte 5xx non sono mai in cache — un retry raggiunge l’handler.
Paginazione
Sezione intitolata “Paginazione”Gli endpoint di elenco accettano cursor=<opaque> e limit=<n≤200>. Quando impostato, la risposta è { "items": [...], "next_cursor": "<str|null>" }; ripassa next_cursor per paginare. Alcuni elenchi restituiscono anche un header X-Tracker-Pagination-Total.
Proiezione dei campi
Sezione intitolata “Proiezione dei campi”Gli endpoint di elenco accettano fields= (separati da virgola) per restituire solo campi specifici. story_id è sempre incluso; 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 | Quando |
|---|---|---|
| 400 | invalid_parameter | input errato; messaggio in error, nessun details (la maggior parte delle validazioni: vuoto/lunghezza/null-byte/email) |
| 400 | validation_failed | errore di input strutturato; details.fields è un array di nomi di campo offendenti |
| 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 |
| 422 | invalid_transition | movimento di stato illegale; details porta { from, to, allowed } |
| 500 | internal_error | guasto del server — messaggio generico; sicuro da riprovare |
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 chiave (per IP per gli endpoint non autenticati), token bucket GCRA:
- Auth —
/auth/*: 0.5 req/s, burst 20. - Public —
/contact,/feedback: 0.2 req/s, burst 10. - Sensitive — reimpostazione password: ~0.002 req/s, burst 5.
Un limite superato restituisce 429 Too Many Requests con un header Retry-After e un body in testo semplice (non l’envelope di errore JSON).