Manifst API Documentation

Welcome to the Manifst REST API v1 documentation. API access is included starting from the Portfolio plan, and is billed based on the plan of the account owning the key. Accounts subscribed prior to the current pricing model retain their access.

Postman Collection
36 ready-to-use requests. Fill in baseUrl and apiKey in the collection variables.
Download

Introduction

Base URL:

https://manifst.net/api/v1/

All responses are returned in JSON format with the following structure:

// Success
{
  "data": { ... },        // object or array
  "meta": { "total": 42 } // present on list responses
}

// Error
{
  "error": {
    "code": "INSUFFICIENT_SCOPE",
    "message": "This API key does not have the required scope: 'projects:write'."
  }
}

Authentication

All requests must include your API key in the Authorization HTTP header:

Authorization: Bearer mfst_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Never expose your API key on the client side (frontend JS, mobile apps). Use it strictly server-side.

Generate a key

Navigate to Settings → API Keys in your Manifst dashboard. API keys are shown only once upon creation.

Request example

curl https://manifst.net/api/v1/projects \
  -H "Authorization: Bearer mfst_live_xxxxx"

Rate limiting

WindowLimit
Per hour1,000 requests
Per month10,000 requests

Every response includes these HTTP 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

When quota is exceeded, the API returns HTTP 429 with a Retry-After header (seconds until reset).

Pagination & incremental refresh

Large collection endpoints — /tickets and /time-entries — support optional pagination and incremental filtering. Without these parameters, responses remain identical to legacy versions (backward compatible).

ParameterDescription
pagePage number (default 1). Enables pagination.
per_pagePage size (default 100, max 500). Enables pagination.
updated_sinceReturns only items updated since this date (YYYY-MM-DD or ISO datetime). Ideal for Power BI incremental refresh.

The meta object always returns the true total count before 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 }
}

Error codes

CodeHTTPDescription
MISSING_API_KEY401Missing Authorization header
INVALID_API_KEY401Key not found
REVOKED_API_KEY401Key revoked
EXPIRED_API_KEY401Key expired
PLAN_REQUIRED403Portfolio plan required
ACCOUNT_INACTIVE403Account inactive
IP_NOT_ALLOWED403IP address not whitelisted
INSUFFICIENT_SCOPE403Missing scope on the API key
RATE_LIMIT_EXCEEDED429Quota limit reached
NOT_FOUND404Resource not found
FORBIDDEN403Access to resource forbidden
VALIDATION_ERROR422Missing or invalid parameter
METHOD_NOT_ALLOWED405HTTP method not supported

Scopes

Each API key is assigned a set of scopes defining its permissions. Available scopes:

ScopeDescription
projects:readRead projects and project members
projects:writeCreate, edit, and delete projects
super-epics:readRead super-epics
super-epics:writeCreate, edit, and delete super-epics
epics:readRead epics
epics:writeCreate, edit, and delete epics
sprints:readRead sprints
sprints:writeCreate and edit sprints
tickets:readRead tickets
tickets:writeCreate, edit, and delete tickets
comments:readRead ticket comments
comments:writeCreate, edit, and delete comments
team:readRead project team members
time:readRead time entries
time:writeLog time entries
statuses:readRead project statuses
finance:readRead finance / EVM indicators (project & portfolio)
roadmap:readRead roadmap dependencies and milestones

Projects

GET /api/v1/projects List projects

Required scope: projects:read

curl /api/v1/projects -H "Authorization: Bearer mfst_live_xxx"

