VocalDocscontracts 1.65.0

Record a consent event

POST /v1/consent-records

PropertyValue
Operationcreate_consent_record
GroupConsent
Scopeconsent:write
Route classcontrol
IdempotencyIdempotency-Key accepted: a retry with the same key replays the first answer
AuditAudited contacts.consent.record (mutation)
Released in1.61.0
Phase 0 hostServed (the hosted api pins 1.65.0)

Appends one record to the consent ledger and sets the derived state in the same transaction (1.61.0), so the next admission and the next send read it; writes consent.changed. Under the Compliance profile's revocation_scope: all_channels an Organization-scope opt-out sets every address channel of the address (applied_channels). An opt-in or a grant over an opt-out without evidence is validation_failed (consent_evidence_required); the channel app_push and the purpose marketing are capability_not_available. The Audit event names the channel, scope and state, never the address.

Request

Set VOCAL_API to the base URL of your API and VOCAL_API_KEY to an API key with the consent:write scope (Authentication and keys). Replace each placeholder, such as agt_... or <name>, with your own value.

curl -X POST "$VOCAL_API/v1/consent-records" \
  -H "Authorization: Bearer $VOCAL_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "voice", "state": "opted_in" }'

Parameters

NameInTypeRequiredDescription
idempotency-keyheaderstringnoA client-chosen key, kept 24 hours per Organization, environment and route. A replay returns the stored response.

Request body

Content type application/json, required: ConsentRecordCreateRequest.

FieldTypeRequiredDescription
addressConsentAddressnoThe address; required for every channel but memory, refused for memory.
basisConsentBasisnoRequired for opted_in and granted, refused for opted_out and revoked.
channelConsentChannelyes
contact_idContactIdnoThe Contact; required for memory, whose subject is a Contact. For an address channel it only links the record, and the Contact must hold the address (consent_contact_unknown otherwise).
evidenceConsentEvidenceInputnoRequired for an opt-in or a grant over an opted_out or revoked state (consent_evidence_required).
occurred_atRequestTimestampnoWhen the person acted; when the api records it if omitted.
purposeConsentPurposenoall when omitted.
scopeConsentScopenoorganization when omitted.
senderConsentSenderInputnoRequired with scope: sender, refused otherwise.
stateConsentStateValueyesAn address channel takes opted_in or opted_out, memory takes granted or revoked.

Responses

StatusContent typeShapeError codes
201application/jsonConsentRecord
400application/jsonErrorEnvelopeinvalid_request
401application/jsonErrorEnvelopeunauthenticated
403application/jsonErrorEnvelopeforbidden, org_suspended
409application/jsonErrorEnvelopeidempotency_in_progress, idempotency_key_reused
422application/jsonErrorEnvelopevalidation_failed, capability_not_available
429application/jsonErrorEnveloperate_limited
500application/jsonErrorEnvelopeinternal_error

Fields of the 201 answer

The shape is ConsentRecord.

FieldTypeRequiredDescription
applied_channelsarray of ConsentChannelyesThe channels whose state the record set: the channel itself, and under revocation_scope: all_channels every address channel of an Organization-scope opt-out.
basisConsentBasis or nullyes
channelConsentChannelyes
contact_idContactId or nullyesThe Contact the record names or whose identity holds the address; or null.
environmentEnvironmentyes
evidenceConsentEvidence or nullyes
idConsentRecordIdyes
identity_idContactIdentityId or nullyesThe identity of that Contact that holds the address; null for memory.
object"consent_record"yes
occurred_atTimestampyes
purposeConsentPurposeyes
recorded_atTimestampyes
recorded_byActorRefyes
scopeConsentScopeyes
senderConsentSender or nullyes
sourceConsentSourceyes
stateConsentStateValueyes