Skip to content

Webhooks

Webhooks deliver real-time shipment status updates to your HTTP endpoint as they occur. This is one of two status relay methods supported by Duty Pro (the other being SFTP).

Configure your webhook endpoint in the dashboard under Settings > Status Relay:

  1. Select Webhook as the relay method.
  2. Enter your endpoint URL (must accept POST requests).
  3. Optionally provide a webhook secret for signature verification.
  4. Optionally provide a basic auth username and password if your endpoint requires HTTP Basic authentication. Both fields must be set together.

Duty Pro sends a POST request with a JSON body. Two examples:

// shipment_created
{
"event": "shipment_created",
"reference": "ORD-2026-00123",
"shipment_status": "PENDING",
"test": false,
"email_sent": 0,
"sms_sent": 0,
"held": true,
"held_on_error": false,
"canceled": false
}
// payment_completed
{
"event": "payment_completed",
"reference": "ORD-2026-00123",
"shipment_status": "PAID",
"test": false,
"email_sent": 1,
"sms_sent": 1,
"held": false,
"held_on_error": false,
"canceled": false
}
FieldTypeDescription
eventstringThe event key that triggered this delivery (e.g. shipment_created, payment_completed)
referencestringYour shipment reference number
shipment_statusstringThe shipment’s current payment status (PENDING, PAID, FAILED, or EXPIRED)
testbooleantrue for shipments created with a test API key (dp_test_...), false for live shipments
email_sentnumberNumber of emails successfully sent to the consignee for this shipment
sms_sentnumberNumber of SMS messages successfully sent to the consignee for this shipment
heldbooleantrue when the shipment is held and customs payment is required
held_on_errorbooleantrue if the shipment is held because of a calculation error
canceledbooleantrue if the payment has expired

The full list of available events is shown in the dashboard under Settings > Status Relay. From that screen you can also choose which events should be relayed; unchecked events are skipped.

If your receiving system expects different field names, contact the Duty Pro team to configure custom key mappings for your account. For example, reference can be mapped to barcode or any other name your system requires.

Every webhook request includes the following headers:

HeaderDescription
Content-Typeapplication/json
X-DutyPro-SignatureHMAC-SHA256 signature (only if a webhook secret is configured)
AuthorizationBasic <base64(username:password)> (only if basic auth credentials are configured)

If you configured a webhook secret, every request includes an X-DutyPro-Signature header containing an HMAC-SHA256 signature. Verify it to ensure the request is authentic and hasn’t been tampered with.

  1. Extract the X-DutyPro-Signature header value.
  2. Serialize the request body as JSON with keys sorted alphabetically.
  3. Compute HMAC-SHA256 using your webhook secret as the key and the serialized body as the message.
  4. Compare the computed signature with the header value.
import hmac
import hashlib
import json
def verify_signature(payload: dict, secret: str, signature: str) -> bool:
body = json.dumps(payload, sort_keys=True).encode()
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
const crypto = require('crypto');
function verifySignature(payload, secret, signature) {
const body = JSON.stringify(payload, Object.keys(payload).sort());
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}

The first delivery attempt is sent immediately when the event occurs: there is no scheduling delay before the first call.

If your endpoint returns a non-success HTTP status (anything outside 200-299) or the request times out (15-second timeout), Duty Pro retries with exponential backoff:

AttemptTiming
1 (initial)Immediate
2 (1st retry)1 minute after attempt 1 fails
3 (2nd retry)2 minutes after attempt 2 fails
4 (3rd retry)4 minutes after attempt 3 fails
5 (4th retry)8 minutes after attempt 4 fails

After 5 failed attempts, the relay is marked as FAILED. You can view failed deliveries in the dashboard under Settings > Status Relay logs, or in the shipment detail view.

Your endpoint should:

  • Return a 2xx status code to acknowledge receipt.
  • Respond within 15 seconds.
  • Process the event idempotently; the same event may be delivered more than once during retries.

All webhook delivery attempts (successful and failed) are logged and visible in two places:

  • Shipment detail view: the “Status Relay Log” section shows relay events for that specific shipment, including payload, response code, and error messages.
  • Settings > Status Relay: shows the overall relay configuration and recent delivery history.