Delete a sub-project
| Method | Path |
|---|---|
DELETE | /v1/sub-project/:subProjectId |
Authentication · Access policies · Projects
Deletes a direct sub-project of your current project, together with the setup Ovok created for it. Use it to remove a project you no longer need. The project must be empty.
The same route also answers at /sub-project/:subProjectId, without /v1.
Auth: Bearer token of a project admin, meaning the membership of the caller in the token's project is an admin one.
Scope: subProjectId must be a direct child of the caller's project (from the token). You cannot delete your own project, a grandchild, or a project that is not below yours.
Request
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
subProjectId | string | Yes | Id of the sub-project to delete. It is not checked as a UUID: an id that is not a direct child of your project answers 404. |
Behaviour
- The project must be empty. It is refused with
409and the errorproject_not_empty, and nothing is changed, when the project still holds aPatient, aDeviceor aLocation, or is the parent of another project. The409body gives the number of each type incountsand the ids of the sub-projects inchildProjectIds. Move or delete those first. Delete the children of a project before the project itself. - When the project is empty, Ovok unlinks it from your project and then deletes, in one all-or-nothing write, its project memberships, Practitioners, AccessPolicies, PlanDefinitions, ClientApplications, Organizations and tenant code. It then deletes the project, revokes its Signals tenant, and finally deletes the parent-child record.
- The project's own access policies are deleted with it. Nothing is copied back to your project.
- User accounts are never deleted: a user can belong to other projects. Audit records (
ProvenanceandAuditEvent) are kept. - Only
Patient,DeviceandLocationare counted. The route does not check for other kinds of data. - The delete is safe to retry. If the Signals tenant cannot be revoked, the project is already deleted and the route answers
502with the errorsignals_tenant_revoke_failed. Send the same request again to finish the revoke. After a200, the same request answers404. - If the project's Signals credentials cannot be read, the route answers
503and nothing is changed. Retry shortly. - Two deletes of the same project cannot run at once. The second answers
409until the first ends. - The result of
GET /v1/sub-projectis refreshed at once, instead of waiting for its 5 minute limit. DELETE /v1/slim/project/child/:subProjectIdruns the same delete.- No access policy permission is checked beyond the admin role.
Example
curl -X DELETE 'https://api.sandbox.ovok.com/v1/sub-project/8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54' \
-H "Authorization: Bearer ${OVOK_TOKEN}"
Successful response
200 — The sub-project was deleted.
{ "success": true }
| Field | Type | Description |
|---|---|---|
success | boolean | Always true. |
Errors
| Status | Meaning |
|---|---|
401 | Bearer token is missing, invalid, revoked or expired, or the session carries no project. |
403 | The caller is not an admin of the project in the token. |
404 | No project with this id is a direct child of your project. It also answers after a delete that already finished. |
409 | The project still holds a Patient, Device or Location, or has sub-projects (project_not_empty). Or another delete of it, or another write to the parent's project links, holds the lock. Nothing was changed. |
429 | Too many requests. Retry after a short wait. |
502 | The project was deleted, but its Signals tenant could not be revoked (signals_tenant_revoke_failed). Send the same request again to finish. |
503 | The project's Signals credentials cannot be read. Nothing was changed. Retry shortly. |
A 409 for a project that is not empty has this shape. The text in message lists only the types that are present.
{
"statusCode": 409,
"error": "project_not_empty",
"timestamp": "2026-10-09T08:53:20.000Z",
"path": "/v1/sub-project/8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54",
"message": "2 Patient, 1 Device still in this project",
"requestId": "5f0e3a6b-2c1d-4e87-9a3b-7d6c5b4a3f21",
"subProjectId": "8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54",
"counts": { "Patient": 2, "Device": 1, "Location": 0 },
"childProjectIds": []
}