POST
Record a consent change for a contact

Authorizations

Authorization
string
header
required

A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.

Headers

Idempotency-Key
string
required

A unique key per logical write. Replaying a request with the same key returns the first response byte for byte instead of applying the write twice.

Path Parameters

marketingContactId
string
required

Body

application/json

THIS WRITES EVIDENCE, NOT A SETTING. The row lands in an append-only ledger this platform holds no update or delete permission on, so a wrong record stands forever and can only be contradicted by a later one, and that ledger is what a merchant produces to show a subscribe was real. Send the action that is true. THE ACTION DECIDES THE STATE, which is why there is no consent field to write: subscribe, confirm and import all land on subscribed, unsubscribe lands on unsubscribed, and pending lands on pending. An event and the state it produced can never disagree. THE BODY IS TWO FIELDS AND THE SERVER OWNS THE REST OF THE ROW. source, text_shown, ip, ua and occurred_at are each refused BY NAME with a 400, not ignored, because all five describe the person who acted and this request was made by your server rather than by them. Your address and http client describe your integration; the disclosure text describes a page an api write showed nobody. The server stamps source as public_api and text_shown as its own sentence saying so, and that is the whole point of the ledger: an auditor has to be able to separate a row a recipient produced by clicking a link in their own inbox from a row a merchant's integration wrote on their behalf, because only the first is evidence the recipient consented. Consent captured from a real shopper on the storefront keeps its own source, text, address and device. The response is the CONTACT, so you can read the resulting state, not the event you just sent.

channel
enum<string>
required

Which channel this decision is about. Consent is per channel: an email unsubscribe says nothing about sms.

Available options:
email,
sms,
push
action
enum<string>
required

What happened. confirm is the completion of a double opt-in, so send it only when you hold the evidence the person clicked a link in their own inbox; import is the right action when migrating a list from another system, and it records the subscription as inherited rather than freshly given. There is no default, because every value here changes who may be mailed.

Available options:
subscribe,
unsubscribe,
confirm,
pending,
import

Response

Success

data
object