Overview
Webhooks allow Sticker to notify your application in real-time when important events occur, such as orders being placed, shipped, or delivered.
Webhooks are optional but recommended for keeping your system in sync with order status changes.
Webhook Events
Sticker sends webhooks for the following events:
order.created
When a new order is placed
order.confirmed
When an order is confirmed and processing begins
order.shipped
When an order ships with tracking information
order.delivered
When an order is successfully delivered
order.cancelled
When an order is cancelled
order.refunded
When an order refund is processed
Webhook Configuration
Contact the Sticker team to configure webhooks for your integration:
Email: partners@sticker.com
Subject: Webhook Configuration for [Your Company]
Include:
- Your Partner ID
- Webhook URL (HTTPS required)
- Events to subscribe to
- Preferred secret key for signature verification
Webhook Payload
All webhook requests are POST requests with JSON payloads:
{
"event": "order.shipped",
"timestamp": "2024-12-11T15:30:00Z",
"data": {
"order_id": "550e8400-e29b-41d4-a716-446655440000",
"partner_org_id": "acme_sf_001",
"status": "shipped",
"tracking_number": "1Z999AA10123456784",
"carrier": "ups",
"estimated_delivery": "2024-12-15T12:00:00Z",
"items": [
{
"product_id": "prod_123",
"name": "Nitrile Gloves - Medium",
"quantity": 100,
"price": 24.99
}
],
"total": 24.99,
"shipping_address": {
"line1": "123 Medical Plaza",
"city": "San Francisco",
"state": "CA",
"zip": "94102"
}
}
}
Sticker includes the following headers with each webhook:
Content-Type: application/json
X-Sticker-Event: order.shipped
X-Sticker-Signature: sha256=abc123...
X-Sticker-Delivery-ID: uuid-here
X-Sticker-Timestamp: 1639584000
Signature Verification
Always verify webhook signatures to ensure requests are from Sticker:
Extract Signature
Get the signature from the X-Sticker-Signature header
Get Raw Body
Read the raw request body (before parsing JSON)
Compute HMAC
Calculate HMAC-SHA256 of the body using your webhook secret
Compare
Use constant-time comparison to match signatures
Verification Examples
const crypto = require('crypto');
app.post('/webhooks/sticker', (req, res) => {
const signature = req.headers['x-sticker-signature'];
const webhookSecret = process.env.STICKER_WEBHOOK_SECRET;
// Get raw body (use express.raw middleware)
const rawBody = req.body.toString('utf8');
// Compute expected signature
const expectedSignature = `sha256=${crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex')}`;
// Constant-time comparison
const signatureBuffer = Buffer.from(signature);
const expectedBuffer = Buffer.from(expectedSignature);
if (signatureBuffer.length !== expectedBuffer.length ||
!crypto.timingSafeEqual(signatureBuffer, expectedBuffer)) {
console.error('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}
// Signature valid, process webhook
const event = JSON.parse(rawBody);
handleWebhook(event);
res.status(200).send('OK');
});
Event Data Structures
order.created
{
"event": "order.created",
"timestamp": "2024-12-11T10:00:00Z",
"data": {
"order_id": "uuid",
"partner_org_id": "your_org_id",
"user_email": "user@example.com",
"status": "pending",
"items": [...],
"subtotal": 100.00,
"tax": 8.50,
"shipping": 10.00,
"total": 118.50,
"payment_method": "credit_card",
"shipping_address": {...}
}
}
order.shipped
{
"event": "order.shipped",
"timestamp": "2024-12-13T14:30:00Z",
"data": {
"order_id": "uuid",
"partner_org_id": "your_org_id",
"status": "shipped",
"tracking_number": "1Z999AA10123456784",
"carrier": "ups",
"tracking_url": "https://tracking.ups.com/...",
"estimated_delivery": "2024-12-15T12:00:00Z",
"shipped_at": "2024-12-13T14:30:00Z"
}
}
order.delivered
{
"event": "order.delivered",
"timestamp": "2024-12-15T11:45:00Z",
"data": {
"order_id": "uuid",
"partner_org_id": "your_org_id",
"status": "delivered",
"delivered_at": "2024-12-15T11:45:00Z",
"signature": "John Smith"
}
}
Handling Webhooks
Acknowledge Quickly
Respond with 200 OK immediately, then process asynchronously:
app.post('/webhooks/sticker', async (req, res) => {
// Verify signature first
if (!verifySignature(req)) {
return res.status(401).send('Invalid signature');
}
// Acknowledge receipt immediately
res.status(200).send('OK');
// Process webhook asynchronously
const event = req.body;
processWebhookAsync(event).catch(error => {
console.error('Webhook processing failed:', error);
});
});
async function processWebhookAsync(event) {
// Your business logic here
await updateOrderStatus(event.data.order_id, event.data.status);
await notifyUser(event.data.user_email, event);
await syncWithInternalSystems(event);
}
Idempotency
Handle duplicate webhook deliveries:
const processedWebhooks = new Set();
async function handleWebhook(event) {
const deliveryId = event.delivery_id;
// Check if already processed
if (processedWebhooks.has(deliveryId)) {
console.log('Duplicate webhook, skipping');
return;
}
// Process webhook
await updateOrderStatus(event.data);
// Mark as processed
processedWebhooks.add(deliveryId);
// Clean up old IDs after 24 hours
setTimeout(() => processedWebhooks.delete(deliveryId), 24 * 60 * 60 * 1000);
}
Retry Failed Webhooks
Sticker automatically retries failed webhooks:
- Retry schedule: 1m, 5m, 15m, 1h, 6h, 24h
- Max retries: 6 attempts
- A webhook is considered failed if your server:
- Doesn’t respond within 30 seconds
- Returns a status code other than 200-299
- Connection times out or fails
If all retries fail, the webhook is marked as failed and you’ll receive an alert email.
Testing Webhooks
Local Testing with ngrok
Use ngrok to test webhooks locally:
# Start ngrok
ngrok http 3000
# Use the ngrok URL as your webhook endpoint
https://abc123.ngrok.io/webhooks/sticker
Sticker provides a webhook testing tool in the partner dashboard:
- Go to
https://partners.sticker.com/webhooks
- Select an event type
- Click “Send Test Webhook”
- Verify your endpoint receives and processes it correctly
Manual Testing
Send a test webhook request:
curl -X POST https://yourapp.com/webhooks/sticker \
-H "Content-Type: application/json" \
-H "X-Sticker-Event: order.created" \
-H "X-Sticker-Signature: sha256=test_signature" \
-d '{
"event": "order.created",
"data": {...}
}'
Monitoring Webhooks
Track webhook delivery in your partner dashboard:
- Delivery success rate
- Average response time
- Failed webhooks
- Retry attempts
Success Rate
Monitor % of successful deliveries
Response Time
Track how fast your endpoint responds
Failed Deliveries
Review and replay failed webhooks
Best Practices
Never process webhooks without signature verification
Return 200 OK immediately, process asynchronously
Use delivery IDs to detect and skip duplicate events
Handle transient failures gracefully in your processing logic
Log all webhook receipts, processing, and errors
Webhook endpoints must use HTTPS in production
Troubleshooting
- Verify your webhook URL is correct and accessible
- Check firewall rules allow traffic from Sticker
- Ensure your server responds within 30 seconds
- Check webhook logs in partner dashboard
Signature Verification Fails
- Use the exact raw request body (before parsing)
- Verify webhook secret is correct
- Check for any middleware modifying the body
- Use constant-time comparison functions
- This is normal behavior for reliability
- Implement idempotency using delivery IDs
- Make webhook processing idempotent
Next Steps