Capture attested consent
Record an opt-in with a full evidence bundle: captured-at timestamp, IP,
user-agent, agreement text, form URL, and consent method. The response
returns the consent id plus the agreement_text_hash for client-side
reconciliation.
Idempotent on the combination of organization, phone number, and contact
number: a duplicate request against an already opted-in contact returns
the existing consent id with already_opted_in=true and does not
re-flip the record.
PAYG orgs (the universal default) pass the plan gate. Orgs still
on a dormant legacy tier need growth or higher; legacy
starter orgs receive 403 PLAN_REQUIRED and can use
double-opt-in via POST /v1/consent/double-opt-in or the hosted
form via POST /v1/consent/hosted instead.
It is rate limited per organization. Exhausted limits return
429 RATE_LIMITED with a Retry-After header. The request body is
capped at 1 MiB; oversized requests are rejected.
Requires the consent:write scope.
Authenticate by sending your API key as a bearer token:
Authorization: Bearer am_live_.... Every request is automatically
scoped to the organization that owns the key and to the scopes granted
to that key.
In: header
Header Parameters
length <= 255Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/consent" \ -H "Content-Type: application/json" \ -d '{ "phone_number_id": "7c1f0a2d-9e8b-4c3a-9d2e-1f0a2b3c4d5e", "contact_number": "+15554443333", "opted_in": true, "evidence": { "captured_at": "2026-04-26T12:00:00Z", "ip_address": "203.0.113.42", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "agreement_text": "By checking this box I agree to receive appointment reminders from Agentmessage. Reply STOP to opt out, HELP for help.", "form_url": "https://example.com/signup", "consent_method": "checkbox" } }'{
"consent_id": "0190a1b2-c3d4-e5f6-a7b8-c9d0e1f2a3b6",
"already_opted_in": false,
"agreement_text_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "authentication failed",
"request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
}
}{
"success": false,
"error": {
"code": "PLAN_REQUIRED",
"message": "Tier 3 consent capture requires Growth or higher; use double-opt-in (POST /v1/consent/double-opt-in) or the hosted form (POST /v1/consent/hosted) on Starter",
"request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
}
}{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "not found",
"request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
}
}{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "validation failed",
"request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM",
"details": {
"to": "must be E.164",
"body": "must be 1..1600 chars"
}
}
}{
"success": false,
"error": {
"code": "RATE_LIMITED",
"message": "rate limited",
"request_id": "01JTBQH2FZ8K1RXC0WJ4Z9P3VM"
}
}