Zapier recipes
Zapier's Catch Hook is one URL, and a StorePilot webhook destination is one URL with the events it receives ticked beside it — so the first thing to do here is give Zapier a destination that receives everything you want to act on.
Setting it up
- In Zapier, create a Zap with the Webhooks by Zapier → Catch Hook trigger and copy its URL.
- In StorePilot: Settings → Notifications → Add destination, choose Webhook, paste the URL and tick every event this Zap should handle.
- If you split events across several Zaps, give each its own destination instead — each receives exactly what it ticked, so nothing is quietly taken from another.
- Make sure the destination's Payload version is Version 2. A new destination starts there; one carried over from the old settings may be on version 1, whose events have five different shapes — a single Zap cannot branch on them cleanly, which is the reason version 2 exists.
Press Send test on the destination. The drill arrives in the destination's own version, so what you build the Zap against is what the real events will look like.
Branching on the event
Every version 2 payload has the same shape, so one Filter or Paths step keyed on event
splits the whole stream:
event → what to do
lead.created → create a CRM contact
lead.converted → mark that contact as a customer, stop any nurture sequence
error.created → post to a Slack channel if data.error.severity is "critical"
uptime.down → page whoever is on call
revenue.silence → tell the shop owner nothing has sold in the window
The fields a Zap usually needs are in the same place for every event:
| Field | Meaning |
|---|---|
event | Which of the twelve events this is |
site.name | Which shop, by name — no id→shop table to maintain |
occurredAt | When it happened (sentAt is when we posted) |
links.dashboard | A link straight to the thing, for the Slack message or the ticket |
id | An idempotency key, for de-duplicating a replayed delivery |
Cancelling an abandoned-cart flow
This is the recipe worth writing down, because until version 2 it could not be built.
A cart arrives as lead.created with data.lead.leadKind = "checkout". If you mail that cart an
hour later, you are racing the customer to their own receipt: they may have paid in the
meantime, and nothing told you.
lead.converted is what tells you. It fires when the checkout is paid, carries the same
data.lead.id, and adds data.order with the external order id, the total and paidAt.
- Path A —
eventislead.createdanddata.lead.leadKindischeckout: start a Zapier Delay For of one hour, then send the recovery mail. - Path B —
eventislead.converted: look the customer up bydata.lead.emailand set a field your Path A mail checks, or remove them from the sequence in your ESP.
Path B needs somewhere to write, because Zapier cannot reach into a delay that is already
running. A single-row lookup table (Zapier Tables, Airtable, a Google Sheet) keyed on
data.lead.id is enough: Path B writes converted = true, and Path A reads it after the delay
and stops if it is set.
:::note A declined card is not a conversion
lead.converted fires only on paid. A checkout that was created and then failed at the
gateway stays a live cart — and that shopper is exactly the person the recovery mail is for.
:::
Verifying the signature
Zapier's Catch Hook does not verify signatures for you. If you set a signing secret, add a Code by Zapier step as the first action and reject anything that fails — otherwise the URL alone is the whole credential, and it travels in every Zap history entry.
See the signature section for the exact material: on version 2
it is <timestamp>.<raw body>, and the timestamp is in X-StorePilot-Timestamp.
What this cannot do
There are no retries. Delivery is fire-and-forget; if Zapier is unreachable, the event is gone. For anything you cannot afford to miss, point a webhook destination at a queue you control and let Zapier read from that.