Aller au contenu

Spécification de l'API

Référence complète des endpoints REST de l'API East Agile Tracker : authentification et rôles, projets, stories, epics, itérations, événements, import et export.

La référence complète des endpoints REST. Pour les tutoriels et les exemples, voir le Guide de l’API.

Tout ce qu’un membre de projet peut faire dans l’interface web est disponible ici — la SPA consomme cette même API. Les opérations nécessitant le rôle manager sont marquées (manager) ; tout le reste ne requiert que l’appartenance au projet (ou, pour les lectures marquées (viewer), n’importe quel niveau d’accès). Les tableaux ci-dessous nomment chaque groupe de routes monté par le serveur ; ceux résumés en une seule ligne sont entièrement décrits dans le openapi.json en direct.

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

L’API dispose de son propre hôte : eastagiletracker.com sert l’application web et répond 404 à /api/v1/…. Toutes les requêtes et réponses sont en JSON, à l’exception de quelques endpoints d’envoi de fichiers qui acceptent le multipart.

Deux groupes se trouvent un niveau plus haut, sous /api plutôt que /api/v1 : la surface d’authentification (/api/auth/*) et le formulaire de contact public (/api/contact). Leurs variantes /api/v1/… renvoient 404.

Chaque requête authentifiée envoie un identifiant via l’un des moyens suivants :

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

Les clés utilisateur commencent par ea_user_, les clés d’agent par ea_agent_, et les jetons d’accès MCP par ea_mcp_. Voir Guide de l’API → Trois types d’identifiants.

Endpoints non authentifiés : /openapi.json, /docs, les endpoints /api/auth/*, et les recherches de données de référence (/story_types, /story_states, /effort_scales, /priority_scales). /meta est authentifié — n’importe quelle clé valide fonctionne, mais il n’est pas restreint à un projet (une clé d’agent liée à un projet y accède également).

Quatre niveaux contrôlent l’accès aux endpoints restreints à un projet :

NiveauQui passeOpérations types
public viewern’importe qui, sur un projet dont la visibilité est publiquelectures du tableau : stories, itérations, recherche, activité des stories et des epics (détails de l’acteur caviardés)
viewerviewer, member, managerlectures (lister/obtenir des stories, recherche, métriques, liste des formats d’export)
membermember, managertoutes les écritures sur les éléments de travail (stories, tâches, commentaires, …), le flux d’événements
managermanager uniquementparamètres du projet, gestion des membres, clés d’agent, suppression, import, téléchargements d’export, sauvegardes, journal d’audit

Les agents détiennent les mêmes rôles que les membres — viewer, member ou manager — plafonnés au rôle du membre qui a émis la clé. Un non-membre reçoit 404 unfound_resource (et non 403) sur les chemins de projets privés, de sorte que les identifiants de projet ne sont pas énumérables.

MéthodeCheminDescription
GET/openapi.jsonLa spécification OpenAPI 3 en direct, corps de requête compris. Non authentifié.
GET/docsSwagger UI. Non authentifié.
GET/metaIdentité de l’appelant (auth.kind/key_id/agent_id/project_id) + le graphe de transitions par type de story. Authentifié (n’importe quelle clé valide ; non restreint à un projet). À appeler en premier.
GET/api/health · /api/configSonde de disponibilité, et la configuration publique du déploiement (mode mono-organisation, fonctionnalités optionnelles activées, nom de l’instance). Non authentifié, hors de /v1.

Endpoints de session, non authentifiés sauf mention contraire. La SPA les pilote ; les scripts utilisent normalement une clé d’API à la place.

MéthodeCheminDescription
POST/auth/registerEnregistrer un nouveau compte — protégé par reCAPTCHA ; le compte passe ensuite la vérification par SMS
POST/auth/sms/challenge · /auth/sms/status · /auth/sms/bypassEnvoyer / vérifier le code SMS d’inscription (le contournement est réservé à l’opérateur)
GET/auth/configLes méthodes de connexion proposées par le déploiement
POST/auth/loginSe connecter avec e-mail + mot de passe ; renvoie un JWT de session, ou une demande de code TOTP
POST/auth/login/totpTerminer une connexion avec un code d’application d’authentification ou un code de récupération
POST/auth/passkey/login/start · /auth/passkey/login/finishConnexion WebAuthn sans mot de passe
GET/auth/oauth/github/start · /auth/oauth/github/callback · /auth/oauth/google/start · /auth/oauth/google/callback · POST /auth/oauth/exchangeConnexion OAuth avec GitHub ou Google
POST/auth/refresh · /auth/refresh/revokeRenouveler le jeton de rafraîchissement / le révoquer
POST/auth/logoutSe déconnecter (authentifié ; révoque le jeton de rafraîchissement de cette session)
POST/auth/forgot-password · /auth/reset-passwordDemander un e-mail de réinitialisation / utiliser le jeton de réinitialisation
POST/auth/accept-invite/lookup · /auth/accept-inviteRésoudre un jeton d’invitation → e-mail / accepter l’invitation au projet (après authentification)
POST/auth/oauth/link/preview · …/link/confirm · /auth/oauth/merge/preview · …/merge/confirmAssocier un compte GitHub ou Google à un compte existant, ou fusionner deux comptes
POST/auth/email_addresses/primary/preview · …/primary/confirmFinaliser un changement d’e-mail principal depuis le lien de confirmation reçu par e-mail

Ces opérations agissent sur l’appelant et ne nécessitent aucun rôle de projet. Elles exigent une identité de membre — une clé d’agent reçoit 401 (les agents utilisent /agent/me). Les appels qui modifient des identifiants — mot de passe, TOTP, passkeys, suppression du compte, changement d’e-mail, régénération du jeton — exigent une session de navigateur ; une clé d’API reçoit 403.

MéthodeCheminDescription
GET/meProfil de l’utilisateur actuel
PUT/meMettre à jour le profil
DELETE/meSupprimer le compte — refusé tant que vous êtes l’unique propriétaire d’une organisation ou d’un projet comptant d’autres membres
GET/me/deletion-impactCe que la suppression du compte retirerait, et ce qui la bloque
PUT/me/passwordChanger le mot de passe
PUT/me/settingsMettre à jour les paramètres (thème, préférences de notification)
POST / DELETE/me/avatarTéléverser (multipart) / retirer votre avatar
POST/me/api-token/regenerateDéconnecter toutes les sessions et renvoyer un nouveau jeton de session ; les clés d’API ne sont pas affectées
GET / POST/me/email_addresses · GET …/email_addresses/offers · PUT …/email_addresses/primaryVos adresses e-mail ; adopter l’adresse d’un fournisseur connecté comme adresse secondaire ; demander un changement d’adresse principale (confirmé par e-mail)
GET/me/oauth_identities · DELETE …/oauth_identities/{provider} · POST …/oauth_identities/{provider}/linkComptes de connexion associés (GitHub, Google) : lister, déconnecter, lancer une association
GET/me/api_keys · POST /me/api_keys · DELETE /me/api_keys/{id}Gérer les clés d’API utilisateur (ea_user_)
GET/me/totp · POST /me/totp/setup · /me/totp/verify · /me/totp/disableActivation de la double authentification (TOTP) ; verify renvoie les codes de récupération une seule fois
GET/me/passkeys · POST /me/passkeys/register/start · /me/passkeys/register/finish · DELETE /me/passkeys/{credential_id}Enregistrement et suppression de passkeys
GET/me/oauth_grants · DELETE /me/oauth_grants/{grant_id}Applications connectées — les clients MCP et applications OAuth que vous avez autorisés
GET/me/activityVotre activité sur tous les projets
GET/me/storiesLes stories dont vous êtes propriétaire, demandeur ou abonné, dans tous les projets que le jeton peut atteindre — role=owned|requested|following, state=, cursor= / limit= (max 200)
GET/me/mentions · POST /me/mentions/{mention_id}/ackLa boîte de mentions @ (unacked=true pour filtrer) et l’accusé de lecture — également intégrée au flux de notifications ci-dessous
GET/me/data-exportAuto-export RGPD de vos données
GET/me/consent · POST /me/consentLire / enregistrer le consentement ({ consent_type, granted })
GET/legal/pending · POST /legal/acceptDocuments clickwrap en attente / enregistrer l’acceptation
GET / PUT/agent/meL’identité et le profil d’une clé d’agent, lisibles et modifiables par l’agent lui-même (l’équivalent côté agent de /me)
POST/api/contact · /api/v1/feedback · /api/v1/feedback/with-screenshotContact + retours dans l’application ; débit limité par IP

Recherches sur les données de référence utilisées lors de la création/estimation des stories. Identifiants stables.

MéthodeCheminDescription
GET/story_typesfeature, bug, chore, release (+ allow_points)
GET/story_statesunstarted … accepted, rejected
GET/effort_scaleséchelles d’estimation disponibles
GET/effort_scales/{scale_id}/valuesles valeurs de points d’une échelle
GET/priority_scales · /priority_scales/{scale_id}/valuesles échelles de priorité et leurs valeurs (le priority_id d’une story se résout ici)

Service hébergé uniquement — une installation auto-hébergée fonctionne en mode mono-organisation et ne monte pas ces routes (sauf la liste des organisations). Les rôles sont des rôles d’organisation : owner, admin, member.

MéthodeCheminDescription
GET / POST/organizationsLister vos organisations / en créer une
GET / PUT / DELETE/organizations/{oid}Lire, renommer (nom + slug ; owner ou admin), supprimer
GET / POST/organizations/{oid}/memberships · PUT / DELETE …/memberships/{member_id}Membres et invitations ; une invitation porte un plafond de rôle (jamais au-dessus de celui de l’appelant ; le rôle owner n’est jamais attribué par invitation)
POST/organizations/{oid}/memberships/bulk-role · …/memberships/bulk-removeChanger le rôle de 200 membres au plus en une fois, ou les retirer. Tout ou rien : un lot qui retirerait le dernier owner ou laisserait un projet sans propriétaire est refusé en entier ; avec reassign_confirmed, vous devenez propriétaire de ces projets à la place
DELETE/organizations/{oid}/invitations/{invitation_id}Révoquer une invitation en attente
POST/organizations/{oid}/transfer-ownershipCéder le rôle owner à un autre membre
GET/organization-invitations/{token} · POST …/{token}/acceptRésoudre / accepter une invitation d’organisation reçue par e-mail
GET/organizations/{oid}/export · POST …/export/jobs · GET …/export/jobs/{job_id} · …/export/jobs/{job_id}/downloadExport de l’organisation, réservé à l’owner : un zip contenant un dump SQL et toutes les pièces jointes, exécuté sous forme de tâche
MéthodeCheminDescription
GET/projectsLister vos projets (limit ≤ 200)
POST/projectsCréer un projet
GET/projects/{id}Obtenir les détails du projet (viewer)
PUT/projects/{id}Mettre à jour les paramètres du projet (manager)
DELETE/projects/{id}Supprimer un projet (manager)
POST / DELETE/projects/{id}/pinÉpingler / désépingler le projet dans votre liste de projets
POST/projects/{id}/transfer-organizationDéplacer le projet vers une autre organisation — l’appelant doit être Responsable du projet et owner ou admin de l’organisation cible
POST/projects/{id}/slack/testEnvoyer un message de test au flux Slack du projet (manager)
GET / POST/projects/{id}/showcase_claim_eligibility · /projects/{id}/showcase_claim · /projects/{id}/showcase_seedProjets vitrines publics : vérifier si vous pouvez en revendiquer un, le revendiquer, l’amorcer (l’amorçage est réservé aux administrateurs du produit ; tout autre appelant reçoit 404)
GET/projects/{id}/audit-logLecture de l’audit log — historique du projet plus activité par story / par epic via surface= ; l’accès varie selon le surface, voir ci-dessous
GET/projects/{id}/eventsFlux d’événements paginé par curseur (member) — voir Événements

Paramètres de requête de l’audit log : event_type= (un type ou liste séparée par des virgules), limit= (50 par défaut, plafonné à 1000), before= (curseur keyset <ISO-8601>|<audit_id> — transmettez le next_cursor de la page précédente), surface= (project_history, story_activities, epic_activities), target_id= (l’id de la story/epic — requis quand surface=story_activities ou epic_activities). Accès : le log non filtré est (manager) ; surface=project_history est (viewer), avec les e-mails des membres caviardés quand le projet les masque ; story_activities / epic_activities sont lisibles par tout membre du projet, et anonymement sur les projets publics avec les PII de l’acteur caviardées.

MéthodeCheminDescription
GET/projects/{id}/membershipsLister les membres (viewer)
POST/projects/{id}/membershipsInviter un membre par e-mail (manager)
PUT/projects/{id}/memberships/{mid}Mettre à jour le rôle (manager)
DELETE/projects/{id}/memberships/{mid}Retirer un membre (manager)
POST/projects/{id}/memberships/bulk-role · …/memberships/bulk-removeChanger le rôle de plusieurs membres à la fois, ou les retirer (manager)
GET/projects/{id}/addable-members · POST /projects/{id}/members/add-existingMembres de l’organisation pas encore sur le projet / en ajouter un sans invitation par e-mail — (manager) et owner ou admin d’organisation
POST/projects/{id}/members/joinUn owner ou admin d’organisation rejoint un projet de son organisation en tant que manager, ou s’y promeut lui-même manager (l’action Make me owner de la liste des projets)
GET / POST/projects/{id}/agent_keysLister (manager) / émettre des clés d’agent — les personnes dont le rôle figure dans la politique de création de clés du projet ; une clé d’agent ne peut pas en émettre
PUT / DELETE/projects/{id}/agent_keys/{kid}Modifier le nom, le rôle ou les indices de réponse d’une clé / la révoquer (manager)
GET/projects/{id}/agent_keys/onboardingLe kit de prise en main : prompts et fichiers de configuration pour les clients d’agent courants
GET/projects/{id}/agents · GET / PUT / DELETE /projects/{id}/agents/{aid}Les agents du projet et leurs profils (nom, initiales, description, couleur) ; DELETE révoque l’agent et toutes ses clés — un manager ou le créateur de l’agent
POST/projects/{id}/agents/{aid}/rotate-key · /projects/{id}/agents/{aid}/avatarRenouveler la clé d’un agent (identité et historique conservés) / téléverser son avatar

Toutes les écritures sur les stories nécessitent le rôle member. Créer une story avec des dates antidatées, une provenance d’import (import_source / import_external_id), ou des propriétaires ou un demandeur externes nécessite (manager).

MéthodeCheminDescription
GET/projects/{id}/storiesLister les stories (paginées, filtrables) (viewer)
POST/projects/{id}/storiesCréer une story
GET/projects/{id}/stories/{sid}Obtenir une story (viewer)
PUT/projects/{id}/stories/{sid}Mettre à jour une story
DELETE/projects/{id}/stories/{sid}Supprimer une story
POST/projects/{id}/stories/{sid}/transitionsChanger d’état avec validation
POST/projects/{id}/stories/{sid}/reject · /projects/{id}/stories/{sid}/restartRejeter une story livrée / remettre une story rejetée à started (rejected est terminal pour /transitions)
POST/projects/{id}/stories/{sid}/archive · /projects/{id}/stories/{sid}/unarchiveArchiver / désarchiver une story
POST/projects/{id}/stories/bulk-unarchiveDésarchiver plusieurs stories
POST/projects/{id}/stories/bulk_transitionFaire transiter plusieurs stories (1–100) à la fois
POST/projects/{id}/stories/bulk-archive · bulk-delete · bulk-duplicate · bulk-moveArchiver, supprimer, dupliquer ou déplacer (vers un panneau / une position) plusieurs stories
POST/projects/{id}/stories/{sid}/duplicateDupliquer une story
POST / DELETE/projects/{id}/stories/{sid}/epics · …/epics/{eid}L’appartenance de la story aux epics
GET/short-links/{code} · /story-referencesRésoudre un lien court /s/<code> vers sa story / résoudre jusqu’à 100 références — codes= (codes de liens courts séparés par des virgules) et ids= (project_id:story_id séparés par des virgules) — vers les stories que l’appelant peut lire

Paramètres de requête de la liste de stories : archived= (exclude par défaut / include / only — le filtre d’archivage à trois états ; remplace le déprécié include_archived=true, désormais alias de archived=include), include_done=true (admet les stories du panneau Done figées sur des itérations passées, exclues par défaut). La pagination (cursor= / limit= / offset=) et les ensembles de champs partiels (fields=) suivent les sections Pagination et Projection de champs.

Création (POST …/stories) : { "name" (required), "story_type": "feature|bug|chore|release", "description"?, "estimate"?, "current_state"?, "icebox"?, "labels"? }. estimate est le libellé de la valeur d’échelle, sous forme de chaîne ("3", "13") ; un nombre JSON est rejeté. labels accepte ["auth"] ou [{ "name": "auth" }] ; les labels inconnus sont créés. Valeurs par défaut : story_type=feature, current_state=unstarted.

Mise à jour (PUT …/stories/{sid}) : mêmes champs, tous optionnels, plus "position" (float), "force_state_change" (bool) et "expected_version" (entier, la version de la story — l’enregistrement d’une description est refusé avec 409 stale_write si la description a changé après cette version). L’ancien "expected_updated_at" (RFC 3339) est déprécié et fonctionne encore pendant une version : envoyé avec une description et sans expected_version, l’enregistrement est refusé avec 409 stale_write s’il ne correspond pas à l’updated_at de la story. Les écritures sur les stories respectent aussi If-Match par rapport à l’ETag de la story ; une non-correspondance donne 412 precondition_failed.

Transition (POST …/transitions) : { "to": "<state>" }. Le champ est to. Renvoie { story_id, state }. Déplacement illégal → 422 invalid_transition avec details: { from, to, allowed }.

Transition groupée (POST …/bulk_transition) : { "story_ids": [int,…] (1–100), "to": "<state>" }. Chaque story est évaluée indépendamment ; renvoie { results: [ { id, status: "ok" } | { id, status: "failed", error } ] }.

Toutes en member. La liste/GET sur la plupart est en (viewer). Supprimer une pièce jointe ou une pièce jointe de type lien nécessite d’en être l’auteur de l’envoi ou (manager).

MéthodeCheminCorps / 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) } ou { comment_emoji }. GET accepte fields= (liste autorisée : comment_id, story_comment_id, story_id, comment_text, comment_emoji, member, created) plus 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}Création : { url, link_type?, title? } ; mise à jour : { url, title? } — link_type ∈ relates_to, duplicates, blocks, is_blocked_by, pull_request, branch, other ; les URL GitHub en /pull/ et /tree/ sont typées automatiquement
GET / POST/projects/{id}/stories/{sid}/reviews · PUT/DELETE …/reviews/{rid}Création : { reviewer_id? / reviewer_agent_id?, comment? } — omettez les deux pour vous assigner vous-même. Mise à jour : { status, comment? }
GET / POST/projects/{id}/stories/{sid}/owners · DELETE …/owners/{mid} · DELETE …/owners/agents/{aid}{ member_id? / agent_id? } — omettez les deux pour ajouter l’appelant
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 } — un label existant du projet ; créez les labels avec POST /projects/{id}/labels, ou envoyez labels dans le PUT de la story
GET / POST/projects/{id}/stories/{sid}/attachments (+ /json) · DELETE …/attachments/{aid}envoi multipart — vidéo ≤ 200 Mo, PDF / Word / Excel ≤ 25 Mo, images / CSV / texte ≤ 10 Mo ; la liste est en (viewer)
GET / POST/projects/{id}/stories/{sid}/link-attachments · DELETE …/link-attachments/{laid}Pièces jointes de type lien — une URL externe conservée avec les pièces jointes de fichier plutôt que comme lien de code
GET/attachments/{token} · /api/v1/avatars/{token}Lectures d’une pièce jointe ou d’un avatar adressées par jeton — les URL que l’API renvoie ; aucun X-TrackerToken n’est requis

Même forme que les stories, sans la machine à états. member pour les écritures et pour les listes de commentaires, de propriétaires et d’abonnés ; (viewer) pour la liste des epics, un epic seul et les listes de pièces jointes.

MéthodeCheminDescription
GET / POST/projects/{id}/epics · GET / PUT / DELETE …/epics/{eid}Un epic porte un nom, une description Markdown et un label associé qui rattache ses stories
GET / POST / PUT / DELETE…/epics/{eid}/comments · …/comments/{cid}Commentaires d’epic
GET / POST / DELETE…/epics/{eid}/owners · …/followers (+ variantes /agents/{aid})Propriétaires et abonnés, membres ou agents — les propriétaires d’un epic se propagent à ses stories
GET / POST / DELETE…/epics/{eid}/attachments (+ /json) · …/link-attachmentsPièces jointes, mêmes plafonds que pour les stories
GET/projects/{id}/analytics/epics · …/analytics/epics/{eid}Progression par epic : burnup, débit, santé, prévision (viewer)

member pour les écritures, (viewer) pour les lectures.

MéthodeCheminDescription
GET / POST/projects/{id}/labelsLister / créer un label
GET / PUT / DELETE/projects/{id}/labels/{lid}Lire / mettre à jour / supprimer un label
POST/projects/{id}/labels/{lid}/archiveArchiver (masquer en douceur) un label

Les lectures sont ouvertes à tout rôle de projet, et anonymes sur un projet public.

MéthodeCheminDescription
GET/projects/{id}/iterationsLister les itérations (≤ 500 par page ; porte un ETag et, en cas de troncature, les en-têtes de continuation X-Tracker-Pagination-*)
GET/projects/{id}/iterations/{itid}Une itération
GET/projects/{id}/iterations/first-previewLa fenêtre, la vélocité projetée et le remplissage depuis le Backlog de l’itération qu’une écriture d’amorçage créerait, ou de l’itération courante si elle existe (member)
POST/projects/{id}/iterationsCréer une itération manuelle (manager)
DELETE/projects/{id}/iterations/{itid}Supprimer une itération (manager)
PUT/projects/{id}/iterations/{itid}/velocityRemplacer la vélocité d’une itération sans changer la stratégie du projet (manager)
GET/projects/{id}/iterations/{itid}/done-storiesLes stories acceptées d’une itération close, paginées
MéthodeCheminDescription
GET/projects/{id}/search?q=…Recherche puissante — texte intégral + qualificateurs de facette / de plage de dates / de personnes (DSL inspiré de GitHub) ; renvoie { results, total, limit, offset }. query est un alias de q ; limit= (50 par défaut, max 1000) / offset= paginent ; sort= trie par relevance (par défaut), created, created_asc, state ou updated. (viewer) — voir le Guide
GET/projects/{id}/metrics/{velocity,burndown,story-types,contributors}Les séries de la page Metrics (viewer) ; les métriques d’epic se trouvent sous /analytics/epics ci-dessus
GET/projects/{id}/backlog/groupingLes groupes d’itérations projetés du Backlog (viewer)
GET / PUT/projects/{id}/preferencesVos préférences de tableau pour ce projet — tout rôle de projet, uniquement votre propre ligne
MéthodeCheminDescription
GET/projects/{id}/eventsFlux d’événements paginé par curseur (member) — les viewers reçoivent 403

Paramètres de requête : since_id=<event_id> (since est l’ancien alias ; since_id l’emporte quand les deux sont envoyés), types=story.created,story.transitioned,comment.added,…, limit= (100 par défaut, ≤ 500), cursor=. La réponse est { items, next_since_id, next_cursor } : conservez next_since_id et renvoyez-le comme since_id pour reprendre ; next_cursor vaut null sur la dernière page.

Le flux de notifications unifié dans l’application : des lignes de notification de premier ordre (demandes de revue, activité des stories, invitations, …) fusionnées avec la boîte de mentions @ en un seul flux, du plus récent au plus ancien. Les ids du flux sont préfixés par leur source (nt-… / sc-… / ec-…). Les sessions membre et les clés ea_user_* lisent leurs lignes côté membre ; les clés ea_agent_* leurs lignes côté agent.

MéthodeCheminDescription
GET/me/notificationsVotre flux de notifications. Filtres : unread=true, since_id=, kind= (mentions / reviews / stories / invitations) ; paginez avec cursor= / limit=
GET/me/notifications/unread-countTotaux non lus — { unread_count, by_category: { mentions, reviews, stories, invitations } }
POST/me/notifications/read-allTout marquer comme lu ; renvoie les compteurs à jour
POST/me/notifications/{id}/ackMarquer un élément comme lu (idempotent)
POST/me/notifications/{id}/acceptAccepter une invitation à un projet / une organisation depuis le flux (jetons membre uniquement)
POST/me/notifications/{id}/declineDécliner une invitation à un projet / une organisation (jetons membre uniquement)
GET/me/notifications/resolve-invite?token=…Associer un jeton d’invitation reçu par e-mail à l’id de votre notification — { "id": "nt-…" } ou { "id": null }
GET/me/notifications/streamPush en direct — Server-Sent Events (text/event-stream) ; voir ci-dessous

L’endpoint de stream n’est pas un endpoint JSON et n’apparaît donc pas dans la spécification OpenAPI : il maintient la connexion ouverte et émet une trame sans payload ({"type":"notification","kind":…}) dès que quelque chose de nouveau arrive, indiquant au client de recharger le flux. Les connexions sont coupées côté serveur au bout de 45 minutes — reconnectez-vous et ré-authentifiez-vous. Sessions membre et clés ea_user_* uniquement ; les clés ea_agent_* reçoivent 403.

MéthodeCheminDescription
POST/projects/{id}/importSources de fichiers : source= ∈ pivotal, jira, asana, gitlab, shortcut, trello, linear, plane, plane_json, eat. Multipart file=. Synchrone — répond avec les compteurs de résultat.
POST/projects/{id}/import/jsonCorps JSON ; source=github ne requiert aucun fichier — owner, repo, token facultatif, et les indicateurs optionnels include_pull_requests / include_milestones / include_releases / include_dependencies, et include_comments (par défaut true) ; les sources de fichiers envoient file_base64. Asynchrone : renvoie 202 { import_id, status }. Le serveur récupère via l’API GraphQL de GitHub, qui rejette les appelants anonymes : un jeton parvient donc toujours à GitHub — le vôtre, ou celui partagé par le déploiement. Voir le Guide.
GET/projects/{id}/imports/{import_id}Suivre une tâche : status passe par pending → fetching → writing → done | failed, avec progress_current / progress_total pendant la récupération et les compteurs de résultat à done

Un seul import JSON s’exécute par projet à la fois ; un second POST …/import/json pendant qu’un import est en cours renvoie 409 import_already_running. Avec check_unpointed_estimates: true (sources fichier ; ignoré pour github), un fichier contenant des estimations de bugs ou de corvées que le projet ne chiffre pas est refusé avec 409 import_unpointed_estimates et details.count avant le démarrage de tout job ; sans l’option, l’import abandonne ces estimations et signale { code: "estimates_unpointed_dropped", count } dans les warnings du résultat. dry_run: true (corps JSON ou dry_run=true multipart) prévisualise n’importe quelle source : analyse, résout, dédoublonne, renvoie les mêmes compteurs { imported, skipped, errors, unmatched }, puis annule tout — rien n’est écrit. Plafonds : un fichier de 10 MiB (400 import_too_large) et 5 000 stories par import pour les sources fichier (400 import_too_many_records) ; rien n’est écrit. Un corps de requête de plus de 16 MiB est refusé plus tôt avec 413 request_too_large. La source GitHub n’est pas plafonnée — elle écrit par lots successifs plutôt qu’en une seule transaction. La réimportation est idempotente par id source — les lignes déjà importées sont ignorées, pas dupliquées.

MéthodeCheminDescription
GET/projects/{id}/export/formatsFormats enregistrés : { id, name, content_type, drops, includes_archived }. Tout rôle de projet.
GET/projects/{id}/export/{format}En télécharger un (manager). Échange : eat (fidélité complète), jira, pivotal, shortcut, trello, asana, gitlab, linear, plane, plane_json ; documents : pdf, docx.
GET/projects/{id}/export/attachmentsToutes les pièces jointes dans un seul zip navigable (les fichiers conservent leurs noms d’origine ; manifeste JSON + CSV) (manager).

Les exports de documents (pdf, docx) acceptent des paramètres de requête supplémentaires : page_size= (letter par défaut / a4 / legal / folio), from= / to= (bornes de la fenêtre de stories — RFC 3339 ou simple YYYY-MM-DD ; une story est dans la plage quand son created ou son completed_at tombe dedans), include_icebox= / include_backlog= (tous deux false par défaut, de sorte qu’un export partageable ne montre que le travail planifié / en cours). Les formats CSV d’échange les ignorent.

MéthodeCheminDescription
GET / POST/projects/{id}/backups · GET …/backups/{snapshot_id} · …/backups/healthLister les instantanés, en prendre un immédiatement, en lire un, et le résumé de santé de la rétention
POST/projects/{id}/restores · POST …/restores/partial · GET …/restores/{restore_id}Restaurer un instantané complet, ou certaines de ses tables, et suivre la restauration

Les POST relèvent du palier de limite de débit sensible (ci-dessous).

East Agile Tracker est un fournisseur OAuth 2.1 pour les clients MCP. Un client le découvre via /.well-known/oauth-authorization-server et /.well-known/oauth-protected-resource/mcp, vous envoie vers /oauth/authorize (la page de consentement), échange le code sur /oauth/token, puis parle MCP sur /mcp avec le jeton ea_mcp_* obtenu. Les autorisations se listent et se révoquent sur /me/oauth_grants. Les endpoints du fournisseur ont leur propre palier de limite de débit.

Les endpoints d’écriture (POST, PUT, DELETE) acceptent un en-tête Idempotency-Key. La même clé + le même corps rejoue la réponse mise en cache (fenêtre de 24 heures) ; la même clé + un corps différent renvoie 409 idempotency_conflict. La clé est propre à l’identifiant qui l’a envoyée. Non appliqué aux requêtes GET/HEAD/OPTIONS, à /openapi.json et /docs, à /api/auth/*, à /mcp, à tout chemin contenant /attachments, ni à toute requête multipart/* ; une requête sans identifiant n’est jamais mise en cache. Les réponses qui n’ont pas abouti à une réponse métier ne sont jamais mises en cache — 401, 403, 404, 429 et tout 5xx — si bien qu’un nouvel essai après l’une d’elles atteint le gestionnaire ; 400, 409, 412 et 422 sont la réponse métier et sont rejouées comme un succès.

Les endpoints de liste acceptent cursor=<opaque> et limit=<n>. Lorsqu’ils sont définis, la réponse est { "items": [...], "next_cursor": "<str|null>" } ; renvoyez next_cursor pour paginer. Le plafond de limit dépend de l’endpoint : 200 pour les stories, les commentaires et les projets ; 500 pour les événements ; 1000 pour le journal d’audit. La recherche pagine avec limit (≤ 1000) et offset plutôt qu’avec un curseur, et renvoie { results, total, limit, offset }.

Une liste simple (sans cursor/limit) qui a dû tronquer sa réponse le signale dans ses en-têtes — X-Tracker-Pagination-Truncated, X-Tracker-Pagination-Limit, X-Tracker-Pagination-Offset et X-Tracker-Pagination-Next-Offset ; renvoyez ce dernier comme offset= pour obtenir la page suivante. Il n’existe pas d’en-tête de nombre total.

Les listes de stories, de commentaires et de projets acceptent fields= (séparés par des virgules) pour ne renvoyer que des champs spécifiques. L’id de la ressource est toujours inclus (story_id, story_comment_id et comment_id, project_id) ; un nom de champ inconnu renvoie 400 validation_failed avec les noms en cause dans details.fields.

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

Chaque erreur JSON possède code et error ; certaines ajoutent details :

{ "code": "invalid_transition",
"error": "Cannot move story from `unstarted` to `accepted`",
"details": { "from": "unstarted", "to": "accepted", "allowed": ["started"] } }
StatutcodeQuand
400invalid_parameterentrée incorrecte ; message dans error. La validation des champs (vide/longueur/octet null/e-mail) ajoute details.fields et details.constraint ; seule une simple erreur de requête invalide omet details
400validation_failederreur d’entrée structurée ; details.fields est un tableau de noms de champs en cause
400codes métierun refus propre à la route, avec son propre code et sans details — par ex. unsupported_export_format, import_too_large, import_unknown_source
401unauthenticatedjeton manquant/invalide
403unauthorized_operationauthentifié mais rôle insuffisant
404unfound_resourceintrouvable — également renvoyé aux non-membres
409conflictconflit de ressource (par ex. doublon)
409idempotency_conflictIdempotency-Key réutilisée avec un corps différent
409stale_write · import_already_running · import_unpointed_estimatesla description a changé après votre expected_version (ou expected_updated_at ne correspond plus) · un import est déjà en cours · le fichier contient des estimations de bugs ou de corvées que le projet ne chiffre pas (details.count)
412precondition_failedIf-Match ne correspond pas à l’ETag actuel de la ressource ; details contient expected et current
413request_too_largele corps dépasse la limite de taille de la route
422invalid_transitiondéplacement d’état illégal ; details contient { from, to, allowed }
429rate_limitedtrop de requêtes depuis cette IP sur une route à débit limité ; en-tête Retry-After
500internal_errordéfaillance serveur — message générique ; peut être réessayé sans risque
502upstream_errorun service dont dépend la route (par ex. GitHub) a échoué
503not_configuredle déploiement ne dispose pas de l’intégration requise par cette route (SMS, stockage objet, …)

details.fields est un tableau JSON de noms de champs (par ex. ["to"]), parfois accompagné de clés supplémentaires comme max. Il n’y a pas de correspondance champ→message.

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

Par IP client, sur une poignée de routes ; ailleurs, le trafic d’API authentifié n’est pas soumis à une limite de débit. Valeurs par défaut (chaque paire indique le débit soutenu et la rafale, réglables par l’opérateur) :

  • Auth — /api/auth/* : 0,5 req/s, rafale 20.
  • Fournisseur OAuth — /oauth/* : 1 req/s, rafale 60.
  • Public — /api/contact : 0,2 req/s, rafale 10.
  • Retours — /api/v1/feedback et /api/v1/feedback/with-screenshot : trois paliers superposés — un envoi par 15 s, 10 par heure, 36 par jour.
  • Avatars — la redirection d’avatar non authentifiée : 20 req/s, rafale 200.
  • Sensible — les POST de sauvegarde et de restauration : ~0,002 req/s, rafale 5.

Une limite dépassée renvoie 429 avec un en-tête Retry-After et l’enveloppe d’erreur JSON standard, code: "rate_limited".