Skip to main content
POST
Purge subject or organization data (two-phase)
Two-phase purge. Phase 1 (dryRun, the default) counts and mints a confirmToken; phase 2 (dryRun: false + that token) deletes. Scope subject erases one provisioned subject completely (the GDPR path). Scope org empties the organization’s knowledge graph but keeps the organization, its users and its API keys: use DELETE /v1/me to delete the account itself. A confirmed purge also deletes the stored files behind the rows it removes: uploaded imports and finished export documents at both scopes, and at org scope the trained ExoBrain as well, since it is derived from the graph being emptied. Retrieval then falls back to the live rows until the org retrains. Admin scope. Not replayable by Idempotency-Key: a repeated confirm must present a valid, unexpired (5 minute) token bound to this org, scope, subject, admin and the impact the dry run reported. If new data has landed since that dry run the confirm is refused with 409 purge_impact_changed and nothing is deleted — re-run the dry run, review the new impact, confirm with the fresh token.

Authorization

This route requires the admin scope. A missing or invalid credential returns 401 authentication_error. A valid credential without the scope returns 403 permission_denied, and the problem body names the exact scope required.

Headers

These are request conventions the contract does not declare as parameters, so they do not appear in the schema tables below.

Success responses

Errors

Beyond the shared statuses, this route can answer with purge_impact_changed. Every problem body names its own code, and the type URI always resolves to the matching page. Every error is an RFC 9457 application/problem+json body carrying a stable code, a requestId, and a suggestedAction where Exo has one. See Errors.

Notes

  • Two phases, and the first one is the default. dryRun true counts the impact and mints a confirmToken. dryRun false with that token deletes.
  • The token expires and the impact is re-checked. If the data has changed since the dry run, the confirm is refused with 409 purge_impact_changed and nothing is deleted.
  • scope: "org" empties the graph but keeps the organization, its users and its keys. To delete the account itself, use DELETE /v1/me.
  • A confirmed purge also deletes stored files: uploaded imports and finished export documents at both scopes, plus the trained brain at organization scope, because it is derived from the graph being emptied.

Authorizations

X-Exo-API-Key
string
header
required

An Exo API key (exo_...) sent as the X-Exo-API-Key header.

Body

application/json

Body of POST /v1/purge.

subjectId is the OBJECT of the call, not a subject selector (this family runs without the subject seam, exactly like /v1/subjects), which is why it is not named subject.

scope
enum<string>
required
Available options:
subject,
org
confirmToken
string | null

The confirmToken from the dry run. Required when dryRun is false.

Maximum string length: 4096
dryRun
boolean
default:true

Default true: count the impact and mint a confirmToken, delete nothing.

subjectId
string | null

Subject to erase. Required for scope=subject, rejected for scope=org.

Maximum string length: 128

Response

Successful Response

Both phases of the ceremony share one shape.

Phase 1 fills confirmToken/expiresAt; phase 2 fills purgedAt and reports ACTUAL per-table deleted counts under the same counts keys. Zero-row tables are omitted from counts so the payload stays readable; totalRows is the sum of everything reported.

counts
Counts · object
required
dryRun
boolean
required
requestId
string
required
scope
string
required
totalRows
integer
required
confirmToken
string | null
expiresAt
string<date-time> | null
preserved
Preserved · object | null
purgedAt
string<date-time> | null
skipped
string[] | null

Tables this purge could not clear (absent from an older schema, or blocked by a foreign key). Present only when non-empty: a purge that left rows behind must never look identical to one that had none.

subjectId
string | null