Overview
Instead of polling, your app can receive webhooks — Salesive sends an HTTPPOST to your
endpoint whenever something changes on a store your app is installed on (an order is created, a
product updated, and so on).
A webhook is a notification, not the data. A delivery tells you what changed — the
resource, the action, and the affected record’s id — but it does not include the record’s
fields. Fetch the current state yourself from the Apps API with your app
token (see Fetch the current data). Reading it back through your own
scoped token means you only ever receive data your permissions allow, and you always act on the
latest state rather than a possibly-stale snapshot.
orders/* events only if the installation has
READ_ORDERS). See Scopes & permissions.
Enable webhooks
Set a Webhook URL on your app in the dashboard Developer console (it’s optional — leave it blank to disable). The URL must be HTTPS and publicly reachable. When you save it, the console shows your app’s signing secret (whsec_…) — you’ll use it to verify deliveries.
One webhook URL serves all installations of your app. Each delivery tells you which store it’s
for (
shopId in the body and the X-Salesive-Shop-Id header), so route by that.The request
Every delivery is aPOST with a JSON body:
Headers
Topics
topic is resource/action. For admin events the action is created (POST), updated
(PUT/PATCH), or deleted (DELETE). Storefront events (customer activity on the live store) carry
their own action (signed_in, placed, paid, …). You receive a topic only if your installation
holds the scope below.
Admin events (dashboard / API changes)
Storefront events (live shopper activity)
These fire from the storefront when a shopper acts on the live store.orders/placed and orders/paid are distinct from the admin orders/created/orders/updated.
A single storefront checkout fires orders/placed (then later orders/paid) — never the admin
topics. Use the resourceId (the order id) with READ_ORDERS to fetch the order via the Apps API.Events fire for successful changes regardless of who made them — a merchant editing an order in
the dashboard, another app, or a shopper on the storefront. Dedupe on
id and treat delivery as
at-least-once.Fetch the current data
The payload carries no record fields — when you receive an event, read the current state from the Apps API using your app access token and theresource + resourceId:
- You only ever see data you’re entitled to. The record comes back through your scoped token, so the webhook can never hand you fields your permissions don’t cover.
- You always act on the latest state, not a snapshot that may be stale by the time you process it.
On a
deleted event the record is gone — don’t re-fetch; act on resource + resourceId. When
resourceId is absent (bulk or sub-actions), re-list the affected resource to re-sync the
collection.Verify the signature
Every delivery is signed so you can trust it came from Salesive and wasn’t altered. Compute the base64 HMAC-SHA256 of the raw request body using your app’s signing secret, and compare it to theX-Salesive-Hmac-SHA256 header with a constant-time check.
Node.js (Express)
Respond & retries
- Acknowledge fast. Return a
2xxwithin a few seconds. Do heavy work asynchronously — Salesive treats anything other than2xx(or a timeout) as a failed delivery. - Retries. A failed delivery is retried with exponential backoff for several attempts before it’s
dropped. Because retries reuse the same
id, make your handler idempotent (dedupe onid). - At-least-once. You may occasionally receive a duplicate; never assume exactly-once.
Best practices
- Verify the signature on every request; reject unsigned or mismatched deliveries.
- Process asynchronously (queue the event, ack immediately).
- Scope your handling to the
shopId— a delivery only ever concerns one store. - Don’t depend on ordering; use
occurredAtif you need to reason about sequence.

