Skip to main content

Delete a sub-project

MethodPath
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​

NameTypeRequiredDescription
subProjectIdstringYesId 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 409 and the error project_not_empty, and nothing is changed, when the project still holds a Patient, a Device or a Location, or is the parent of another project. The 409 body gives the number of each type in counts and the ids of the sub-projects in childProjectIds. 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 (Provenance and AuditEvent) are kept.
  • Only Patient, Device and Location are 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 502 with the error signals_tenant_revoke_failed. Send the same request again to finish the revoke. After a 200, the same request answers 404.
  • If the project's Signals credentials cannot be read, the route answers 503 and nothing is changed. Retry shortly.
  • Two deletes of the same project cannot run at once. The second answers 409 until the first ends.
  • The result of GET /v1/sub-project is refreshed at once, instead of waiting for its 5 minute limit.
  • DELETE /v1/slim/project/child/:subProjectId runs 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 }
FieldTypeDescription
successbooleanAlways true.

Errors​

StatusMeaning
401Bearer token is missing, invalid, revoked or expired, or the session carries no project.
403The caller is not an admin of the project in the token.
404No project with this id is a direct child of your project. It also answers after a delete that already finished.
409The 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.
429Too many requests. Retry after a short wait.
502The project was deleted, but its Signals tenant could not be revoked (signals_tenant_revoke_failed). Send the same request again to finish.
503The 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": []
}