Guide to SHOPLINE Webhooks: Features and Best Practices
SHOPLINE webhooks notify your app about store activity: an order is created, a product updates, a collection changes. If you're building on the SHOPLINE Open Platform, webhooks are how you react to store events without polling. If you've integrated Shopify, this will feel familiar, SHOPLINE's webhook model is a close clone.
This guide covers how SHOPLINE webhooks work, the topics you'll subscribe to, how to verify the X-Shopline-Hmac-Sha256 header, the retry behavior, and the best practices for production.
What are SHOPLINE webhooks?
SHOPLINE Open Platform (developer.shopline.com) webhooks are HTTP POSTs delivered to a URL you subscribe per topic. They're signed with an HMAC-SHA256 of the raw body, keyed with your app secret, in the X-Shopline-Hmac-Sha256 header, Shopify-style. Companion headers identify the topic and shop.
SHOPLINE webhook features
| Feature | Details |
|---|---|
| Configuration | Admin REST API: POST https://{handle}.myshopline.com/admin/openapi/{version}/webhooks.json (body must include api_version) |
| Signature header | X-Shopline-Hmac-Sha256 |
| Signature scheme | HMAC-SHA256 of the raw body, keyed with the app secret |
| Encoding | lowercase hex (verified against real deliveries) |
| Other headers | X-Shopline-Topic, X-Shopline-Shop-Domain, X-Shopline-Shop-Id, X-Shopline-Webhook-Id (stable across resends) |
| Topics | Shopify-style slash format (orders/create) |
| Acknowledgement | 5-second timeout |
| Retries | Up to 19 over 48h, then the subscription is auto-removed |
| SDK | None published |
Common topics
SHOPLINE topics use the Shopify-style slash format:
| Topic | Fires when |
|---|---|
orders/create | An order is created |
orders/updated | An order updates |
products/create | A product is created |
products/update | A product updates |
collect/delete | A collect is deleted |
Subscribe to the topics you process, and consult SHOPLINE's webhook reference for the full list.
Setting up SHOPLINE webhooks
Subscribe via the Admin REST API: POST https://{handle}.myshopline.com/admin/openapi/{version}/webhooks.json with { topic, address, api_version }. Your app secret (Developer Center > App credentials) is the HMAC key.
api_version is required in the body. Omit it and the request fails with a 400, even though the URL already contains a version segment. Include api_version explicitly in the JSON payload.
Securing SHOPLINE webhooks
Each delivery carries an X-Shopline-Hmac-Sha256 header: a lowercase-hex HMAC-SHA256 of the raw request body, keyed with your app secret. Verify against the raw, un-parsed body and compare in constant time. (Despite the Shopify-style header name, SHOPLINE uses hex, not base64, confirmed against real deliveries.)
const crypto = require("crypto");
const APP_SECRET = process.env.SHOPLINE_APP_SECRET;
function verify(rawBody, signature) {
const expected = crypto.createHmac("sha256", APP_SECRET).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.headers["x-shopline-hmac-sha256"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge within 5s
processQueue.add({
topic: req.headers["x-shopline-topic"],
body: JSON.parse(req.body),
});
});
The same check in Python:
import hashlib
import hmac
import os
APP_SECRET = os.environ["SHOPLINE_APP_SECRET"].encode()
def verify(raw_body: bytes, signature: str) -> bool:
expected = hmac.new(APP_SECRET, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
SHOPLINE webhook limitations and pain points
api_version is required on creation
The Problem: POST /webhooks.json returns a 400 if the request body doesn't include api_version, even though the URL path already carries a version segment. The failure isn't obviously about the missing field, so it's easy to lose time on it.
Why It Happens: SHOPLINE validates api_version from the body, not the URL, on webhook creation.
Workarounds:
- Always include
api_versionin the JSON body (alongsidetopicandaddress).
How Hookdeck Can Help: Once created, point the webhook address at Hookdeck for verification, queuing, and retries, so the one-time creation quirk is behind you and delivery is reliable from then on.
Two developer platforms
The Problem: SHOPLINE has a newer Open Platform (developer.shopline.com) and an older one (open-api.docs.shoplineapp.com). Following the wrong docs leads to wrong headers or endpoints.
Why It Happens: SHOPLINE runs two developer platforms.
Workarounds:
- Use the newer Open Platform (the one this guide and the source align with).
How Hookdeck Can Help: Hookdeck's filters and normalization insulate your app from platform differences.
The 5-second timeout and auto-removal
The Problem: You must respond within 5 seconds, and after up to 19 retries over 48 hours the subscription is auto-removed, so a sustained outage loses the subscription entirely.
Why It Happens: SHOPLINE caps the ack time and prunes failing subscriptions.
Workarounds:
- Acknowledge fast, process off a queue, and monitor/recreate a removed subscription; dedupe on
X-Shopline-Webhook-Id(stable across resends).
How Hookdeck Can Help: Hookdeck acknowledges within the window, deduplicates on the webhook id, and retries to your downstream on its own schedule, so the subscription stays alive. See our guide to webhook idempotency.
Raw-body handling
The Problem: The signature is over the raw body, so a JSON parser upstream breaks verification.
Why It Happens: The signed content is the exact bytes.
Workarounds:
- Capture the raw body before parsing.
How Hookdeck Can Help: Hookdeck verifies against the bytes as received.
Best practices
Include api_version when creating webhooks
Put api_version in the POST /webhooks.json body, or creation fails with a 400.
Verify the lowercase-hex signature over the raw body
Compute a lowercase-hex HMAC-SHA256 over the raw body with the app secret and compare in constant time.
Acknowledge within 5 seconds, process asynchronously
Return 200 quickly and defer work to a queue. See why to process webhooks asynchronously.
Dedupe on the webhook id
Use X-Shopline-Webhook-Id (stable across resends) as an idempotency key.
Use the newer Open Platform
Follow developer.shopline.com for headers, topics, and the subscribe endpoint.
Make SHOPLINE webhooks production-ready
Hookdeck verifies X-Shopline-Hmac-Sha256, deduplicates, and durably queues every store event
Conclusion
SHOPLINE webhooks are a Shopify-style clone, with two things the docs get wrong or gloss over: the X-Shopline-Hmac-Sha256 signature is lowercase hex (not base64), and webhook creation requires api_version in the body or it 400s. Verify the hex HMAC over the raw body, use the slash-format topics, acknowledge within 5 seconds, and dedupe on the webhook id to survive the 48-hour retry window and auto-removal.
Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique store events.
Get started with Hookdeck for free and handle SHOPLINE webhooks reliably in minutes.