AgentMessage
Consent

Capture attested consent

POST
/v1/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.

AuthorizationBearer <token>

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

Idempotency-Key?string
Lengthlength <= 255

Request 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"
  }
}