Agent skill

parcelLab Webhooks Skill

Receive and authenticate parcelLab post-purchase tracking webhooks. Use when setting up a parcelLab webhook endpoint, checking the HTTP Basic Authorization header, debugging 401s, or handling shipment events such as onDispatch, onOutForDelivery, onDelivered and onReturn.

Install this skill

npx skills add hookdeck/webhook-skills --skill parcellab-webhooks


parcelLab (post-purchase tracking and delivery notifications) sends a webhook to your HTTPS endpoint each time a consignment changes status. Payloads are not signed. parcelLab sets webhooks up for you from the URL and credentials you give it, and supports three authentication mechanisms: HTTP Basic, access token headers and OAuth 2.0. This skill covers HTTP Basic.

When to Use This Skill

  • How do I receive parcelLab webhooks?
  • How do I verify the parcelLab Authorization: Basic header?
  • Does parcelLab sign webhook payloads? (No: shared credentials only)
  • Why does my parcelLab webhook endpoint return 401?
  • How do I handle onDispatch, onOutForDelivery or onDelivered events?

Verification (core)

Give parcelLab a username and password along with your HTTPS URL. It sends them as Authorization: Basic base64(username:password). Split the decoded value on the first colon, then compare username and password each in constant time, evaluating both before deciding:

const crypto = require('crypto');

const sha = (buf) => crypto.createHash('sha256').update(buf).digest();
const safeEqual = (a, b) => crypto.timingSafeEqual(sha(a), sha(b)); // equal-length digests

function verifyParcellabRequest(headers, config = process.env) {
  const { PARCELLAB_WEBHOOK_USERNAME: user, PARCELLAB_WEBHOOK_PASSWORD: pass } = config;
  if (!user || !pass) return false;                      // never accept when unconfigured
  const m = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(headers['authorization'] || '');
  if (!m) return false;
  const decoded = Buffer.from(m[1], 'base64');
  const colon = decoded.indexOf(0x3a);                   // first colon only
  if (colon < 0) return false;
  const userOk = safeEqual(decoded.subarray(0, colon), Buffer.from(user));
  const passOk = safeEqual(decoded.subarray(colon + 1), Buffer.from(pass));
  return userOk && passOk;                               // no short-circuit
}

Return 401 for a missing or malformed header or any mismatch, 400 for a body that is not a JSON object, and 200 once handled. Read the body raw (express.raw({ type: '*/*' })) so any content type works, and parse JSON only after the credential check. Python and Next.js equivalents are in references/verification.md.

Static credentials authenticate the sender, not the body. There is no signature and no timestamp, so a captured request can be replayed and the body can't be proven untampered. Use HTTPS only (parcelLab doesn't support plain HTTP), keep the credential secret, and rotate it if it leaks. Deduplicate on eventid.

Credentials must arrive on the first request. The docs don't say whether parcelLab sends Basic credentials preemptively, so assume it does. A 401 + WWW-Authenticate challenge flow won't work, and it won't work through Hookdeck either, which verifies the request as received.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Types

The event name is in the event field of the JSON body:

EventFires when
onCreated / onUpdatedA record is created or updated from retailer data
onDispatchFirst carrier scan (once per consignment)
onScheduledCarrier announces or changes the delivery day or window
onOutForDeliveryConsignment is out for delivery
onDelay / onInternalDelayCarrier delay, or the consignment wasn't shipped in time
onFailedAttemptDelivery attempted but recipient not met or location not accessible
onPickupReadyReady for collection at an access point or locker
onDeliveredFinal: delivered
onReturnFinal: being returned to the sender

parcelLab can also send CloudEvents format, where type is com.parcellab.tracking.event.<lowercased event> and the data sits under data. The examples handle both shapes. There is no event deduplication on parcelLab's side.

Environment Variables

PARCELLAB_WEBHOOK_USERNAME=parcellab
PARCELLAB_WEBHOOK_PASSWORD=replace-with-a-long-random-password

Local Development

npx hookdeck-cli listen 3000 parcellab --path /webhooks/parcellab

No account required. Give the printed URL, plus your Basic credentials, to parcelLab as the webhook target.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 5, 2026

View on GitHub →