Send checkout events with the Custom API
Post checkout and order events from any platform to a campaign's private trigger URL: the fields ACR reads, consent, cart links, lead matching and the answers you get back.
Last reviewed November 7, 2026
Get the trigger URL
Create a campaign and choose Custom API under Where leads come from. The campaign's first setup step shows a Checkout abandoned trigger with a Trigger URL and a Copy button. The token at the end of the URL is the only key, so anyone holding it can send events: keep it on your server.
One URL takes every event for that campaign, the completed order included. An admin can press Make a new URL, and the old one stops working at once. A duplicated campaign gets a URL of its own.
ACR stores events only while the trigger is on, and the trigger can be switched on only after the campaign is published. With the trigger off, the URL still answers 200 and keeps nothing.
Events
Every request names its event in the required event field. (The API reference lists an older name for the same field, which ACR also accepts.) It takes one of these values:
| Event | What ACR does |
|---|---|
checkout/updated | Creates or updates the checkout named by unique_id, and the shopper's lead. Each one restarts the abandonment wait, 30 minutes by default. Send it whenever the checkout changes. |
checkout/completed | The purchase. Completes the checkout, records an order with the same unique_id and final_price, ends the shopper's open runs and credits a campaign. Without it, outreach carries on after the shopper buys. |
leads/updated | Updates the lead only. It starts no campaign. |
meetings/requested, orders/delivered | Accepted and recorded on the lead. They start no campaign today. |
Fields ACR reads
| Field | Accepts | Used for |
|---|---|---|
unique_id | Text up to 200 characters, or a number | Your checkout or cart id. Required on checkout events; events with the same id update one checkout. |
email | A valid address, up to 254 characters | Matching and email outreach |
phone | Up to 40 characters; E.164 such as +15125550199 is safest | Matching, calls and texts. A number without a + is read with country_code, or the store's default country. |
first_name, last_name | Up to 100 characters each | The agent's greeting and merge fields |
country_code | Two letters | Country rules and phone parsing |
language, timezone | Such as en-US and America/Chicago | The agent's language and the shopper's local hours |
final_price | Text or a number | The checkout total, in the store's currency. There is no currency field. |
discount_codes | Up to 50 codes | Codes already applied |
items | Up to 200 items with id and name | What is in the cart. ACR keeps each item's id and name and counts one of each. |
shipping_details | An object | Its first_name, last_name, phone, country_code and province_code fill gaps in the fields above. Street, city and postcode are accepted and not kept. |
cart_link | A full URL, up to 2,000 characters | The link back to the checkout (below) |
should_verify_phone_presence | true or false | With true, no campaign starts until the lead has a phone number. A later update that brings one restarts the wait. |
context | Any object | Extra facts for start conditions and merge fields as context.*. On checkout/completed, utm_ keys in it are recorded on the order. |
consent | sms, calls, email as true or false | What the shopper agreed to (below) |
This checkout/updated request records a checkout and its lead:
POST /api/v1/trigger/{token}
Content-Type: application/json
{
"event": "checkout/updated",
"unique_id": "cart_58213",
"email": "jordan@example.com",
"phone": "+15125550199",
"first_name": "Jordan",
"country_code": "US",
"final_price": "86.00",
"items": [{ "id": "sku-204", "name": "Canvas weekender bag" }],
"cart_link": "https://shop.example.com/checkout/cart_58213",
"consent": { "sms": true, "email": true },
"context": { "utm_source": "meta" }
}Consent in the payload
Put what the shopper agreed to in consent: true for an opt-in, false for an opt-out, and leave a channel out when you do not know. ACR records it as Consent sent with Custom API events, including from Zapier and Make, one of the sources ticked by default under Consent that counts on the campaign's Compliance step.
With the default settings, calls and texts need an opt-in for that channel, and so does email. A shopper sent with no consent gets no outreach until consent arrives. Consent explains the rules.
The cart link
Send the shopper's own checkout address as cart_link. With the campaign's Link source set to Dynamic, the default, texts and emails use it. Each newer cart_link replaces the one stored before, so send a fresh one whenever the cart changes. See Checkout links.
How ACR matches the lead
ACR looks for an existing lead by unique_id first, then by email, then by phone in E.164, and the first match wins. Gmail and Googlemail addresses match without their dots or anything after a +, so j.ordan+shop@gmail.com is the same shopper as jordan@gmail.com; other addresses only ignore case. With no match, ACR creates a lead.
A value you leave out never erases one ACR already has. A checkout/updated with no email or phone stores the checkout but creates no lead, so it cannot start a campaign until a later update brings one.
Answers and limits
| Status | Body | When |
|---|---|---|
| 200 | {"message": "Success", "data": []} | The event was taken. Also when the trigger is off (nothing stored) and for a repeat. |
| 404 | {"message": "Not found", "errors": []} | The token is unknown or was replaced, or the campaign is archived |
| 422 | {"message": "The entered data was invalid", "errors": {...}} | The body is not JSON or is over 512,000 characters, a field fails its check, a checkout event has no unique_id, or another event has neither email nor phone. errors names each field. |
| 429 | {"message": "Too Many Attempts.", "errors": []} | More than 600 requests in one minute to one trigger URL. The Retry-After header gives the seconds to wait. |
Identical bodies that arrive in the same five-second window count once, so an instant retry is not recorded twice.