Grant consent

View as Markdown
Records that a contact granted one type of consent (`voice_call`, `email` or `data_processing`). The contact's previous `granted` record of the same type, if any, is marked `revoked` in the same transaction, so a contact has at most one active grant per type. The history is kept: read it with `GET /api/compliance/consent/{contactId}` and test it with `GET /api/compliance/consent/check/{contactId}/{consentType}`. `contactId` is **not** checked against existing contacts, so a mistyped id records consent for a contact that does not exist. The request's source IP is stored in `ip_address`. For a server-to-server API call, that is your server's IP, not the end customer's. Put the customer's proof in `evidence`. A `voice_call` grant matters when the workspace setting *require consent before calling* is on. The campaign dialer then skips any contact without an active, unexpired `voice_call` grant. **Side effects.** Writes a consent record. Evicts the contact's cached consent check and history. Writes an audit entry (`grant_consent`, with `consentType` and `source`). No provider calls, no messages. **Idempotency.** Safe to retry in effect: each retry revokes the previous grant and inserts a new one, so one active grant remains. Each retry does add one more `revoked` row to the history. **Access** - **Required scope:** `full`. Signed-in users need the `owner` or `admin` role. - **Rate limit:** General API — 120 (Starter), 200 (Growth), 300 (Business) or 600 (Enterprise) requests/min per workspace. See [Rate limits](/rate-limits). - **Plan:** Available on every plan.

Authentication

AuthorizationBearer
Workspace API key: `jl_` followed by 64 lowercase hex characters, created by the workspace owner in the dashboard (**Settings → API Keys**) and sent as `Authorization: Bearer jl_...`. The plaintext is shown once, at creation; Jelliu stores only a SHA-256 hash. A workspace can hold up to 25 active keys. | Scope | GET / HEAD | POST / PUT / PATCH / DELETE | Admin-only routes | | --- | --- | --- | --- | | `read` | Yes | No | No | | `write` | Yes | Yes | No | | `full` | Yes | Yes | Yes | Operations restricted to admins or owners reject keys without the `full` scope with `403`, and say so in their description. No key, whatever its scope, can mint or revoke API keys or rotate a webhook secret — that requires a signed-in owner session. A revoked key stops authenticating within about 10 seconds. See [Authentication](/authentication).

Request

This endpoint expects an object.
contactIdstringRequiredformat: "uuid"
The contact the consent belongs to. Not checked for existence.
consentTypeenumRequired
What the contact agreed to. - `voice_call`: being called by phone, including by an AI voice agent. - `email`: receiving commercial email. - `data_processing`: having personal data stored and processed at all.
Allowed values:
sourcestringRequired1-255 characters

Where the consent was captured, as free text, e.g. web_form, ivr, verbal, whatsapp_optin.

evidencestringOptional<=2000 characters

A reference to the proof, e.g. a form submission id, a recording URL or a signed-document id.

expiresAtdatetimeOptional

When the consent stops counting, as an ISO 8601 UTC datetime with the Z suffix. Offsets such as -05:00 fail validation. Omit it for consent that does not expire.

Response

Consent recorded.
dataobject

Errors

400
Bad Request Error
401
Unauthorized Error
403
Forbidden Error
429
Too Many Requests Error