2026-06-22
Added POST /v1/orders/placed endpoint
You can create and update orders through the API with the POST /v1/orders/placed endpoint, available under the orders_write OAuth scope.
The endpoint is an idempotent upsert keyed on order_id: the first call for a given order_id creates the order and returns 201 Created, while subsequent calls with the same order_id update the existing order and return 200 OK. Send the full current state of the order on every call — omitted optional fields keep their previously stored values.
- Required fields:
order_id,total,currency,order_date, plus at least one ofemailorphone. - Customer linkage. When an
emailorphoneis provided, Privy finds or creates the matching contact.accepts_email_marketingdrives email subscribe-on-create semantics, andaccepts_sms_marketingrecords an SMS opt-in on newly created contacts (requiresphone). - Historical imports. Pass
initial_sync: trueto load past orders without triggering real-time side effects such as flows, automations, and campaign-revenue attribution. Customer order stats are still updated so segmentation and winback stay accurate.
Tie orders to a Custom Integration with X-Privy-Integration-Token
POST /v1/orders/placed accepts an optional X-Privy-Integration-Token header that attributes the order to a specific Custom Integration. Generate the token when you create a Custom Integration in Settings → Integrations, and retrieve it later with the Reveal action.
- When the header is present, it must match an active Custom Integration for your business.
- When the header is omitted and exactly one Custom Integration exists, the order is automatically tied to it.
- Otherwise, the order is created with no integration attribution.
Authorization: Bearer OAuth token, which still authenticates the request.
2026-05-22
Welcome SMS for API-created SMS subscribers
When you setsms_consent to subscribed via POST /v1/contacts or PATCH /v1/contacts/{id}, Privy now automatically sends a TCPA-required welcome SMS to the contact. This only fires when the contact actually transitions to a confirmed opt-in state — contacts that are already subscribed are not messaged again.
To suppress the welcome SMS (for example, when you already collected consent outside of Privy), pass send_welcome_sms: false in the request body. The parameter defaults to true.
2026-05-14
Contact creation conflict responses now include id
POST /v1/contacts now returns the id of the existing contact in 409 Conflict responses. This lets API consumers identify and update the existing contact without a separate lookup.
2026-05-12
Consent vocabulary and PATCH-based consent management
Breaking changes:- Response field renames. Contact responses now return
email_consentandsms_consentinstead ofemail_permissionandphone_permission. - Filter parameter renames. The
GET /v1/contactsquery parametersemail_permissionandphone_permissionhave been renamed toemail_consentandsms_consent. - New consent values. The old
non_subscribedvalue has been replaced bynever_subscribed. New values have been added — see below.
- Consent management via PATCH.
PATCH /v1/contacts/{id}now acceptsemail_consentandsms_consentfields. You can combine consent changes with other field updates in a single request. - Consent on create.
POST /v1/contactsnow accepts the full set of writable consent values foremail_consentandsms_consent. - Expanded email consent values:
subscribed— contact opted into email.unsubscribed— contact opted out of email.never_subscribed— no opt-in, no opt-out (replacesnon_subscribed).suppressed— merchant-suppressed (writable). Writing any consent value to a merchant-suppressed contact unsuppresses it first.compliance_suppressed— system-suppressed (read-only, filterable). Any write to a compliance-suppressed contact returns422.
- Expanded SMS consent values:
subscribed— contact has confirmed SMS opt-in.unsubscribed— contact opted out of SMS.never_subscribed— no opt-in, no opt-out (replacesnon_subscribed).single_opt_in— merchant collected a single opt-in (not yet confirmed). Writable; requires a phone number.pending— awaiting confirmation reply (read-only, filterable).
POST /v1/contacts/{id}/unsubscribeis deprecated. UsePATCH /v1/contacts/{id}withemail_consent: "unsubscribed"instead. The endpoint continues to work but now returnsDeprecation: trueandLinkheaders.