Agent skill
Sendcloud Webhooks Skill
Receive and verify Sendcloud shipping webhooks. Use when setting up a Sendcloud webhook endpoint, debugging Sendcloud-Signature HMAC-SHA256 verification, or handling actions like parcel_status_changed, return_created, integration_connected, integration_updated and integration_deleted.
Install this skill
npx skills add hookdeck/webhook-skills --skill sendcloud-webhooks
Sendcloud is a shipping platform. Its webhooks notify your application when a parcel changes status, when a return is created, and when an integration is connected, modified or deleted. Every webhook request is signed with an HMAC-SHA256 signature in the Sendcloud-Signature header. Webhooks are scoped to the integration they are configured on.
When to Use This Skill
- How do I receive Sendcloud webhooks?
- How do I verify the
Sendcloud-Signatureheader? - Where do I find the Sendcloud webhook secret (Secret Key or Webhook Signature Key)?
- How do I handle
parcel_status_changedorreturn_createdwebhooks? - Why is my Sendcloud webhook signature verification failing?
- How do I deal with out-of-order Sendcloud parcel updates?
Verification (core)
| Item | Value |
|---|---|
| Header | Sendcloud-Signature |
| Algorithm | HMAC-SHA256 |
| Signed content | The entire raw request body, exactly as received |
| Key | Integration Secret Key or Webhook Signature Key, as UTF-8 |
| Encoding | Bare lowercase hex (no prefix, no timestamp) |
Sendcloud has no webhook SDK, so verification is manual:
const crypto = require('crypto');
// rawBody: Buffer of the exact request body, NOT re-serialised JSON
function verifySendcloudSignature(rawBody, signature, secret) {
if (!signature || !secret) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Docs test vector: body {"key": "value"} with secret secretkey gives 1eed4b3d41f4653ac64fd56f1bf1cbfd349e4482cbc11dff7134bd93e5da4b0a.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Event Envelope
The event type is in the action field (there is no event type header). Payloads carry a timestamp and no event ID.
{ "action": "parcel_status_changed", "timestamp": 1525271885993,
"parcel": { "id": 1, "tracking_number": "3SYZXG132912330", "status": { "id": 1, "message": "Ready to send" } } }
Common Event Types
action | Fired when |
|---|---|
parcel_status_changed | A parcel of this integration shifts to a different status |
return_created | A return is created via the API or Return Portal (not via the Return Form) |
integration_connected | The integration is created |
integration_updated | The integration is modified |
integration_deleted | The integration is deleted |
Delivery Semantics
- Return a
2xxwithin 10 seconds. Sendcloud makes up to 10 attempts over about an hour and a half: the first retry is within 5 minutes and later waits grow to roughly half an hour. - Timeouts, an unreachable endpoint,
406,408,409,429and5xxare retried. Any other4xx, such as400,401,404or422, stops delivery with no retry, so return a5xxfor temporary problems. Every failed attempt appears in the connection issue log. - Webhooks can arrive out of order. Use the payload
timestampto find the latest parcel update, and make handlers idempotent. - Read the body raw (Express:
express.raw({ type: '*/*' })) so any content type verifies.
Environment Variables
SENDCLOUD_WEBHOOK_SECRET=your_secret_key_or_webhook_signature_key
Local Development
# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 sendcloud --path /webhooks/sendcloud
Put the printed URL in the integration's Webhook url field and use Test API webhook to send a test request.
Reference Materials
- references/overview.md - Events and payload fields
- references/setup.md - Integration configuration and secrets
- references/verification.md - Signature details, gotchas, debugging