GRANTED consent returns a 422.
The consent object
The channel this consent applies to:
EMAIL, RCS, or SMS.The send type this consent covers:
MESSAGE (action-based) or NEWSLETTER (subscription).Overall consent state.
When
| Value | Meaning |
|---|---|
GRANTED | Consent is active — sends are permitted |
REVOKED | Consent was withdrawn — sends are blocked |
PENDING | Single opt-in recorded but DOI confirmation not yet completed |
enforced_doi: true, status only transitions to GRANTED after doi_status reaches DOI_ACCEPTED.Where the consent signal came from (e.g.
landing_page, api, checkout, crm_sync). Free-form string for your audit reference.Human-readable description of the consent event — form URL, checkbox label, email subject. Stored for GDPR audit. Max 5,000 characters.
Whether Double Opt-In confirmation is required before this consent becomes
GRANTED.false(default) — single opt-in. Status moves directly toGRANTEDon creation.true— DOI required. Status staysPENDINGuntil the contact confirms, at which point it advances toGRANTEDanddoi_statusis set toDOI_ACCEPTED.
Current DOI confirmation state.
null when enforced_doi is false.| Value | Meaning |
|---|---|
DOI_SEND | DOI confirmation message has been sent to the contact via doi_channel |
DOI_ACCEPTED | Contact clicked the confirmation link — consent is now GRANTED |
The channel used to deliver the DOI confirmation message:
EMAIL, RCS, or SMS. null when enforced_doi is false.ISO 8601 timestamp when consent was granted (for DOI flows, this stamps when
DOI_ACCEPTED is reached). null while PENDING.ISO 8601 timestamp when consent was revoked.
null if still active.DOI lifecycle
Whenenforced_doi: true, consent follows a two-step confirmation process:
GRANTED consent unlocks message sends. A contact in PENDING state cannot receive NEWSLETTER sends.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /v1/contacts/{id}/consent | List all consent records for a contact |
POST | /v1/contacts/{id}/consent | Create or update consent |
DELETE | /v1/contacts/{id}/consent/{record_id} | Revoke a specific consent record |
GET /v1/contacts//consent
Returns all consent records for a contact across all channels and message types.Bearer <api_key>Contact ID.
- 200 OK
- 404 Not found
POST /v1/contacts//consent
Creates or updates consent for a specific channel and message type. If a record for that combination already exists it is upserted.Bearer <api_key>Contact ID.
Channel to grant consent for:
EMAIL, RCS, or SMS.Send type to grant consent for:
MESSAGE or NEWSLETTER.GRANTED (single opt-in) or PENDING (start a DOI flow). When enforced_doi: true, always pass PENDING — the platform advances to GRANTED after confirmation.Where consent was collected (e.g.
"landing_page", "checkout", "crm_sync").Human-readable audit description. Include the form URL and checkbox label text. Max 5,000 characters.
Set to
true to require Double Opt-In confirmation before consent becomes GRANTED. When enabled, the platform sends a confirmation message to the contact via doi_channel and sets doi_status: DOI_SEND.Required when
enforced_doi: true. Channel used to deliver the DOI confirmation message: EMAIL, RCS, or SMS. The contact must have a verified address on this channel.- Single opt-in (no DOI)
- Double opt-in (DOI)
Consent is immediately
GRANTED.- 201 Created — single opt-in
- 201 Created — DOI initiated
- 400 Validation error
- 404 Not found
DELETE /v1/contacts//consent/
Revokes a specific consent record. The record is not hard-deleted —status becomes REVOKED and revoked_at is stamped. Full audit trail is preserved.
After revocation the contact is immediately suppressed from sends using that channel and message type.
Bearer <api_key>Contact ID.
Consent record ID (e.g.
cr_a1b2c3).- 200 OK
- 404 Not found
GDPR compliance notes
Arowana stores an
ip_hash of the request IP automatically on every consent write. This provides a cryptographic audit fingerprint without storing raw IP addresses. You do not send this field.- Audit trail — consent records are never hard-deleted. Revocation stamps
revoked_atand setsstatus: REVOKED. The full history is preserved. - DOI as best practice — use
enforced_doi: trueforNEWSLETTERconsent in jurisdictions where double opt-in is required (e.g. Germany). For action-based (MESSAGE) consent tied to a transaction, single opt-in withproof_textis typically sufficient. - Send-time enforcement — only
GRANTEDrecords (withdoi_status: DOI_ACCEPTEDif DOI was enforced) permit sends.PENDINGcontacts cannot receiveNEWSLETTERsends. - Cascading delete — deleting a contact cascade-deletes all consent records. Use
status: BLOCKEDon the contact instead if you need to suppress without losing audit history.
Consent sync journey
End-to-end guide for syncing opt-ins from a CRM or form platform.
Contact events
Webhook events fired on consent changes.