
# Import consent records

`POST /v1/jobs/consent-imports` · permission `consent-records:write`

Imports acceptances of your legal documents that were recorded in another system, for example when you move users to KeenAuth. The request is synchronous: 1–500 records are written in one transaction, so either all of them are written or none is. Every imported record has `method = import`, and `occurred_at` keeps the time from the source system. The version, content hash and locale are taken from the document; you cannot supply them. Imported records are append-only like every other consent record. To record a single acceptance obtained now, use [Record a consent](/docs/api/management/users/create-consent-record).

`Idempotency-Key` is required. A retry with the same key and request returns the same response (with `Idempotent-Replayed: true`) and writes nothing a second time.

## Request

JSON body (unknown fields are rejected with `400 unknown_field`):

| Field | Type | Required | Description |
|---|---|---|---|
| `records` | object[] | yes | 1–500 records, written in this order. |
| `records[].user_id` | string | yes | User ID (`usr_…`). |
| `records[].subject_type` | string | yes | Only `document`. |
| `records[].subject_id` | string | yes | Legal document ID (`ldoc_…`). |
| `records[].state` | string | yes | `presented`, `accepted` or `declined`. |
| `records[].application_id` | string \| null | no | Application (`app_…`); when omitted and the document is application-specific, the document's application is recorded. |
| `records[].occurred_at` | string (date-time) | yes | When it happened in the source system; not in the future. |

## Response

`201 Created` with the written records (`records`), in input order.

```json
{
  "imported_count": 1,
  "records": [
    {
      "id": "crec_01j9xk3m7q8r2s4t6v8w0y2z4b",
      "user_id": "usr_01j9xk3m7q8r2s4t6v8w0y2z4c",
      "subject_type": "document",
      "subject_id": "ldoc_01j9xk3m7q8r2s4t6v8w0y2z4a",
      "subject_version": "2026-10",
      "content_sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "locale": "en",
      "state": "accepted",
      "method": "import",
      "application_id": null,
      "occurred_at": "2025-03-14T08:00:00Z"
    }
  ]
}
```

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `malformed_request`, `unknown_field` | The `Idempotency-Key` header is missing or malformed, the body is not valid JSON, or it has an unknown field. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 413 | `payload_too_large` | The body is larger than 1 MiB. |
| 415 | `unsupported_media_type` | The content type is not `application/json`. |
| 422 | `validation_failed` | A record is invalid; `errors[].pointer` is `/records/<index>/<field>`. An unknown user is `unknown_user`, an unknown application `unknown_application`, an unknown document `unknown_subject`; fewer than 1 or more than 500 records is `out_of_range` at `/records`. Nothing is written. |
| 422 | `idempotency_key_reuse` | The `Idempotency-Key` was used with a different request. |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl -X POST https://api.eu.keenauth.com/v1/jobs/consent-imports \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"records":[{"user_id":"usr_01j9xk3m7q8r2s4t6v8w0y2z4c","subject_type":"document","subject_id":"ldoc_01j9xk3m7q8r2s4t6v8w0y2z4a","state":"accepted","occurred_at":"2025-03-14T08:00:00Z"}]}'
```

CLI: `keenauth jobs consent-imports create --data records.json`

## Personal data

This endpoint carries personal data: consent records. [Personal data in the KeenAuth APIs](/docs/policies/personal-data) describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.