// Response 200
{
  "data": [
    {
      "uuid": "abc-123",
      "name": "My Project",
      "description": "Description",
      "color": "#6366f1",
      "default_dod": ["Code review done", "Tests passing"],
      "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 }
}
GET /api/v1/projects/{uuid} Project details

Required scope: projects:read

curl /api/v1/projects/abc-123 -H "Authorization: Bearer mfst_live_xxx"
GET /api/v1/projects/{uuid}/members Project members

Required scope: team:read

POST /api/v1/projects Create project

Required scope: projects:write

Project creation automatically initializes the 6 default statuses (Backlog, To Do, In Progress, In Review, Done, Blocked) and 2 default ticket types (Story, Bug).

Body

{
  "name": "My Project",                    // required, 1–80 chars
  "description": "...",                    // optional
  "color": "#6366f1",                      // optional, hex #rrggbb
  "default_dod": ["Tests OK", "Code review"], // optional — Definition of Done (array)
  "contingency_pct": 10.00,                // optional — financial reserve, 0–100% (default: 10)
  "budget": 350000.00                      // optional — BAC / budget at completion (≥ 0, null to clear)
}

Response 201

{
  "data": {
    "uuid": "...",
    "name": "My Project",
    "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"
  }
}
PUT /api/v1/projects/{uuid} Update project

Required scope: projects:write — owner only

Body

{
  "name": "New name",                    // optional
  "description": "...",                  // optional
  "color": "#f59e0b",                    // optional
  "default_dod": ["item 1", "item 2"],    // optional — null or [] to clear
  "contingency_pct": 15.00,               // optional — 0–100%
  "budget": 420000.00                     // optional — BAC (≥ 0, null to clear)
}

Response 200

{
  "data": {
    "uuid": "...",
    "name": "New name",
    "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"
  }
}
DELETE /api/v1/projects/{uuid} Delete project

Required scope: projects:write — owner only

// Response 200
{ "data": { "deleted": true } }

Super-epics

GET /api/v1/super-epics?project={uuid} List super-epics

Required scope: super-epics:read

GET /api/v1/super-epics/{uuid} Details

Required scope: super-epics:read

POST /api/v1/super-epics Create

Required scope: super-epics:write

Body

{
  "project_uuid": "abc-123",
  "title": "Title",
  "description": "...",  // optional
  "status": "backlog",   // optional — backlog | in_progress | done (default: backlog)
  "tags": ["tag-uuid-1"] // optional — array of tag UUIDs
}

Response 201

{
  "data": {
    "uuid": "...",
    "project_id": 1,
    "title": "Title",
    "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" }]
  }
}
PUT /api/v1/super-epics/{uuid} Update

Required scope: super-epics:write

Body

{
  "title": "New title",      // optional
  "description": "...",      // optional
  "status": "in_progress",   // optional — backlog | in_progress | done
  "tags": ["tag-uuid-1"]     // optional — replaces all tags
}

Response 200

{
  "data": {
    "uuid": "...",
    "project_id": 1,
    "title": "New title",
    "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" }]
  }
}
DELETE /api/v1/super-epics/{uuid} Delete

Required scope: super-epics:write — linked epics are unlinked, not deleted.

Epics

GET /api/v1/epics?project={uuid} List epics

Required scope: epics:read

GET /api/v1/epics/{uuid} Details

Required scope: epics:read

POST /api/v1/epics Create

Required scope: epics:write

Body

{
  "project_uuid": "abc-123",
  "title": "Title",
  "description": "...",            // optional
  "super_epic_uuid": "se-uuid",    // optional
  "status": "backlog",             // optional — backlog | todo | in_progress | in_review | done | blocked (default: backlog)
  "tags": ["tag-uuid-1"]           // optional — array of tag UUIDs
}

Response 201

{
  "data": {
    "uuid": "...",
    "project_id": 1,
    "super_epic_id": null,
    "super_epic_uuid": null,
    "title": "Title",
    "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" }]
  }
}
PUT /api/v1/epics/{uuid} Update

Required scope: epics:write

Body

{
  "title": "...",           // optional
  "description": "...",     // optional
  "super_epic_uuid": null,  // optional — uuid or null to unlink
  "status": "done",         // optional — backlog | todo | in_progress | in_review | done | blocked
  "tags": ["tag-uuid-1"]    // optional — replaces all tags
}

Response 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" }]
  }
}
DELETE /api/v1/epics/{uuid} Delete

