Skip to main content

Zapier recipes

Zapier's Catch Hook is one URL, which is the opposite of how the other two webhook settings are arranged: those are split by subject, because an n8n flow is built per subject. So the first thing to do here is give Zapier the address that receives everything.

Setting it up

  1. In Zapier, create a Zap with the Webhooks by Zapier → Catch Hook trigger and copy its URL.
  2. In StorePilot: Settings → Notifications → All events (one address), paste it, save.
  3. Leave the two subject addresses empty. They win for their own subjects when set, so filling one in would quietly take those events away from Zapier.
  4. Make sure Payload contract is Version 2. Sites created before September 2026 are on version 1, whose events have five different shapes — a single Zap cannot branch on them cleanly, which is the reason version 2 exists.

Send a test from the same panel. The drill arrives in the site's own contract, 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:

FieldMeaning
eventWhich of the twelve events this is
site.nameWhich shop, by name — no id→shop table to maintain
occurredAtWhen it happened (sentAt is when we posted)
links.dashboardA link straight to the thing, for the Slack message or the ticket
idAn 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.

  1. Path Aevent is lead.created and data.lead.leadKind is checkout: start a Zapier Delay For of one hour, then send the recovery mail.
  2. Path Bevent is lead.converted: look the customer up by data.lead.email and 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 webhook_url at a queue you control and let Zapier read from that.