> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# DSAR (Data Subject Access Requests)

> GDPR/CCPA data subject access request management — export or delete customer data.

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

```json theme={null}
{
  "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

```bash theme={null}
curl -X POST https://playground.kaireonai.com/api/v1/dsar \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{
    "requestType": "delete",
    "subjectId": "C-1234",
    "subjectType": "customer_id"
  }'
```

### Response (202)

```json theme={null}
{
  "requestId": "clx...",
  "status": "queued"
}
```

<Tip>
  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`.
</Tip>

<Note>
  A `delete` request runs the same erasure path as [GDPR Erasure](/api-reference/gdpr-erasure) (`eraseSubjectData`). It removes the full category set — interaction history, interaction summaries, suppressions, decision traces, attribution results, variant assignments, identity links, journey enrollments, channel deliveries, stored DSAR export payloads, and customer-type dynamic schema rows. The `DsarRequest` row, `ConsentRecord` history, and hash-chained audit log are deliberately retained as legal-obligation proof.
</Note>

***

## GET /api/v1/dsar/{id}/download

Download the portable export payload for a completed DSAR export request. **Admin only.**

Returns the persisted export as a plain JSON file attachment (`Content-Disposition: attachment; filename="dsar-export-{subjectId}-{date}.json"`).

<Note>
  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"`.
</Note>

<Note>
  **Encrypted at rest, decrypted on download (SOC 2 Phase 0).** `dsar_exports.payload` is encrypted (AES-256-GCM) at rest by default — every DSAR export generated by the worker (`WORKER_INPROCESS=1`), the `drain-queues` cron path, and the Shopify `customers/data_request` GDPR webhook persists a `{ ciphertext, format: "encrypted-aes-256-gcm" }` envelope, not plaintext PII. This endpoint decrypts server-side (the caller already passed the admin-role + tenant-scope check above) and always returns plain JSON — there is no client-side decryption step, and the `X-Kaireon-Payload-Encrypted` response header has been removed since it no longer describes anything the caller needs to act on. Exports persisted before this change (plain JSON) are served unchanged.
</Note>

### Path Parameters

| Parameter | Type   | Required | Description     |
| --------- | ------ | -------- | --------------- |
| `id`      | string | Yes      | DSAR request ID |

### Response (200)

The response body is always the plain export JSON (decrypted server-side if the stored payload was encrypted). Headers:

| Header                | Value                                                        | When   |
| --------------------- | ------------------------------------------------------------ | ------ |
| `Content-Type`        | `application/json`                                           | Always |
| `Content-Disposition` | `attachment; filename="dsar-export-{subjectId}-{date}.json"` | Always |

### 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.

<Warning>
  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.
</Warning>