Required scope: epics:write — linked tickets are unlinked.

Sprints

GET /api/v1/sprints?project={uuid} List sprints

Required scope: sprints:read

GET /api/v1/sprints/{uuid} Details

Required scope: sprints:read

POST /api/v1/sprints Create

Required scope: sprints:write

Body

{
  "project_uuid": "abc-123",
  "title": "Sprint 1",
  "goal": "...",               // optional
  "status": "planning",        // optional — planning | active | completed (default: planning)
  "start_date": "2026-04-01",  // optional
  "end_date": "2026-04-14",    // optional
  "dod": ["item 1", "item 2"]   // optional — Sprint Definition of Done (array)
}

Response 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"
  }
}
PUT /api/v1/sprints/{uuid} Update

Required scope: sprints:write

Body

{
  "title": "Sprint 1",         // optional
  "status": "active",          // optional — planning | active | completed
  "goal": "...",               // optional
  "start_date": "2026-04-01",  // optional
  "end_date": "2026-04-14",    // optional
  "dod": ["item 1"]            // optional — null or [] to clear
}

Response 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

GET /api/v1/tickets?project={uuid} List tickets

Required scope: tickets:read

Optional query filters: ?sprint={uuid} and ?epic={uuid}

GET /api/v1/tickets/{uuid} Details (with AC, dependencies, and subtasks)

Required scope: tickets:read

{
  "data": {
    "uuid": "...", "title": "...", "description": "...",
    "priority": "haute", "status": "todo", "story_points": 5,
    "epic_id": 1, "sprint_id": 2, "assignee": "Alice Martin",
    "acceptance_criteria": ["Criteria 1", "Criteria 2"],
    "dependencies": [{ "uuid": "...", "title": "Other story" }],
    "tags": [{ "uuid": "tag-uuid", "name": "bug" }],
    "subtasks": [
      { "uuid": "...", "title": "Technical task", "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
  }
}
POST /api/v1/tickets Create

Required scope: tickets:write

Body

{
  "project_uuid": "abc-123",
  "title": "As a user...",
  "description": "...",
  "priority": "haute",         // critique | haute | normale | faible
  "status": "backlog",         // backlog | todo | in_progress | in_review | done | blocked
  "story_points": 5,           // optional
  "epic_uuid": "epic-uuid",    // optional
  "sprint_uuid": "sprint-uuid",// optional
  "assignee_id": 3,            // optional
  "acceptance_criteria": ["Criteria 1"], // optional
  "dependencies": ["us-uuid-1"],        // optional
  "tags": ["tag-uuid-1"]                // optional — array of tag UUIDs
}

Response 201

{
  "data": {
    "uuid": "...",
    "project_id": 1,
    "epic_id": null,
    "sprint_id": null,
    "assignee_id": null,
    "assignee": null,
    "title": "As a user...",
    "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": ["Criteria 1"],
    "dependencies": [],
    "tags": [{ "uuid": "tag-uuid", "name": "bug" }]
  }
}
PUT /api/v1/tickets/{uuid} Update

Required scope: tickets:write

Body

{
  "title": "...",               // optional
  "description": "...",         // optional
  "priority": "haute",          // optional — critique | haute | normale | faible
  "status": "in_progress",      // optional — backlog | todo | in_progress | in_review | done | blocked
  "story_points": 8,            // optional
  "epic_uuid": "epic-uuid",     // optional — uuid or null to unlink
  "sprint_uuid": "sprint-uuid", // optional — uuid or null to unlink
  "assignee_id": 3,             // optional — id or null
  "acceptance_criteria": ["Criteria 1"], // optional — replaces existing criteria
  "dependencies": ["us-uuid-1"],        // optional — replaces existing dependencies
  "tags": ["tag-uuid-1"]                // optional — replaces all tags
}

Response 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": ["Criteria 1"],
    "dependencies": [],
    "tags": [{ "uuid": "tag-uuid", "name": "bug" }]
  }
}
DELETE /api/v1/tickets/{uuid} Delete

