Agent skill
Commerce Layer Webhooks Skill
Receive and verify Commerce Layer webhooks. Use when setting up Commerce Layer webhook handlers, debugging X-CommerceLayer-Signature verification, or handling commerce events like orders.place, orders.approve, orders.pay, or shipments.ship.
Install this skill
npx skills add hookdeck/webhook-skills --skill commercelayer-webhooks
When to Use This Skill
- How do I receive Commerce Layer webhooks?
- How do I verify Commerce Layer webhook signatures?
- How do I handle
orders.place,orders.approve, ororders.payevents? - Why is my Commerce Layer
X-CommerceLayer-Signatureverification failing? - Setting up a Commerce Layer callback endpoint for order/shipment events
Verification (core)
Commerce Layer signs the raw request body with HMAC-SHA256 keyed on the webhook's shared_secret and sends the digest as base64 in the X-CommerceLayer-Signature header. The triggering topic is in X-CommerceLayer-Topic. The shared_secret is returned once, in the response when you create the webhook (POST /api/webhooks) — it is not the same as your API credentials.
Read the raw body, NOT the parsed one. Re-serializing parsed JSON changes bytes (key order, whitespace) and breaks the signature. Commerce Layer has no SDK verify helper, so verify manually (this matches the official docs example).
Node:
const crypto = require('crypto');
function verifyCommerceLayerSignature(rawBody, signature, sharedSecret) {
if (!signature) return false;
const expected = crypto
.createHmac('sha256', sharedSecret)
.update(rawBody) // rawBody is a Buffer/string — never JSON.parse first
.digest('base64');
try {
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
} catch {
return false; // length mismatch = invalid
}
}
Python:
import hmac, hashlib, base64
def verify_commercelayer_signature(raw_body: bytes, signature: str, shared_secret: str) -> bool:
if not signature:
return False
expected = base64.b64encode(
hmac.new(shared_secret.encode(), raw_body, hashlib.sha256).digest()
).decode()
return hmac.compare_digest(signature, expected)
For complete handlers with route wiring, event dispatch, and tests, see:
Common Event Types (Topics)
Topics use the format {resource}.{trigger}.
| Topic | Triggered When |
|---|---|
orders.place | Customer places an order |
orders.approve | Order is approved |
orders.cancel | Order is cancelled |
orders.pay | Order is paid (payment captured) |
orders.refund | Order is refunded |
customers.create | A new customer is created |
shipments.ship | A shipment is shipped |
shipments.deliver | A shipment is delivered |
Commerce Layer supports 100+ topics across
orders,customers,shipments,returns,refunds,authorizations,captures,gift_cards, and more. For the full list, see references/overview.md and the Commerce Layer webhooks docs.
Payload: JSON:API format, identical to fetching the resource via the REST API — { "data": { "id", "type", "attributes", "relationships" } }. For .destroy topics only data.id is populated (other attributes are null).
Environment Variables
COMMERCELAYER_SHARED_SECRET=your_webhook_shared_secret # returned when you create the webhook
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 commercelayer --path /webhooks/commercelayer
Reliability & Retries
- Your endpoint must return a 2xx status within 5 seconds.
- Failed deliveries are retried up to 10 times.
- After 5 unsuccessful attempts, the organization owner/admins are notified.
- After 30 consecutive failures the webhook's circuit breaker trips (
circuit_state→open, tracked viacircuit_failure_count) and it must be reset manually. (closedis the healthy default state.)
Verify fast, then do slow work asynchronously so you always answer within 5 seconds.
Reference Materials
- references/overview.md - Commerce Layer webhook concepts and topics
- references/setup.md - Create a webhook, get the shared_secret
- references/verification.md - Signature verification details and gotchas