Shipping Webhooks
Receive real-time shipping event notifications via webhooks.
Overview
Webhooks allow your application to receive real-time notifications when shipping events occur. Register a webhook endpoint in your Developer Dashboard, and Peeap will send signed POST requests to your URL whenever the subscribed events happen.
Webhook Management: Register and manage webhook endpoints via the Developer Dashboard at https://my.peeap.com/merchant/developer or programmatically via POST /v1/webhooks.
Shipping Events
shipping.delivery.created
Triggered when a new delivery job is created. This event contains the delivery details, including the job number, addresses, and handoff codes.
{
"event": "shipping.delivery.created",
"livemode": true,
"created": 1721640000,
"data": {
"object": {
"job_number": "SHP-A1B2C3D4-X5Y6",
"transaction_id": "txn_abc123",
"order_number": "MKT-ABC123",
"store_name": "Tech Store",
"delivery_address": "456 Main Rd, Bo",
"delivery_city": "Bo",
"pickup_code": "4821",
"delivery_code": "7395",
"shipping_fee": 25.00,
"status": "assigned"
}
}
}shipping.status.updated
Triggered whenever a delivery's status changes. This includes driver assignment, pickup, transit updates, delivery completion, and cancellations.
{
"event": "shipping.status.updated",
"livemode": true,
"created": 1721643600,
"data": {
"object": {
"transaction_id": "txn_abc123",
"job_number": "SHP-A1B2C3D4-X5Y6",
"status": "in_transit",
"order_status": "shipped",
"pickup_verified": true,
"delivery_verified": false,
"order_number": "MKT-ABC123"
}
}
}Signature Verification
Every webhook request includes a signature header that you must verify to ensure the request genuinely came from Peeap. The signature is an HMAC-SHA256 hash of the raw request body, computed using your webhook signing secret.
Headers
| Header | Description |
|---|---|
X-Peeap-Signature | HMAC-SHA256 signature of the request body |
X-Peeap-Event | The event type (e.g. shipping.status.updated) |
Verification Example (Node.js)
class="code-keyword">const crypto = class="code-function">require(class="code-keyword">class="code-string">'crypto');
class="code-keyword">function class="code-function">verifyWebhookSignature(body, signature, secret) {
class="code-keyword">const expected = crypto
.class="code-function">createHmac(class="code-keyword">class="code-string">'sha256', secret)
.class="code-function">update(JSON.class="code-function">stringify(body))
.class="code-function">digest(class="code-keyword">class="code-string">'hex');
class="code-keyword">return crypto.class="code-function">timingSafeEqual(
Buffer.class="code-keyword">from(expected),
Buffer.class="code-keyword">from(signature)
);
}
class="code-keyword">class=class="code-keyword">class="code-string">"code-comment">// Express.js middleware example
app.class="code-function">post(class="code-keyword">class="code-string">'/webhooks/peeap', (req, res) => {
class="code-keyword">const signature = req.headers[class="code-keyword">class="code-string">'x-peeap-signature'];
class="code-keyword">const event = req.headers[class="code-keyword">class="code-string">'x-peeap-event'];
class="code-keyword">if (!class="code-function">verifyWebhookSignature(req.body, signature, process.env.PEEAP_WEBHOOK_SECRET)) {
class="code-keyword">return res.class="code-function">status(401).class="code-function">json({ error: class="code-keyword">class="code-string">'Invalid signature' });
}
class="code-function">switch(event) {
case class="code-keyword">class="code-string">'shipping.delivery.created':
console.class="code-function">log(class="code-keyword">class="code-string">'New delivery:', req.body.data.object.job_number);
break;
case class="code-keyword">class="code-string">'shipping.status.updated':
console.class="code-function">log(class="code-keyword">class="code-string">'Status update:', req.body.data.object.status);
break;
}
res.class="code-function">status(200).class="code-function">json({ received: class="code-keyword">true });
});Best Practices
- Always verify signatures — Use the signing secret shown once when creating the webhook to verify every request.
- Respond quickly — Your endpoint should respond with a 200 status within 10 seconds. Heavy processing should be queued.
- Expect retries — If your endpoint returns a non-200 status, Peeap will retry up to 3 times with exponential backoff.
- Use idempotent processing — The same event may be delivered more than once. Use the job number and status to detect duplicates.
- Monitor deliveries — Use the Developer Dashboard to view delivery logs and redeliver failed events after fixing your endpoint.