---
title: "Record CASL consent for up to 5,000 phone numbers"
method: POST
path: "/v1/compliance/consents/batch"
tags: ["Compliance / CASL"]
---

# Record CASL consent for up to 5,000 phone numbers

`POST /v1/compliance/consents/batch`

## Request

- Base URL: `https://api.honkio.ca`
- URL: `https://api.honkio.ca/v1/compliance/consents/batch`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Each row is `defaults` with the row's own fields on top. Every row gets its own outcome: recorded, invalid, duplicate_in_file (the number appeared on an earlier row), opted_out (the number has opted out; never re-consented by an upload), revoked_by_review (HonkIO revoked the number's consent on review of an earlier upload; it cannot be recorded again unless HonkIO lifts the block) or already_recorded (an active consent at least as strong exists, so re-sending a file records nothing twice). The upload is kept as a consent batch (GET /v1/compliance/consent-batches). SMS only.

Requires `compliance:w`.

## Request body

- object
  - `defaults` object, required: The fields every row starts from.
    - `consent_type` 'express' | 'implied', required
    - `source_description` string
    - `source_ip` string
    - `source_url` string
    - `relationship_type` string
    - `last_transaction_date` string
    - `expires_at` string, nullable
  - `rows` object[], required: 1 to 5,000 rows; each row's fields override the defaults.
    - `phone_number` string, required
    - `consent_type` string: express or implied; any other value makes that row invalid.
    - `source_description` string
    - `source_ip` string
    - `source_url` string
    - `relationship_type` string
    - `last_transaction_date` string
    - `expires_at` string, nullable
  - `file_name` string: The uploaded file's name, kept on the batch.
  - `attested` boolean: The uploader confirms these people gave this consent or have this relationship. Recorded on the batch.

## Response `200`

Every row's outcome, in the order sent, and the counts. Partial success is normal: only a request that is wrong as a whole is refused.

- object: Every row's outcome, in the order sent, and the counts. Partial success is normal: only a request that is wrong as a whole is refused.
  - `batch_id` string, required: cb_…
  - `counts` object, required
    - `rows` integer, required
    - `recorded` integer, required
    - `express` integer, required
    - `implied` integer, required
    - `already_recorded` integer, required
    - `opted_out` integer, required
    - `revoked_by_review` integer, required
    - `duplicate_in_file` integer, required
    - `invalid` integer, required
  - `results` object[], required
    - `row` integer, required: Index into rows.
    - `phone_number` string, required: E.164, or the input as sent when it did not parse.
    - `status` 'recorded' | 'invalid' | 'duplicate_in_file' | 'opted_out' | 'revoked_by_review' | 'already_recorded', required
    - `reason` string: Present on invalid rows (the field and what is wrong with it) and on revoked_by_review rows.
    - `consent_type` 'express' | 'implied': Present on recorded rows.
    - `expires_at` string, nullable: Present on recorded rows; null for express.

## Other responses

- `401`: Missing, invalid, revoked or expired API key.
- `402`: The account has no balance, or a LIVE key was used before the first top-up.
- `403`: The API key lacks the permission this operation requires, or the account is suspended or closed.
- `422`: VALIDATION_ERROR: rows empty or over 5,000, or defaults wrong in themselves (unknown consent_type, an unparseable date, expires_at with express).
- `429`: Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/honkio/apis/honkio-api.md) · [All operations](https://skmtc.dev/honkio/apis/honkio-api/llms.txt) · [OpenAPI document](https://skmtc.dev/honkio/apis/honkio-api/revisions/ce4ed3fe9691?raw)
