The DSAR API handles data subject access requests for GDPR, CCPA, and other privacy regulations. Requests are processed asynchronously via a background job queue. Admin only.
GET /api/v1/dsar
List DSAR requests for the tenant.
Query Parameters
| Parameter | Type | Required | Description |
|---|
status | string | No | Filter by status: queued, processing, completed, failed |
limit | number | No | Max results (default: 50, max: 200) |
Response
{
"requests": [
{
"id": "clx...",
"tenantId": "my-tenant",
"requestType": "export",
"subjectId": "C-1234",
"subjectType": "customer_id",
"requestedBy": "admin@example.com",
"status": "completed",
"requestedAt": "2026-03-18T10:00:00.000Z",
"completedAt": "2026-03-18T10:02:30.000Z"
}
],
"count": 1
}
POST /api/v1/dsar
Create and enqueue a DSAR request. Returns 202 Accepted — the request is processed asynchronously. Rate limited to 10 requests/min. Admin only.
Request Body
| Field | Type | Required | Description |
|---|
requestType | string | Yes | Request type: export or delete |
subjectId | string | Yes | Customer ID or email of the data subject |
subjectType | string | No | Identifier type: customer_id or email (default: customer_id) |
Example
curl -X POST https://playground.kaireonai.com/api/v1/dsar \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: my-tenant" \
-H "X-User-Role: admin" \
-d '{
"requestType": "delete",
"subjectId": "C-1234",
"subjectType": "customer_id"
}'
Response (202)
{
"requestId": "clx...",
"status": "queued"
}
Poll GET /api/v1/dsar?status=completed to check when the request finishes processing.
Once the status is completed, download the export payload with GET /api/v1/dsar/{id}/download.
GET /api/v1/dsar//download
Download the portable export payload for a completed DSAR export request. Admin only.
Returns the persisted JSON payload as a file attachment (Content-Disposition: attachment; filename="dsar-export-{subjectId}-{date}.json").
This endpoint is only available for requests with requestType = "export". Calling it on a delete request returns 404 with detail "Download is only available for export requests".
Path Parameters
| Parameter | Type | Required | Description |
|---|
id | string | Yes | DSAR request ID |
Response (200)
The response body is the full export JSON payload. Headers:
| Header | Value | When |
|---|
Content-Type | application/json | Always |
Content-Disposition | attachment; filename="dsar-export-{subjectId}-{date}.json" | Always |
X-Kaireon-Payload-Encrypted | true | When the export was created with options.encrypt = true. The payload body is { ciphertext: string, format: "encrypted-aes-256-gcm" } and must be decrypted by the caller before consuming it as structured data. |
Error responses
| Status | Detail string | Cause |
|---|
404 | "DSAR request not found" | The request id does not exist, or it belongs to another tenant |
404 | "Download is only available for export requests" | The request’s requestType is not "export" |
404 | "export payload is no longer stored — it may predate deliverable storage (F10) or have aged past the retention window; re-run the export" | No payload is stored — either the export predates deliverable storage (created before 2026-06-07, migration 28) or it has aged past the retention window. Re-run the export to generate a fresh downloadable payload. |
How exports age out
Export payloads are stored in the dsar_exports table and age out on the decisions retention class (configurable per tenant in Settings → Retention). DsarRequest rows are never purged — only the payload in dsar_exports is removed by the GET /api/v1/cron/dsar-purge cron. After purge, the download endpoint returns the 404 detail above and the export must be re-run.
Exports work in both the in-process (single-instance) and worker-mode deployment configurations.
Exports completed before 2026-06-07 (migration 28) were not persisted to dsar_exports — they are not downloadable. Re-run the export from the DSAR queue to get a downloadable payload.