Required scope: tickets:write

Subtasks

Subtasks have fixed statuses (todo, in_progress, done), independent of project custom statuses. They serve as a technical checklist linked to a ticket.

GET /api/v1/subtasks?ticket_uuid={uuid} List subtasks for a ticket

Required scope: tickets:read

{
  "data": [
    {
      "uuid": "...",
      "title": "Technical task",
      "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 }
}
POST /api/v1/subtasks Create subtask

Required scope: tickets:write

Body

{
  "ticket_uuid": "us-uuid",        // required
  "title": "Technical task",   // required
  "status": "todo",            // optional — todo | in_progress | done (default: todo)
  "assignee_id": 3             // optional
}

Response 201

{
  "data": {
    "uuid": "...", "title": "Technical task", "status": "todo",
    "sort_order": 1, "assignee_id": null, "assignee_name": null,
    "created_at": "...", "updated_at": "..."
  }
}
PUT /api/v1/subtasks/{uuid} Update

Required scope: tickets:write

Body

{
  "title": "...",          // optional
  "status": "in_progress", // optional — todo | in_progress | done
  "assignee_id": 3,        // optional — id or null to unassign
  "sort_order": 2          // optional
}

Response 200

{
  "data": {
    "uuid": "...", "title": "...", "status": "in_progress",
    "sort_order": 2, "assignee_id": 3, "assignee_name": "Alice Martin",
    "created_at": "...", "updated_at": "..."
  }
}
DELETE /api/v1/subtasks/{uuid} Delete

Required scope: tickets:write

Comments

Comments are attached to a ticket. Only the author (or an administrator) can edit or delete their own comments. Content is sanitized HTML (scripts and JS event handlers removed).

GET /api/v1/comments?ticket_uuid={uuid} List comments for a ticket

Required scope: comments:read

ParameterTypeDescription
usstringTicket UUID — required

Response 200

{
  "data": [
    {
      "uuid": "...",
      "author_id": 3,
      "author_name": "Alice Martin",
      "author_initials": "AM",
      "content": "<p>Comment content</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 }
}
GET /api/v1/comments/{uuid} Comment details

Required scope: comments:read

POST /api/v1/comments Create comment

Required scope: comments:write

Body

{
  "ticket_uuid":  "...",                     // required — Ticket UUID
  "content":  "<p>My comment</p>",       // required — Sanitized HTML
  "mentions": [4, 7]                     // optional — Mentioned user IDs
}

Response 201

{
  "data": {
    "uuid": "...",
    "author_id": 3,
    "author_name": "Alice Martin",
    "author_initials": "AM",
    "content": "<p>My comment</p>",
    "mentions": [4],
    "ticket_uuid": "...",
    "created_at": "2026-04-02 10:00:00",
    "updated_at": "2026-04-02 10:00:00"
  }
}
PUT /api/v1/comments/{uuid} Update comment

Required scope: comments:write — author or admin only.

Body

{
  "content":  "<p>Updated content</p>",  // optional
  "mentions": [4, 7]                       // optional — replaces full mention list
}
DELETE /api/v1/comments/{uuid} Delete comment

Required scope: comments:write — author or admin only.

{ "data": { "deleted": true } }

Team

GET /api/v1/team?project={uuid} Project team members

Required scope: 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 = average daily rate (cost/day) of the member on this project, used as the basis for financial indicators; null if unspecified.

Time entries

GET /api/v1/time-entries?project={uuid} List time entries

Required scope: time:read

Optional filter: ?story={uuid} for a specific story.

POST /api/v1/time-entries Log time

Required scope: time:write

Body

{
  "ticket_uuid": "story-uuid",      // required
  "duration_minutes": 90,       // required
  "logged_at": "2026-03-24",    // required, format YYYY-MM-DD
  "comment": "Code review"      // optional
}

Response 201

{
  "data": {
    "uuid": "...",
    "ticket_id": 12,
    "user_id": 3,
    "user_name": "Alice Martin",
    "ticket_uuid": "...",
    "ticket_title": "As a user...",
    "duration_minutes": 90,
    "comment": "Code review",
    "logged_at": "2026-03-24 00:00:00",
    "created_at": "2026-03-24 20:00:00"
  }
}

Statuses

GET /api/v1/statuses?project={uuid} List project statuses

Required scope: statuses:read

Returns all project statuses (default and custom), sorted by sort_order.

Response 200

[
  {
    "key":        "backlog",
    "label":      "Backlog",
    "color":      "#64748b",
    "bg_color":   "#f1f5f9",
    "sort_order": 1,
    "is_done":    false,
    "is_default": true
  },
  {
    "key":        "in_validation",
    "label":      "In Validation",
    "color":      "#7c3aed",
    "bg_color":   "#f5f3ff",
    "sort_order": 7,
    "is_done":    false,
    "is_default": false
  }
]

Dependencies

Finish-to-start links between roadmap items (epic or super-epic). Each node is exposed by its UUID (resolvable via /epics and /super-epics) to reconstruct the graph and compute the critical path client-side.

GET /api/v1/dependencies?project={uuid} List dependencies

Required scope: 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 }
}

Milestones

GET /api/v1/milestones?project={uuid} List dated milestones

Required scope: roadmap:read

{
  "data": [
    { "uuid": "...", "name": "Go-live", "date": "2026-09-30", "color": "#e11d48" }
  ],
  "meta": { "total": 1 }
}

Finance / EVM

Project Earned Value Management (EVM) performance indicators, computed server-side from story points, logged time (× TJM), and the declared BAC (projects.budget).

Indicators depending on budget (bac, pv, ev, cpi, cv, sv, eac, etc, vac, tcpi) evaluate to null as long as no BAC is declared for the project. Progress and cost metrics (ac, engaged_charge, spi, progress_pct, planned_pct) remain calculated.
GET /api/v1/finance?project={uuid} Project EVM indicators

Required scope: finance:read

{
  "data": {
    "project_uuid": "abc-123",
    "bac": 350000.00,          // budget at completion (declared)
    "base_budget": 315000.00,  // BAC − contingency reserve
    "reserve": 35000.00,       // contingency reserve (included in BAC)
    "contingency_pct": 10.00,
    "pv": 326341.95,           // planned value = % planned SP to date × BAC
    "ev": 257455.27,           // earned value  = % completed SP × BAC
    "ac": 186573.75,           // actual cost   = Σ (time ÷ 480) × TJM
    "engaged_charge": 137253.75, // actual cost of unfinished epics
    "cpi": 1.38,               // EV ÷ AC   (> 1 = under budget)
    "spi": 0.79,               // % completed ÷ % planned (> 1 = ahead of schedule)
    "tcpi": 0.57,              // (BAC − EV) ÷ (BAC − AC)
    "eac": 253639.45,          // estimate at completion = BAC ÷ CPI
    "etc": 67065.70,           // estimate to complete = EAC − AC
    "vac": 96360.55,           // variance at completion = BAC − EAC
    "cv": 70881.52,            // cost variance = EV − AC
    "sv": -68886.68,           // schedule variance = (% completed − % planned) × BAC
    "total_sp": 503,
    "done_sp": 370,
    "planned_sp": 469.10,
    "progress_pct": 73.56,     // % completed SP
    "planned_pct": 93.24       // % planned SP to date
  }
}

Portfolio

EVM roll-up across all projects accessible to the API key holder — a single request replacing project-by-project polling. Consolidated indexes are calculated on the sum of values (EV, PV, AC), not an average of ratios.

GET /api/v1/portfolio/finance Multi-project EVM roll-up

Required scope: finance:read

Optional query filter: ?projects=uuid1,uuid2 to target a specific team / program.

{
  "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 across ALL projects (BAC declared or not)
      "engaged_all": 410000.00   // committed charge across all projects
    },
    "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 }
}

Manifst API v1 Documentation · Back to site