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:
| Field | Description |
|---|---|
id | Unique delivery id. Use it to dedupe — retries reuse the same id. |
topic | resource/action (see below). The action is best-effort. |
resource / action | Resource changed, and one of created / updated / deleted. |
method / path | The exact API call that triggered the event — use these to disambiguate bulk or sub-actions (the topic won’t capture, e.g., a bulk price update). |
resourceId | The affected record’s id — present on creates (the new record), updates and deletes. May be absent for bulk/sub-actions; fall back to method + path. |
shopId | The store this event belongs to. |
occurredAt | ISO-8601 timestamp. |
Headers
| Header | Value |
|---|---|
X-Salesive-Topic | The event topic, e.g. orders/updated. |
X-Salesive-Shop-Id | The store id. |
X-Salesive-App-Client-Id | Your app’s clientId. |
X-Salesive-Event-Id | Same as the body id. |
X-Salesive-Hmac-SHA256 | Base64 HMAC-SHA256 signature of the raw body (see below). |
Topics
topic is resource/action, where action is created (POST), updated (PUT/PATCH), or
deleted (DELETE). You receive a resource’s events only if your installation holds the scope below.
| Resource | Required scope | Example topics |
|---|---|---|
orders | READ_ORDERS | orders/created, orders/updated |
products / foods / services | READ_INVENTORY | products/updated, foods/created |
categories | READ_CATEGORIES | categories/created |
customers | READ_CUSTOMERS | customers/updated |
shipping | READ_SHIPPING | shipping/created |
discounts | READ_DISCOUNTS | discounts/created |
blogs | READ_BLOGS | blogs/updated |
notifications | READ_NOTIFICATIONS | notifications/updated |
tasks | READ_TASKS | tasks/created |
notes | READ_NOTES | notes/updated |
scripts | READ_SCRIPTS | scripts/created |
comments | WRITE_COMMENTS | comments/created |
shipday | READ_SHIPDAY | shipday/updated |
kyc | READ_KYC | kyc/updated |
domains | READ_DOMAINS | domains/updated |
roles | READ_ROLES | roles/updated |
payouts | READ_PAYOUTS | payouts/updated |
Events fire for successful changes regardless of who made them — a merchant editing an order in
the dashboard, another app, or your own app. 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 like POST /products/bulk/price), use method +
path to decide what to re-sync — typically re-list the affected 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.

