Webhooks
Receive real-time HTTP callbacks whenever important events occur in your SpireStock workspace — new orders, status changes, user sign-ups, and payment confirmations.
How Webhooks Work
Webhooks follow a simple four-step flow:
- Register— You configure an HTTPS endpoint URL and choose the events you want to subscribe to via the SpireStock dashboard or API.
- Trigger— An event occurs in your workspace (e.g., a new order is created).
- Deliver — SpireStock sends a
POSTrequest containing the event payload to your registered endpoint within seconds. - Acknowledge — Your server responds with a
2xxstatus code. If delivery fails, SpireStock retries with exponential back-off for up to 72 hours.
HTTPS Required
Webhook endpoints must use HTTPS. Plain HTTP URLs are rejected to protect payload integrity and confidentiality.
Event Types
Subscribe to one or more of the following event types:
| Event | Description | Fired When |
|---|---|---|
order.created | A new order has been placed | A sales rep or customer submits a new order through any channel |
order.delivered | An order has been delivered | The order status changes to delivered (status 4) |
user.created | A new user joined the workspace | An admin creates a new user or a user signs up in your workspace |
Payload Format
Every webhook delivery includes a set of custom headers and a JSON body.
Headers
| Header | Description | Example |
|---|---|---|
X-Webhook-Event | The event type that triggered this delivery | order.created |
X-Webhook-Signature | HMAC-SHA256 hex digest for payload verification | sha256=a1b2c3d4e5... |
X-Webhook-Timestamp | Unix timestamp (seconds) when the event was sent | 1717200000 |
Content-Type | Always JSON | application/json |
Example Payload
Below is a sample payload for an order.created event:
{
"id": 1,
"event": "order.created",
"timestamp": "2026-06-01T10:30:00.000Z",
"organization_id": 5,
"data": {
"id": 142,
"order_code": "ORD-2026-0142",
"order_status": 1,
"user_id": 42,
"user_name": "Sharma Dairy Store",
"order_total_amount": 1400.00,
"order_items_count": 1,
"order_date": "2026-06-01",
"createdAt": "2026-06-01T10:30:00.000Z"
}
}Signature Verification
Every webhook delivery is signed using your workspace’s webhook secret. You should always verify the signature before processing a payload to ensure it was sent by SpireStock and has not been tampered with.
How It Works
- Concatenate the timestamp and the raw request body, separated by a dot:
{timestamp}.{body} - Compute an HMAC-SHA256 digest using your webhook secret as the key.
- Compare the computed signature with the value in the
X-Webhook-Signatureheader using a timing-safe comparison to prevent timing attacks.
Never skip verification
Without signature verification, an attacker could forge webhook deliveries to your endpoint. Always use a timing-safe comparison function to prevent timing-based side-channel attacks.
import crypto from "crypto";
import express from "express";
const app = express();
// Use raw body for signature verification
app.post(
"/webhooks/spirestock",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.headers["x-webhook-signature"];
const timestamp = req.headers["x-webhook-timestamp"];
const body = req.body.toString();
// Build the signed content
const signedContent = `${timestamp}.${body}`;
// Compute expected signature
const expected = "sha256=" +
crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(signedContent)
.digest("hex");
// Timing-safe comparison
const isValid =
expected.length === signature.length &&
crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
if (!isValid) {
return res.status(401).json({ error: "Invalid signature" });
}
// Parse and process the event
const event = JSON.parse(body);
console.log("Received event:", event.event, event.id);
// Acknowledge receipt
res.status(200).json({ received: true });
}
);
app.listen(3000);Best Practices
- Respond quickly — Return a
2xxstatus within 5 seconds. Offload heavy processing to a background queue. - Handle duplicates — Use the event
idfield to deduplicate deliveries. SpireStock may retry events that did not receive an acknowledgment. - Validate timestamps— Reject events where the timestamp is more than 5 minutes old to guard against replay attacks.
- Use a secret per environment— Generate unique webhook secrets for staging and production to isolate environments.
- Monitor failures— Check the webhook delivery logs in the SpireStock dashboard for failed deliveries and error details.
- Consider IP allowlisting— For additional defense-in-depth, restrict your webhook endpoint to only accept requests from SpireStock’s IP ranges.