# E-commerce events

Cart Abandoned, Product Viewed and Order Placed as native SendBeam automation triggers — one endpoint, fed by the WooCommerce plugin, a Shopify webhook, or your own code.

`POST /api/v1/ecommerce/events` turns what happens in your store into three
[automation triggers](https://sendbeam.io/docs/automations/triggers): **Cart abandoned**,
**Product viewed** and **Order placed**. A store posts one normalised
event; SendBeam matches or creates the contact by email (exactly the same rules as everywhere
else a contact comes from an external event — a bounced, complained or deleted address is never
resubscribed by this) and fires any automation built on the matching trigger, at once, the same
way a form submission or a tag does.

## The three triggers

- **Order placed** — the reliable one. Every order fires it, and also adds the
  order's value to the contact's `lifetime_value` custom field (see below).
- **Cart abandoned** — best effort, from every source. Nothing can prove a cart
  was truly abandoned rather than completed a minute later somewhere else; this is a heuristic,
  not a guarantee, and it only ever fires for a cart where the store already knew an email
  address.
- **Product viewed** — only ever fires for a KNOWN contact. There is no anonymous
  visitor tracking behind this: if the store has no email for the visitor at view time, nothing
  is sent, on purpose.

## The endpoint

Authenticate with an API key carrying the **E-commerce events** permission
(`ecommerce:write`) — create one under [Settings → API keys](https://sendbeam.io/settings/api-keys) — in the `x-api-key` header, same as every other `/api/v1/*`
write. The body:

```
{ "type": "cart_abandoned" | "product_viewed" | "order_placed",
  "email": "jane@example.com",
  "name": "Jane Doe",       // optional
  "value": 84.50,           // optional — order/cart total
  "currency": "GBP"         // optional
}
```

A successful call answers with what happened — nothing is ever silently dropped:

```
{ "ok": true, "processed": true, "contact_id": "...", "contact_created": false,
  "enrolled": true, "lifetime_value": 214.30 }
```

When the address is suppressed, or the workspace's contact cap is reached, the call still
answers `200` (your store's checkout hook should never fail because of our
suppression list) with `{ "ok": true, "processed": false, "reason": "suppressed" | "contact_limit" }`.

## WooCommerce

Use the [official SendBeam plugin](https://sendbeam.io/docs/wordpress). Once its API key is set
(**Settings → SendBeam**, with the E-commerce events permission), turn on each
event under **Settings → SendBeam → E-commerce events**:

- **Order placed** fires from WooCommerce's own order-processed hook — reliable,
  on by default once enabled.
- **Product viewed** fires from the product page for a logged-in customer, or one
  known from an earlier step in the same session; otherwise nothing is sent.
- **Cart abandoned** is a wp-cron heuristic: adding to cart is timestamped, and if
  no order follows within a window you set (60 minutes by default) it fires once — only when
  WooCommerce already knows the shopper's email. This is the same honest limitation every
  dedicated cart-recovery plugin has; WooCommerce core has no real "abandoned cart" event to
  hook.

## Shopify

No app, and no Shopify Partner / app-store listing — you wire this up directly from your own
store. In Shopify Admin, go to **Settings → Notifications → Webhooks**, choose
**JSON** format, and create a webhook for each topic you want:

| Shopify topic | SendBeam trigger |
| --- | --- |
| `Order creation` / `Order payment` | Order placed |
| `Checkout creation` / `Checkout update` | Cart abandoned (best effort — see below) |

Use the same URL for every topic, with your workspace id (shown on [Settings → E-commerce](https://sendbeam.io/settings/ecommerce)) in the query string:

```
https://sendbeam.io/api/v1/ecommerce/events?tenant=<your-workspace-id>
```

Shopify shows a webhook **signing secret** the first time you create a webhook on
the store. Paste it into [Settings → E-commerce](https://sendbeam.io/settings/ecommerce); every delivery's
`X-Shopify-Hmac-SHA256` header is then verified against it (HMAC-SHA256 over the raw
body) before anything is processed. No secret saved means Shopify-signed events are refused —
there is no unsigned fallback for this path.

> `checkouts/create` and `checkouts/update` fire on an *incomplete*
> checkout, not a confirmed abandonment — completeness and timing vary by Shopify plan, same
> honest caveat as WooCommerce's cart_abandoned. There is **no Shopify webhook topic for "a product page was viewed"** — Shopify does not emit one — so Product viewed cannot be
> fed from Shopify at all.
> 

Building an actual Shopify app with an App Store listing is a separate future step that needs
the account owner's own Shopify Partner account — this endpoint is what you can use today
without one.

## Anything else (n8n, Zapier, your own code)

Post the normalised shape directly with your API key:

```
curl -X POST https://sendbeam.io/api/v1/ecommerce/events \
  -H "x-api-key: sb_live_XXXXXXXX_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "order_placed",
    "email": "jane@example.com",
    "name": "Jane Doe",
    "value": 84.50,
    "currency": "GBP"
  }'
```

## Lifetime value

Every `order_placed` event adds `value` to the contact's
`lifetime_value` custom field — created automatically as a Number field the first
time an order arrives, and always INCREASED, never overwritten, so two orders add up. Use it in
a segment, a merge tag, or a condition step the same as any other Number field. The same
increment mechanism is available generally: the [Set Field step](https://sendbeam.io/docs/automations/steps) has an **Increase by** mode for building your own running counters.

## What this is not

- Not a Shopify app — no App Store listing, no OAuth install flow. A merchant wires the
  webhook up themselves, today, with the steps above.
- Not anonymous behavioural tracking — Product viewed and Cart abandoned only ever fire for a
  contact the store already has an email for.
- Cart abandoned is always a heuristic. Treat it as "probably didn't finish", not as proof.

---
Source: https://sendbeam.io/docs/ecommerce
