Connect your website
Your store knows when an order is placed, when it ships and when a cart is left behind. Tell Engage, and your workflows send the WhatsApp message for each - confirmations, tracking links, reminders. Any website that can make an HTTP request from its server can do this; no plugin needed.
On Shopify or WooCommerce?
You do not need any of the code below. Shopify connects with a few webhooks, and WooCommerce has a plugin. Both send the same events this page describes.
How it fits together
- Your website sends an event to Engage at each moment that matters.
- A workflow waiting for that event sends an approved WhatsApp template - straight away, or after a wait.
- When the customer replies, the conversation lands in your inbox, where you or your team answer.
1. Create an API key
In the dashboard: Settings, API keys, Create key. Name it after the website - “Shop website” - so you know which key to revoke if you ever need to. It is shown once; store it in your server's environment as ENGAGE_API_KEY.
Only ever from your server
The key goes in a header of a request your server makes - never in JavaScript that runs in the shopper's browser. Anything a browser receives, anyone can read, and a key read from a page can report events and create customers in your workspace. A key can reach only events and customers - not your conversations, team or WhatsApp number - but that is still yours to protect.
2. Report the moments that matter
Three events cover most stores. The names and fields below are the ones the dashboard's workflow recipes use, so a recipe works with no changes. Use your own names if you prefer; the workflow just has to wait for the same name you send.
order.created - When a customer checks out.
curl -X POST https://api.engentra.io/v1/events \
-H "X-API-Key: $ENGAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348030000001",
"name": "Ada Obi",
"type": "order.created",
"data": {
"orderNumber": "1042",
"total": 25000,
"currency": "NGN"
},
"idempotencyKey": "1042-order-created",
"optIn": {
"evidence": "Checkout checkbox: Send me order updates on WhatsApp"
}
}'order.shipped - When the order leaves for delivery.
curl -X POST https://api.engentra.io/v1/events \
-H "X-API-Key: $ENGAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348030000001",
"name": "Ada Obi",
"type": "order.shipped",
"data": {
"orderNumber": "1042",
"trackingUrl": "https://track.example.com/NG1042"
},
"idempotencyKey": "1042-order-shipped"
}'checkout.started - As soon as a shopper at checkout has typed their phone number. Send it straight away - the workflow does the waiting, and stops for anyone who orders.
curl -X POST https://api.engentra.io/v1/events \
-H "X-API-Key: $ENGAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348030000001",
"name": "Ada Obi",
"type": "checkout.started",
"data": {
"cartUrl": "https://shop.example.com/cart/7f3a",
"total": 18000,
"currency": "NGN"
},
"idempotencyKey": "cart-7f3a-checkout-started"
}'| Field | Type | Notes |
|---|---|---|
phone | string | The customer’s WhatsApp number with the country code: +2348030000001. A customer Engage has not seen is created from it. |
name | string | Used only when the customer is new. |
type | string | What happened. Lowercase words joined by dots. |
data | object | Details a template can use - order number, tracking link, cart link. The workflow builder fills template variables from these by name. |
idempotencyKey | string | Your own id for this one event, reused if you send it again. A retried request is then recorded once, and the customer gets one message, not two. |
optIn | object | Only when the customer agreed to WhatsApp messages - see step 3. |
Numbers are usually typed the local way. Convert them before sending:
Nigerian numbers
// 0803 000 0001 -> +2348030000001
function toE164(phone) {
const digits = phone.replace(/\D/g, '');
if (phone.trim().startsWith('+')) return '+' + digits;
if (digits.startsWith('234')) return '+' + digits;
if (digits.startsWith('0')) return '+234' + digits.slice(1);
return null; // not a number we can safely guess - skip it
}3. Ask for WhatsApp consent at checkout
Order confirmations and shipping updates are utility messages: they reach a customer who just ordered, no opt-in needed. Cart reminders, offers and win-back messages are marketing, and Engage refuses to send one to anybody without an opt-in on record - WhatsApp's rules, and messages people did not ask for are how a number's quality rating drops and Meta starts limiting it.
So add a checkbox to your checkout - “Send me order updates and offers on WhatsApp” - and when it is ticked, include optIn in the order.created event, saying where they agreed. Engage records it with that evidence, before the event, so a workflow that reacts straight away already sees it.
"optIn": { "evidence": "Checkout checkbox: Send me order updates and offers on WhatsApp" }An opt-out always wins
Someone who replied STOP is not messaged again because a later checkout says they agreed - nor because they later write to you about something else. They opt back in by sending START, or an owner lifts it with a reason; see Suppression and consent.
4. Check it worked
The response tells you two things. recorded is true the first time and false for a repeat of the same idempotency key. matchedWorkflows is how many workflows are waiting for that event:
response
{
"event": { "id": "…", "type": "order.created", … },
"recorded": true,
"customerCreated": true,
"matchedWorkflows": 1
}A zero there, once you have built the workflow, almost always means the names differ - order_created sent, order.created awaited. Everything your website sends also appears in the dashboard under Activity, Events, with its data, and the workflow builder says when an event has arrived.
5. Build the workflows
In the dashboard: Workflows, New workflow. Start from Confirm an order on WhatsApp, Tell customers their order has shipped or Recover abandoned carts, choose an approved template, and switch it on. Replies go to the inbox.
The cart recipe starts on checkout.started, waits an hour, and stops for anyone who has ordered or replied since - so send checkout.started as soon as you have the shopper's number and let the workflow do the waiting. Your website needs no timer of its own.
Retries and timeouts
Give the request a timeout of a few seconds and do not let it hold up the checkout - send it after the order is saved, or from a background job. If it fails, retry with the same idempotency key.
Next
Events →
Every field, how idempotency works, and reading events back.