Abandoned cart texts
A shopper starts checkout and leaves. An hour later, if no order came in, they get one text with their cart link:
checkout_started
-> Wait until order_placed
arrives: end
not in 1 hour: continue
-> Send SMSAcme: you left something in your cart. Finish your order here:
https://acme.com/checkouts/c/4b1e... Reply STOP to opt out.This flow is the Abandoned cart template in Console → Automations. It runs on two tracked events from your store:
| Event | When | Properties |
|---|---|---|
checkout_started | A shopper with a phone number reaches checkout | checkout_url (the link in the text) |
order_placed | The order goes through | none needed |
A connected Shopify store sends them for you. Otherwise send them from Shopify Flow, Klaviyo, or your own code. Each way is below.
Before you start
- A number that can text the public: a registered local number or a verified toll-free number. See Compliance.
- Opt-ins on file. A cart reminder is a marketing text, so it goes only to shoppers whose opt-in is recorded with TextKit. Shoppers who tick the SMS box at your Shopify checkout come in when you connect Shopify in Console → Contacts → Integrations. Subscribers from another tool come in as a CSV with consent columns (Contacts). Everyone else is skipped, and the run logs why.
- An API key for the tool that calls TextKit. A
restricted key is enough: the
automationsscope forPOST /v1/track, ormessages:sendforPOST /v1/messages.
Connected Shopify store
- Connect the store in
Console → Contacts → Integrations. The
store's app needs the
read_customersandread_ordersscopes. A store connected before cart reminders existed: reconnect it once. - In Console → Automations, create a flow from the Abandoned cart template, pick your sending number, edit the text, and activate it.
That's all. Every 10 minutes TextKit checks the store for abandoned
checkouts and new orders and sends the two events, each checkout once.
Shoppers who ticked the SMS box at checkout are recorded as opted in on the
way. A checkout becomes an event only for a shopper who agreed to texts
(that box, or an opt-in already on file); nobody else gets a reminder. The checks run only while a flow that starts on checkout_started
is active. If Shopify refuses them, the integration's card in the console
says why.
Shopify Flow
Shopify Flow is Shopify's free automation app. Its Send HTTP request action is on the Grow, Advanced and Plus plans, not Basic.
- In Console → Automations, create a flow from the Abandoned cart template, pick your sending number, edit the text, and activate it.
- In Shopify admin, open Flow → Create workflow.
- Trigger: Customer abandons checkout.
- Action: Send HTTP request.
- Method:
POST - URL:
https://api.jointextkit.com/v1/track - Headers:
Authorization:Bearer YOUR_KEY(store the key as a Flow secret), andContent-Type:application/json - Body:
- Method:
{
"event": "checkout_started",
"phone": "{{ customer.phone }}",
"properties": {
"checkout_url": "{{ abandonment.abandonedCheckoutPayload.abandonedCheckoutUrl }}"
}
}- Turn the workflow on.
Pick the two variables from Flow's variable list if your store's names
differ. Shopify decides when a checkout counts as abandoned, so the text
goes out about an hour after that. To stop a text for a shopper who orders
in that hour, add a second workflow: trigger Order created, the same
request with "event": "order_placed" and "phone": "{{ order.phone }}".
Klaviyo
Klaviyo's own Abandoned Checkout flow decides when to send and skips shoppers who ordered. TextKit sends the text, so you don't need the template here.
- Open the flow that starts on Checkout Started.
- After its time delay, add a Webhook action:
- URL:
https://api.jointextkit.com/v1/messages - Headers:
Authorization:Bearer YOUR_KEY, andContent-Type:application/json - Body:
- URL:
{
"from": "+18335550100",
"to": "{{ person.phone_number }}",
"body": "Acme: you left something in your cart. Finish your order here: {{ event.extra.checkout_url }} Reply STOP to opt out.",
"category": "marketing"
}- Set the action to Live.
Klaviyo needs two-step authentication on your login before it sends webhooks. Open View profile and event variables in the webhook editor to check the checkout link's name in your account.
Your own code
Send the two events when they happen:
curl -X POST https://api.jointextkit.com/v1/track \
-H "Authorization: Bearer $TEXTKIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"checkout_started","phone":"+14155550132","properties":{"checkout_url":"https://acme.com/checkouts/c/4b1e"}}'
curl -X POST https://api.jointextkit.com/v1/track \
-H "Authorization: Bearer $TEXTKIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event":"order_placed","phone":"+14155550132"}'A shopper who starts checkout again while a run is waiting stays in that run: one text per checkout, not one per page view.
Order and shipping texts
A connected Shopify store also sends two events for its orders:
| Event | When | Properties |
|---|---|---|
order_placed | A new order with a phone number | order_name (#1001), order_url (the order status page), total, currency, items, item |
order_shipped | A shipment gets a tracking number or link | order_name, tracking_number, tracking_url, tracking_company |
Two templates in Console → Automations start on them:
Acme: thanks for your order #1001. Check its status here:
https://acme.com/... Reply STOP to opt out.
Acme: your order #1001 has shipped. Track it here:
https://www.ups.com/... Reply STOP to opt out.- Connect the store as above. Order texts need
read_orders; shipping texts from a store connected with one click also useread_fulfillments. - Create a flow from Order confirmation or Shipping update, pick your sending number, edit the text, and activate it.
A store connected with one click sends each event within seconds. A store
connected with its own token is checked every 10 minutes. Each order and
each shipment counts once. Orders older than a day and shipments older than
a week never start a flow. When a shipment has no tracking link,
tracking_url is the order status page.
These texts go only to shoppers whose opt-in is on file with TextKit:
shoppers who ticked the SMS box at your checkout, or who opted in any other
way (Contacts). Everyone else is skipped, and the run logs
why. Your own verified numbers always get them, so you can test on yourself.
The same holds when you send order_placed or order_shipped yourself
with POST /v1/track.
Check it
Each run has a timeline in Console → Automations: the event that started it, the wait, and the text, or why it was held (quiet hours) or skipped (no opt-in, opted out). Try the flow with a test key and your own number before you turn it on for shoppers.