Delivery hangs off one chain: a client owns missions, a mission staffs consultants through assignments, and each mission carries a budget you can measure against actuals. This guide walks the whole chain in order.
1. Create a client
POST /clients HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{ "name": "Acme Corp", "status": "customer", "industry": "Manufacturing" }
Returns 201 Created with a ClientResponse. status is prospect or customer (defaults to customer). Keep the returned id.
2. Open a mission
A mission belongs to a client and moves through draft, active, completed, or cancelled.
POST /missions HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"client_id": "0190a1c2-...",
"name": "Apollo",
"start_date": "2026-01-01",
"end_date": "2026-06-30"
}
Returns 201 Created with a MissionResponse. Update it with PUT /missions/{id}, which also takes the status you want to move it to.
3. Assign a consultant
An assignment links a consultant to a mission over a date range, with an optional billing rate. See Manage people to create the consultant.
POST /assignments HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"mission_id": "0190a1c2-...",
"consultant_id": "0190a1c2-...",
"start_date": "2026-01-01",
"billing_rate": "900.00"
}
Returns 201 Created with an AssignmentResponse. status is active, completed, or cancelled. The billing_rate comes back as null for consultant-role callers (see Roles and permissions). An active assignment is what turns a consultant’s status to active and unlocks timesheet lines for them (see Track time).
4. Set the budget
A budget declares the sale mode and planned revenue/cost. Only an admin can set it.
PATCH /missions/{id}/budget HTTP/1.1
Authorization: Bearer <access_token>
Content-Type: application/json
{
"sale_mode": "time_and_materials",
"budget_revenue": "100000.00",
"budget_cost": "60000.00"
}
sale_mode is time_and_materials (default) or fixed_price.
5. Read the budget against actuals
GET /missions/{id}/budget HTTP/1.1
Authorization: Bearer <access_token>
Returns a MissionBudgetResponse that compares plan, actuals, and forecast:
{
"sale_mode": "time_and_materials",
"health": "on_track",
"reasons": [],
"progress_percent": 42.0,
"budget": { "revenue": "100000.00", "cost": "60000.00", "margin": "40000.00" },
"actuals": { "revenue": "41000.00", "cost": "25000.00", "margin": "16000.00" },
"forecast": { "revenue": "98000.00", "cost": "59000.00", "margin": "39000.00" },
"variance": { "revenue": "-2000.00", "cost": "-1000.00", "margin": "-1000.00" },
"days_worked": "46"
}
health is unknown, on_track, at_risk, or over. cost and margin are null for consultant-role callers; revenue is always visible. To compare several missions at once, use GET /kpi/mission-budgets?ids=... (see Read KPIs).
Endpoints at a glance
| Action | Method | Path | Success |
|---|---|---|---|
| Create client | POST | /clients | 201 |
| List / get clients | GET | /clients, /clients/{id} | 200 |
| Create mission | POST | /missions | 201 |
| Update mission | PUT | /missions/{id} | 200 |
| Create assignment | POST | /assignments | 201 |
| Update assignment | PUT | /assignments/{id} | 200 |
| Set budget | PATCH | /missions/{id}/budget | 200 |
| Read budget | GET | /missions/{id}/budget | 200 |
With assignments in place, the day-to-day flows Track time and Manage expenses both attach to the mission.