Salta ai contenuti

Specifica API

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

https://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.

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:

LivelloChi passaOperazioni tipiche
viewerviewer, member, ownerletture (elenco/get di storie, ricerca, analisi)
membermember, ownertutte le scritture di work-item (storie, task, commenti, …)
ownersolo ownerimpostazioni 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.

MetodoPathDescrizione
GET/openapi.jsonLa spec OpenAPI 3 live. 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.

Queste agiscono sul chiamante e richiedono solo una chiave valida (nessun ruolo di progetto).

MetodoPathDescrizione
POST/auth/registerRegistra un nuovo account
POST/auth/loginAccedi, restituisce un token di sessione
POST/auth/logoutEsci
POST/auth/forgot-passwordRichiedi un’email di reimpostazione password
POST/auth/reset-passwordUsa un token di reset per impostare una nuova password
GET/auth/verify-emailVerifica un indirizzo email
POST/auth/accept-invite/lookupRisolvi un token di invito → email (non autenticato)
POST/auth/accept-inviteAccetta un invito a un progetto (dopo l’autenticazione)
GET/meProfilo dell’utente corrente
PUT/meAggiorna il profilo
DELETE/meElimina l’account
PUT/me/passwordCambia password
PUT/me/settingsAggiorna le impostazioni (tema, preferenze di notifica)
POST/me/avatarCarica l’avatar (multipart)
POST/me/api-token/regenerateRuota 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/activityLa tua attività in tutti i progetti
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
POST/contact · POST /feedback · POST /feedback/with-screenshotContatto + feedback in-app

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

MetodoPathDescrizione
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
MetodoPathDescrizione
GET/projectsElenca i tuoi progetti
POST/projectsCrea 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-logStream delle attività del progetto (owner)
GET/projects/{id}/eventsStream di eventi paginato a cursore (viewer) — vedi Events
MetodoPathDescrizione
GET/projects/{id}/membershipsElenca i membri (viewer)
POST/projects/{id}/membershipsInvita 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_keysElenca / genera chiavi agente (owner)
DELETE/projects/{id}/agent_keys/{kid}Revoca una chiave agente (owner)

Tutte le scritture sulle storie richiedono il ruolo member.

MetodoPathDescrizione
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/bulk_transitionFai transitare molte storie (1–100) in una volta
POST/projects/{id}/stories/bulk-deleteElimina molte storie
POST/projects/{id}/stories/bulk-duplicateDuplica molte storie
POST/projects/{id}/stories/{sid}/duplicateDuplica 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 } ] }.

Tutte member. List/GET sulla maggior parte è (viewer).

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

MetodoPathDescrizione
GET / POST/projects/{id}/labelsElenca / crea una label
PUT / DELETE/projects/{id}/labels/{lid}Aggiorna / elimina una label
POST/projects/{id}/labels/{lid}/archiveArchivia (nascondi in modo soft) una label
MetodoPathDescrizione
GET/projects/{id}/iterationsElenca le iterazioni (member)
POST/projects/{id}/iterationsCrea un’iterazione manuale (owner)
DELETE/projects/{id}/iterations/{itid}Elimina un’iterazione (owner)
MetodoPathDescrizione
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}/preferencesLe tue preferenze di board per questo progetto (member)
MetodoPathDescrizione
GET/projects/{id}/eventsStream 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.

MetodoPathDescrizione
POST/projects/{id}/import (+ /json)Upload multipart. source=pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json.
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.

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.

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.

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,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"] } }
StatuscodeQuando
400invalid_parameterinput errato; messaggio in error, nessun details (la maggior parte delle validazioni: vuoto/lunghezza/null-byte/email)
400validation_failederrore di input strutturato; details.fields è un array di nomi di campo offendenti
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
422invalid_transitionmovimento di stato illegale; details porta { from, to, allowed }
500internal_errorguasto 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"] } }

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).