Master Projects API
A master project groups related projects under one umbrella with a shared client, budget, and timeline. The Master Projects API covers creating and managing master projects, reading their project hierarchy and budget rollup, linking and unlinking sub-projects, and managing dependencies between projects.
Authentication: every endpoint requires an API key. See API Keys & Authentication.
Requests run inside the organisation your key belongs to, and responses use
the standard { "success": true, ... } envelope. Endpoints that create or
change data need project creation or project update access in your
organisation; read endpoints are open to any organisation member.
Master project status is one of draft, active, on_hold, completed,
archived.
GET /api/v1/master-projects
Section titled “GET /api/v1/master-projects”List the master projects in your organisation, with pagination.
Any organisation member can call this.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
| status | string | No | Filter by status. See the valid values above. |
| clientOrganizationId | UUID | No | Only master projects for this client. |
| limit | integer | No | Page size, 1 to 100. Defaults to 50. |
| offset | integer | No | Number of records to skip. Defaults to 0. |
Example request
curl 'https://api.runnit.io/api/v1/master-projects?status=active' \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "masterProjects": [ { "id": "a2c40f11-...", "organizationId": "8c2d41b7-...", "clientOrganizationId": "b91c77e4-...", "name": "Brand Refresh Programme", "description": "All workstreams for the 2026 brand refresh.", "status": "active", "overallBudget": 400000, "budgetCurrency": "AUD", "startDate": "2026-07-01T00:00:00.000Z", "targetCompletionDate": "2026-12-18T00:00:00.000Z", "ownerId": "d3a6f0c1-...", "tags": [], "metadata": {}, "clientName": "Northwind", "ownerName": "Alex Chen", "projectCount": 4, "totalAllocated": 310000, "createdAt": "2026-06-12T00:00:00.000Z", "updatedAt": "2026-07-01T00:00:00.000Z" } ], "pagination": { "total": 6, "limit": 50, "offset": 0, "hasMore": false }}clientOrganizationId, description, overallBudget, the date fields,
clientName, and ownerName can be null or absent. projectCount and
totalAllocated roll up the linked sub-projects.
Errors
400if no active organisation can be resolved for your account, or a query parameter is invalid.
POST /api/v1/master-projects
Section titled “POST /api/v1/master-projects”Create a master project. You become the owner unless you nominate someone else.
Requires project creation access in your organisation.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Master project name. Must not be empty. |
| description | string | No | Longer description. |
| clientOrganizationId | UUID | No | Client the programme is for. |
| overallBudget | number | No | Total budget across all sub-projects. |
| budgetCurrency | string | No | Currency code. |
| startDate | ISO 8601 date | No | Planned start. |
| targetCompletionDate | ISO 8601 date | No | Target delivery date. |
| ownerId | UUID | No | Owner. Defaults to you. |
| tags | array of strings | No | Tag list. |
| metadata | object | No | Free-form metadata. |
Example request
curl -X POST https://api.runnit.io/api/v1/master-projects \ -H 'Authorization: Bearer rnk_your_key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Brand Refresh Programme", "clientOrganizationId": "<client-uuid>", "overallBudget": 400000, "budgetCurrency": "AUD" }'Response
Returns 201 with the created master project:
{ "success": true, "masterProject": { "id": "a2c40f11-...", "name": "Brand Refresh Programme", "status": "draft" } }Errors
400ifnameis missing or empty, or a field fails validation.400if no active organisation can be resolved for your account.
GET /api/v1/master-projects/:id
Section titled “GET /api/v1/master-projects/:id”Get a master project by ID, including its client name, owner name, project count, and total allocated budget.
Any organisation member can call this.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Example request
curl https://api.runnit.io/api/v1/master-projects/<master-project-id> \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "masterProject": { "id": "a2c40f11-...", "name": "Brand Refresh Programme", "projectCount": 4, "totalAllocated": 310000 } }The object has the same shape as in the list response.
Errors
400ifidis not a UUID.404if the master project does not exist.
PATCH /api/v1/master-projects/:id
Section titled “PATCH /api/v1/master-projects/:id”Update a master project. Send only the fields you want to change.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Request body (all optional)
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | No | New name. Must not be empty. |
| description | string | No | Description text. |
| status | string | No | One of draft, active, on_hold, completed, archived. |
| clientOrganizationId | UUID | No | Client to link. |
| overallBudget | number | No | Total budget. |
| budgetCurrency | string | No | Currency code. |
| startDate | ISO 8601 date | No | Planned start. |
| targetCompletionDate | ISO 8601 date | No | Target delivery date. |
| actualCompletionDate | ISO 8601 date | No | Actual completion date. |
| ownerId | UUID | No | New owner. |
| tags | array of strings | No | Replaces the tag list. |
| metadata | object | No | Replaces the metadata object. |
Example request
curl -X PATCH https://api.runnit.io/api/v1/master-projects/<master-project-id> \ -H 'Authorization: Bearer rnk_your_key' \ -H 'Content-Type: application/json' \ -d '{ "status": "active", "overallBudget": 450000 }'Response
{ "success": true, "masterProject": { "id": "a2c40f11-...", "status": "active", "overallBudget": 450000 } }Errors
400if a field fails validation.404if the master project does not exist.
DELETE /api/v1/master-projects/:id
Section titled “DELETE /api/v1/master-projects/:id”Delete a master project. This removes the grouping only; the linked projects themselves are not deleted.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Example request
curl -X DELETE https://api.runnit.io/api/v1/master-projects/<master-project-id> \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true }Errors
400ifidis not a UUID.404if the master project does not exist.
GET /api/v1/master-projects/:id/hierarchy
Section titled “GET /api/v1/master-projects/:id/hierarchy”Get the full project tree under a master project: top-level sub-projects and their nested child projects, ordered by depth then name.
Any organisation member can call this.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Example request
curl https://api.runnit.io/api/v1/master-projects/<master-project-id>/hierarchy \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "projects": [ { "id": "1f0e9a52-...", "name": "Winter Launch", "status": "active", "stage": "planning", "budget": 75000, "budgetCurrency": "AUD", "parentProjectId": null, "depth": 0, "startDate": "2026-07-01T00:00:00.000Z", "targetCompletionDate": "2026-08-31T00:00:00.000Z", "jobNumber": "RB-2026-014", "color": "matcha" } ]}The list is flat: rebuild the tree using parentProjectId and depth.
Top-level sub-projects have no parent. budget, color, and the date fields
can be null or absent.
Errors
400ifidis not a UUID.404if the master project does not exist.
GET /api/v1/master-projects/:id/budget
Section titled “GET /api/v1/master-projects/:id/budget”Get the budget rollup for a master project: the overall budget, how much has been allocated to sub-projects, how much has been spent, and a per-project breakdown.
Any organisation member can call this.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Example request
curl https://api.runnit.io/api/v1/master-projects/<master-project-id>/budget \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "budgetSummary": { "masterProjectId": "a2c40f11-...", "overallBudget": 400000, "budgetCurrency": "AUD", "totalAllocated": 310000, "totalSpent": 122400, "remaining": 90000, "projectCount": 4, "projectBreakdown": [ { "projectId": "1f0e9a52-...", "projectName": "Winter Launch", "budget": 75000, "spent": 31200, "depth": 0, "parentProjectId": null } ] }}overallBudget and remaining can be absent when the master project has no
overall budget set. A breakdown entry’s budget can also be absent.
Errors
400ifidis not a UUID.404if the master project does not exist.
GET /api/v1/master-projects/:id/dependencies
Section titled “GET /api/v1/master-projects/:id/dependencies”List the dependencies between projects inside a master project.
Any organisation member can call this.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Example request
curl https://api.runnit.io/api/v1/master-projects/<master-project-id>/dependencies \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "dependencies": [ { "id": "5c8b02de-...", "projectId": "63f1aa20-...", "dependsOnProjectId": "1f0e9a52-...", "dependencyType": "finish_to_start", "isBlocking": true } ]}Errors
400ifidis not a UUID.
POST /api/v1/master-projects/:id/dependencies
Section titled “POST /api/v1/master-projects/:id/dependencies”Add a dependency between two projects.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| projectId | UUID | Yes | The project that depends on another. |
| dependsOnProjectId | UUID | Yes | The project it depends on. |
| dependencyType | string | No | finish_to_start, finish_to_finish, or start_to_start. |
| isBlocking | boolean | No | Whether the dependency blocks the dependent project. |
Example request
curl -X POST https://api.runnit.io/api/v1/master-projects/<master-project-id>/dependencies \ -H 'Authorization: Bearer rnk_your_key' \ -H 'Content-Type: application/json' \ -d '{ "projectId": "<dependent-project-uuid>", "dependsOnProjectId": "<prerequisite-project-uuid>", "dependencyType": "finish_to_start", "isBlocking": true }'Response
Returns 201 with the created dependency:
{ "success": true, "dependency": { "id": "5c8b02de-...", "dependencyType": "finish_to_start", "isBlocking": true } }Errors
400if either project ID is not a UUID or the dependency type is invalid.400if the dependency would create a circular reference.404if either project does not exist.409if the dependency already exists.
DELETE /api/v1/master-projects/:id/dependencies/:dependencyId
Section titled “DELETE /api/v1/master-projects/:id/dependencies/:dependencyId”Remove a project dependency.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
| dependencyId | UUID | Yes | Dependency ID. |
Example request
curl -X DELETE https://api.runnit.io/api/v1/master-projects/<master-project-id>/dependencies/<dependency-id> \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true }Errors
400if either ID is not a UUID.
POST /api/v1/master-projects/:id/projects/link
Section titled “POST /api/v1/master-projects/:id/projects/link”Link an existing project to a master project as a sub-project.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| projectId | UUID | Yes | The project to link. Must belong to the same organisation and must not already belong to another master project. |
Example request
curl -X POST https://api.runnit.io/api/v1/master-projects/<master-project-id>/projects/link \ -H 'Authorization: Bearer rnk_your_key' \ -H 'Content-Type: application/json' \ -d '{ "projectId": "<project-uuid>" }'Response
{ "success": true, "project": { "id": "1f0e9a52-...", "masterProjectId": "a2c40f11-..." } }Errors
400if the project belongs to a different organisation.404if the master project or project does not exist.409if the project is already linked to another master project.
POST /api/v1/master-projects/:id/projects
Section titled “POST /api/v1/master-projects/:id/projects”Create a new draft project and link it to the master project in one step. The new project inherits the master project’s client and currency when you do not supply them.
Requires project creation access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
Request body
| Name | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Project name. Must not be empty. |
| description | string | No | Longer description. |
| clientOrganizationId | UUID or null | No | Client override. Defaults to the master project’s client. Null creates an internal project. |
| budget | number or null | No | Project budget. |
| budgetCurrency | string | No | Currency code. Defaults to the master project’s currency, then AUD. |
| startDate | ISO 8601 date or null | No | Planned start. |
| targetCompletionDate | ISO 8601 date or null | No | Target delivery date. |
| jobNumber | string | No | 1 to 100 characters. Runnit generates one if omitted. |
| color | string | No | Project colour key: guava, mandarin, matcha, acai, coffee, or their -dark variants. |
Example request
curl -X POST https://api.runnit.io/api/v1/master-projects/<master-project-id>/projects \ -H 'Authorization: Bearer rnk_your_key' \ -H 'Content-Type: application/json' \ -d '{ "name": "Social Cutdowns", "description": "Create platform variants.", "budget": 12000, "startDate": "2026-07-20", "targetCompletionDate": "2026-08-05" }'Response
Returns 201 with the created project:
{ "success": true, "project": { "id": "63f1aa20-...", "name": "Social Cutdowns", "status": "draft", "masterProjectId": "a2c40f11-..." } }Errors
400ifnameis missing or empty, or a field fails validation.404if the master project does not exist.
DELETE /api/v1/master-projects/:id/projects/:projectId
Section titled “DELETE /api/v1/master-projects/:id/projects/:projectId”Unlink a project from a master project. The project itself is not deleted; it just stops being a sub-project.
Requires project update access in your organisation.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| id | UUID | Yes | Master project ID. |
| projectId | UUID | Yes | Project to unlink. Must currently be linked to this master project. |
Example request
curl -X DELETE https://api.runnit.io/api/v1/master-projects/<master-project-id>/projects/<project-id> \ -H 'Authorization: Bearer rnk_your_key'Response
{ "success": true, "project": { "id": "1f0e9a52-...", "masterProjectId": null } }Errors
400if the project is not linked to this master project.404if the project does not exist.
Next steps
Section titled “Next steps”Manage the sub-projects themselves through the Projects API.