Documentation API Manifst
Bienvenue dans la documentation de l'API REST Manifst v1. Elle est incluse à partir du plan Portefeuille, et s'évalue sur l'abonnement du compte propriétaire de la clé. Les comptes souscrits avant la grille actuelle conservent leur accès.
baseUrl et apiKey dans les variables de collection.Introduction
URL de base :
https://manifst.net/api/v1/
Toutes les réponses sont au format JSON avec la structure suivante :
// Succès
{
"data": { ... }, // objet ou tableau
"meta": { "total": 42 } // présent sur les listes
}
// Erreur
{
"error": {
"code": "INSUFFICIENT_SCOPE",
"message": "This API key does not have the required scope: 'projects:write'."
}
}
Authentification
Toutes les requêtes doivent inclure votre clé API dans le header Authorization :
Authorization: Bearer mfst_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Générer une clé
Rendez-vous dans Paramètres → Clés API de votre dashboard Manifst. Les clés sont affichées une seule fois à la création.
Exemple de requête
curl https://manifst.net/api/v1/projects \
-H "Authorization: Bearer mfst_live_xxxxx"
Rate limiting
| Fenêtre | Limite |
|---|---|
| Par heure | 1 000 requêtes |
| Par mois | 10 000 requêtes |
Chaque réponse inclut ces headers :
X-RateLimit-Limit-Hour: 1000
X-RateLimit-Remaining-Hour: 847
X-RateLimit-Limit-Month: 10000
X-RateLimit-Remaining-Month: 9231
X-RateLimit-Reset-Hour: 1711234567
En cas de dépassement, l'API retourne HTTP 429 avec le header Retry-After (secondes avant le prochain reset).
Pagination & rafraîchissement incrémental
Les listes volumineuses — /tickets et /time-entries — acceptent une pagination optionnelle et un filtre incrémental. Sans ces paramètres, la réponse reste identique aux versions précédentes (rétro-compatible).
| Paramètre | Description |
|---|---|
page | Numéro de page (défaut 1). Active la pagination. |
per_page | Taille de page (défaut 100, max 500). Active la pagination. |
updated_since | Ne renvoie que les éléments modifiés depuis cette date (YYYY-MM-DD ou datetime). Idéal pour un refresh incrémental Power BI. |
Le bloc meta renvoie toujours le total réel avant pagination :
GET /api/v1/tickets?project=abc-123&page=2&per_page=50&updated_since=2026-07-01
{
"data": [ ... ],
"meta": { "total": 320, "count": 50, "page": 2, "per_page": 50 }
}
Codes d'erreur
| Code | HTTP | Description |
|---|---|---|
| MISSING_API_KEY | 401 | Header Authorization absent |
| INVALID_API_KEY | 401 | Clé introuvable |
| REVOKED_API_KEY | 401 | Clé révoquée |
| EXPIRED_API_KEY | 401 | Clé expirée |
| PLAN_REQUIRED | 403 | Plan Portefeuille requis |
| ACCOUNT_INACTIVE | 403 | Compte inactif |
| IP_NOT_ALLOWED | 403 | IP non autorisée (whitelist) |
| INSUFFICIENT_SCOPE | 403 | Scope manquant sur la clé |
| RATE_LIMIT_EXCEEDED | 429 | Quota dépassé |
| NOT_FOUND | 404 | Ressource introuvable |
| FORBIDDEN | 403 | Accès interdit à cette ressource |
| VALIDATION_ERROR | 422 | Paramètre manquant ou invalide |
| METHOD_NOT_ALLOWED | 405 | Méthode HTTP non supportée |
Scopes
Chaque clé API dispose d'un ensemble de scopes qui définissent ses permissions. Les scopes disponibles :
| Scope | Description |
|---|---|
| projects:read | Lire les projets et leurs membres |
| projects:write | Créer, modifier, supprimer des projets |
| super-epics:read | Lire les super-épics |
| super-epics:write | Créer, modifier, supprimer les super-épics |
| epics:read | Lire les épics |
| epics:write | Créer, modifier, supprimer les épics |
| sprints:read | Lire les sprints |
| sprints:write | Créer et modifier les sprints |
| tickets:read | Lire les tickets |
| tickets:write | Créer, modifier, supprimer les tickets |
| comments:read | Lire les commentaires d'un ticket |
| comments:write | Créer, modifier, supprimer des commentaires |
| team:read | Lire les membres d'un projet |
| time:read | Lire les entrées de temps |
| time:write | Enregistrer des entrées de temps |
| statuses:read | Lire les statuts d'un projet |
| finance:read | Lire les indicateurs finance / EVM (projet & portefeuille) |
| roadmap:read | Lire les dépendances et jalons de roadmap |
Projets
Scope requis : projects:read
curl /api/v1/projects -H "Authorization: Bearer mfst_live_xxx"
// Réponse 200
{
"data": [
{
"uuid": "abc-123",
"name": "Mon projet",
"description": "Description",
"color": "#6366f1",
"default_dod": ["Code review faite", "Tests passants"],
"contingency_pct": 10.0,
"budget": 350000.00,
"user_role": "owner",
"member_count": 5,
"created_at": "2026-01-15 10:00:00",
"updated_at": "2026-03-01 14:22:00"
}
],
"meta": { "total": 1 }
}
Scope requis : projects:read
curl /api/v1/projects/abc-123 -H "Authorization: Bearer mfst_live_xxx"
Scope requis : team:read
Scope requis : projects:write
La création initialise automatiquement les 6 statuts par défaut (Backlog, À faire, En cours, En revue, Terminé, Bloqué) et les 2 types de tickets par défaut (Story, Bug).
Body
{
"name": "Mon projet", // requis, 1–80 caractères
"description": "...", // optionnel
"color": "#6366f1", // optionnel, hex #rrggbb
"default_dod": ["Tests OK", "Code review"], // optionnel — Definition of Done (tableau)
"contingency_pct": 10.00, // optionnel — aléas finance, 0–100 % (défaut: 10)
"budget": 350000.00 // optionnel — BAC / budget à terminaison (≥ 0, null pour effacer)
}
Réponse 201
{
"data": {
"uuid": "...",
"name": "Mon projet",
"description": null,
"color": "#6366f1",
"default_dod": null,
"contingency_pct": 10.0,
"budget": 350000.00,
"user_role": "owner",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00"
}
}
Scope requis : projects:write — owner uniquement
Body
{
"name": "Nouveau nom", // optionnel
"description": "...", // optionnel
"color": "#f59e0b", // optionnel
"default_dod": ["item 1", "item 2"], // optionnel — null ou [] pour vider
"contingency_pct": 15.00, // optionnel — 0–100 %
"budget": 420000.00 // optionnel — BAC (≥ 0, null pour effacer)
}
Réponse 200
{
"data": {
"uuid": "...",
"name": "Nouveau nom",
"description": null,
"color": "#f59e0b",
"default_dod": ["item 1", "item 2"],
"contingency_pct": 15.0,
"budget": 420000.00,
"user_role": "owner",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00"
}
}
Scope requis : projects:write — owner uniquement
// Réponse 200
{ "data": { "deleted": true } }
Super-épics
Scope requis : super-epics:read
Scope requis : super-epics:read
Scope requis : super-epics:write
Body
{
"project_uuid": "abc-123",
"title": "Titre",
"description": "...", // optionnel
"status": "backlog", // optionnel — backlog | in_progress | done (défaut: backlog)
"tags": ["tag-uuid-1"] // optionnel — array d'UUID de tags
}
Réponse 201
{
"data": {
"uuid": "...",
"project_id": 1,
"title": "Titre",
"description": null,
"status": "backlog",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : super-epics:write
Body
{
"title": "Nouveau titre", // optionnel
"description": "...", // optionnel
"status": "in_progress", // optionnel — backlog | in_progress | done
"tags": ["tag-uuid-1"] // optionnel — remplace l'ensemble des tags
}
Réponse 200
{
"data": {
"uuid": "...",
"project_id": 1,
"title": "Nouveau titre",
"description": null,
"status": "in_progress",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : super-epics:write — les épics liés sont détachés, pas supprimés.
Épics
Scope requis : epics:read
Scope requis : epics:read
Scope requis : epics:write
Body
{
"project_uuid": "abc-123",
"title": "Titre",
"description": "...", // optionnel
"super_epic_uuid": "se-uuid", // optionnel
"status": "backlog", // optionnel — backlog | todo | in_progress | in_review | done | blocked (défaut: backlog)
"tags": ["tag-uuid-1"] // optionnel — array d'UUID de tags
}
Réponse 201
{
"data": {
"uuid": "...",
"project_id": 1,
"super_epic_id": null,
"super_epic_uuid": null,
"title": "Titre",
"description": null,
"status": "backlog",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : epics:write
Body
{
"title": "...", // optionnel
"description": "...", // optionnel
"super_epic_uuid": null, // optionnel — uuid ou null pour détacher
"status": "done", // optionnel — backlog | todo | in_progress | in_review | done | blocked
"tags": ["tag-uuid-1"] // optionnel — remplace l'ensemble des tags
}
Réponse 200
{
"data": {
"uuid": "...",
"project_id": 1,
"super_epic_id": null,
"super_epic_uuid": null,
"title": "...",
"description": null,
"status": "done",
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : epics:write — les tickets liés sont détachées.
Sprints
Scope requis : sprints:read
Scope requis : sprints:read
Scope requis : sprints:write
Body
{
"project_uuid": "abc-123",
"title": "Sprint 1",
"goal": "...", // optionnel
"status": "planning", // optionnel — planning | active | completed (défaut: planning)
"start_date": "2026-04-01", // optionnel
"end_date": "2026-04-14", // optionnel
"dod": ["item 1", "item 2"] // optionnel — Definition of Done du sprint (tableau)
}
Réponse 201
{
"data": {
"uuid": "...",
"project_id": 1,
"title": "Sprint 1",
"goal": null,
"status": "planning",
"start_date": "2026-04-01",
"end_date": "2026-04-14",
"dod": null,
"created_at": "2026-03-24 20:00:00"
}
}
Scope requis : sprints:write
Body
{
"title": "Sprint 1", // optionnel
"status": "active", // optionnel — planning | active | completed
"goal": "...", // optionnel
"start_date": "2026-04-01", // optionnel
"end_date": "2026-04-14", // optionnel
"dod": ["item 1"] // optionnel — null ou [] pour vider
}
Réponse 200
{
"data": {
"uuid": "...",
"project_id": 1,
"title": "Sprint 1",
"goal": null,
"status": "active",
"start_date": "2026-04-01",
"end_date": "2026-04-14",
"dod": ["item 1"],
"created_at": "2026-03-24 20:00:00"
}
}
Tickets
Scope requis : tickets:read
Filtres optionnels : ?sprint={uuid} et ?epic={uuid}
Scope requis : tickets:read
{
"data": {
"uuid": "...", "title": "...", "description": "...",
"priority": "haute", "status": "todo", "story_points": 5,
"epic_id": 1, "sprint_id": 2, "assignee": "Alice Martin",
"acceptance_criteria": ["Critère 1", "Critère 2"],
"dependencies": [{ "uuid": "...", "title": "Autre story" }],
"tags": [{ "uuid": "tag-uuid", "name": "bug" }],
"subtasks": [
{ "uuid": "...", "title": "Tâche technique", "status": "todo",
"sort_order": 1, "assignee_id": 3, "assignee_name": "Alice Martin",
"created_at": "2026-03-25 10:00:00", "updated_at": "2026-03-25 10:00:00" }
],
"subtasks_total": 1,
"subtasks_done": 0
}
}
Scope requis : tickets:write
Body
{
"project_uuid": "abc-123",
"title": "En tant qu'utilisateur…",
"description": "...",
"priority": "haute", // critique | haute | normale | faible
"status": "backlog", // backlog | todo | in_progress | in_review | done | blocked
"story_points": 5, // optionnel
"epic_uuid": "epic-uuid", // optionnel
"sprint_uuid": "sprint-uuid",// optionnel
"assignee_id": 3, // optionnel
"acceptance_criteria": ["Critère 1"], // optionnel
"dependencies": ["us-uuid-1"], // optionnel
"tags": ["tag-uuid-1"] // optionnel — array d'UUID de tags
}
Réponse 201
{
"data": {
"uuid": "...",
"project_id": 1,
"epic_id": null,
"sprint_id": null,
"assignee_id": null,
"assignee": null,
"title": "En tant qu'utilisateur…",
"description": null,
"priority": "haute",
"status": "backlog",
"story_points": 5,
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"acceptance_criteria": ["Critère 1"],
"dependencies": [],
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : tickets:write
Body
{
"title": "...", // optionnel
"description": "...", // optionnel
"priority": "haute", // optionnel — critique | haute | normale | faible
"status": "in_progress", // optionnel — backlog | todo | in_progress | in_review | done | blocked
"story_points": 8, // optionnel
"epic_uuid": "epic-uuid", // optionnel — uuid ou null pour détacher
"sprint_uuid": "sprint-uuid", // optionnel — uuid ou null pour détacher
"assignee_id": 3, // optionnel — id ou null
"acceptance_criteria": ["Critère 1"], // optionnel — remplace les critères existants
"dependencies": ["us-uuid-1"], // optionnel — remplace les dépendances existantes
"tags": ["tag-uuid-1"] // optionnel — remplace l'ensemble des tags
}
Réponse 200
{
"data": {
"uuid": "...",
"project_id": 1,
"epic_id": null,
"sprint_id": null,
"assignee_id": null,
"assignee": null,
"title": "...",
"description": null,
"priority": "haute",
"status": "in_progress",
"story_points": 8,
"created_at": "2026-03-24 20:00:00",
"updated_at": "2026-03-24 20:00:00",
"acceptance_criteria": ["Critère 1"],
"dependencies": [],
"tags": [{ "uuid": "tag-uuid", "name": "bug" }]
}
}
Scope requis : tickets:write
Sous-tâches
Les sous-tâches ont des statuts fixes (todo, in_progress, done), indépendants des statuts personnalisés du projet. Elles représentent une liste de contrôle technique attaché à un ticket.
Scope requis : tickets:read
{
"data": [
{
"uuid": "...",
"title": "Tâche technique",
"status": "todo", // todo | in_progress | done
"sort_order": 1,
"assignee_id": 3,
"assignee_name": "Alice Martin",
"created_at": "2026-03-25 10:00:00",
"updated_at": "2026-03-25 10:00:00"
}
],
"meta": { "total": 1 }
}
Scope requis : tickets:write
Body
{
"ticket_uuid": "us-uuid", // requis
"title": "Tâche technique", // requis
"status": "todo", // optionnel — todo | in_progress | done (défaut: todo)
"assignee_id": 3 // optionnel
}
Réponse 201
{
"data": {
"uuid": "...", "title": "Tâche technique", "status": "todo",
"sort_order": 1, "assignee_id": null, "assignee_name": null,
"created_at": "...", "updated_at": "..."
}
}
Scope requis : tickets:write
Body
{
"title": "...", // optionnel
"status": "in_progress", // optionnel — todo | in_progress | done
"assignee_id": 3, // optionnel — id ou null pour désassigner
"sort_order": 2 // optionnel
}
Réponse 200
{
"data": {
"uuid": "...", "title": "...", "status": "in_progress",
"sort_order": 2, "assignee_id": 3, "assignee_name": "Alice Martin",
"created_at": "...", "updated_at": "..."
}
}
Scope requis : tickets:write
Commentaires
Les commentaires sont attachés à un ticket. Seul l'auteur (ou un admin) peut modifier ou supprimer ses propres commentaires. Le contenu est du HTML sanitisé (scripts et handlers JS retirés).
Scope requis : comments:read
| Paramètre | Type | Description |
|---|---|---|
us | string | UUID du ticket — requis |
Réponse 200
{
"data": [
{
"uuid": "...",
"author_id": 3,
"author_name": "Alice Martin",
"author_initials": "AM",
"content": "<p>Texte du commentaire</p>",
"mentions": [4, 7],
"ticket_uuid": "...",
"created_at": "2026-04-02 10:00:00",
"updated_at": "2026-04-02 10:00:00"
}
],
"meta": { "total": 1 }
}
Scope requis : comments:read
Scope requis : comments:write
Body
{
"ticket_uuid": "...", // requis — UUID du ticket
"content": "<p>Mon commentaire</p>", // requis — HTML sanitisé
"mentions": [4, 7] // optionnel — IDs utilisateurs mentionnés
}
Réponse 201
{
"data": {
"uuid": "...",
"author_id": 3,
"author_name": "Alice Martin",
"author_initials": "AM",
"content": "<p>Mon commentaire</p>",
"mentions": [4],
"ticket_uuid": "...",
"created_at": "2026-04-02 10:00:00",
"updated_at": "2026-04-02 10:00:00"
}
}
Scope requis : comments:write — auteur ou admin uniquement.
Body
{
"content": "<p>Contenu modifié</p>", // optionnel
"mentions": [4, 7] // optionnel — remplace la liste complète
}
Scope requis : comments:write — auteur ou admin uniquement.
{ "data": { "deleted": true } }
Équipe
Scope requis : team:read
{
"data": [
{
"uuid": "...", "firstname": "Alice", "lastname": "Martin",
"email": "alice@example.com", "scrum_role": "dev",
"project_role": "member", "status": "active",
"tjm": 550.00, "service": "Delivery"
}
],
"meta": { "total": 4 }
}
tjm = taux journalier moyen (coût/jour) du membre sur ce projet, base des indicateurs finance ; null si non renseigné.
Entrées de temps
Scope requis : time:read
Filtre optionnel : ?story={uuid} pour une story spécifique.
Scope requis : time:write
Body
{
"ticket_uuid": "story-uuid", // requis
"duration_minutes": 90, // requis
"logged_at": "2026-03-24", // requis, format YYYY-MM-DD
"comment": "Revue de code" // optionnel
}
Réponse 201
{
"data": {
"uuid": "...",
"ticket_id": 12,
"user_id": 3,
"user_name": "Alice Martin",
"ticket_uuid": "...",
"ticket_title": "En tant qu'utilisateur…",
"duration_minutes": 90,
"comment": "Revue de code",
"logged_at": "2026-03-24 00:00:00",
"created_at": "2026-03-24 20:00:00"
}
}
Statuts
Scope requis : statuses:read
Retourne tous les statuts du projet (par défaut et personnalisés), triés par sort_order.
Réponse 200
[
{
"key": "backlog",
"label": "Backlog",
"color": "#64748b",
"bg_color": "#f1f5f9",
"sort_order": 1,
"is_done": false,
"is_default": true
},
{
"key": "in_validation",
"label": "En validation",
"color": "#7c3aed",
"bg_color": "#f5f3ff",
"sort_order": 7,
"is_done": false,
"is_default": false
}
]
Dépendances
Liens finish-to-start entre items de roadmap (épic ou super-épic). Chaque nœud est exposé par son UUID (joignable avec /epics et /super-epics) pour reconstruire le graphe et, côté consommateur, en dériver le chemin critique.
Scope requis : roadmap:read
{
"data": [
{
"uuid": "dep-uuid",
"type": "FS", // finish-to-start
"pred_type": "epic", // epic | super_epic
"pred_uuid": "epic-uuid-1",
"succ_type": "epic",
"succ_uuid": "epic-uuid-2"
}
],
"meta": { "total": 1 }
}
Jalons
Scope requis : roadmap:read
{
"data": [
{ "uuid": "...", "name": "Go-live", "date": "2026-09-30", "color": "#e11d48" }
],
"meta": { "total": 1 }
}
Finance / EVM
Indicateurs de gestion par la valeur acquise (Earned Value Management) d'un projet, calculés côté serveur à partir des story points, des temps enregistrés (× TJM) et du BAC déclaré (projects.budget).
bac, pv, ev, cpi, cv, sv, eac, etc, vac, tcpi) valent null tant qu'aucun BAC n'est déclaré sur le projet. Les métriques d'avancement et de coût (ac, engaged_charge, spi, progress_pct, planned_pct) restent calculées.Scope requis : finance:read
{
"data": {
"project_uuid": "abc-123",
"bac": 350000.00, // budget à terminaison (déclaré)
"base_budget": 315000.00, // BAC − réserve d'aléa
"reserve": 35000.00, // réserve d'aléa (incluse dans le BAC)
"contingency_pct": 10.00,
"pv": 326341.95, // valeur planifiée = % SP planifié à date × BAC
"ev": 257455.27, // valeur acquise = % SP réalisé × BAC
"ac": 186573.75, // coût actuel = Σ (temps ÷ 480) × TJM
"engaged_charge": 137253.75, // coût réel des épics non terminées
"cpi": 1.38, // EV ÷ AC (> 1 = sous le budget)
"spi": 0.79, // % réalisé ÷ % planifié (> 1 = en avance)
"tcpi": 0.57, // (BAC − EV) ÷ (BAC − AC)
"eac": 253639.45, // coût final estimé = BAC ÷ CPI
"etc": 67065.70, // reste à terminaison = EAC − AC
"vac": 96360.55, // écart à terminaison = BAC − EAC
"cv": 70881.52, // écart de coût = EV − AC
"sv": -68886.68, // écart de délai = (% réalisé − % planifié) × BAC
"total_sp": 503,
"done_sp": 370,
"planned_sp": 469.10,
"progress_pct": 73.56, // % SP réalisés
"planned_pct": 93.24 // % SP planifiés à date
}
}
Portefeuille
Consolidation EVM sur tous les projets accessibles au porteur de la clé — une seule requête là où il fallait boucler projet par projet. Les indices consolidés sont calculés sur la somme des valeurs (EV, PV, AC), pas sur une moyenne des ratios.
Scope requis : finance:read
Filtre optionnel : ?projects=uuid1,uuid2 pour cibler une équipe / un programme.
{
"data": {
"totals": {
"projects": 12, "with_bac": 4, "without_bac": 8,
"bac": 1250000.00, "pv": 910000.00, "ev": 742000.00, "ac": 690000.00,
"engaged_charge": 305000.00,
"cpi": 1.08, "spi": 0.82,
"eac": 1157407.41, "vac": 92592.59,
"cv": 52000.00, "sv": -168000.00,
"ac_all": 812000.00, // AC sur TOUS les projets (BAC ou non)
"engaged_all": 410000.00 // charge engagée sur tous les projets
},
"projects": [
{ "project_uuid": "abc-123", "project_name": "CMA-CGM", "bac": 350000.00, "ev": 257455.27, "ac": 186573.75, "cpi": 1.38, "spi": 0.79, "vac": 96360.55, "engaged_charge": 137253.75, "...": "..." }
]
},
"meta": { "total": 12 }
}
Documentation Manifst API v1 · Retour au site