Skip to main content

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"
    }
  }
}

Webhook Headers

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:
1

Extract Signature

Get the signature from the X-Sticker-Signature header
2

Get Raw Body

Read the raw request body (before parsing JSON)
3

Compute HMAC

Calculate HMAC-SHA256 of the body using your webhook secret
4

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

Webhook Testing Tool

Sticker provides a webhook testing tool in the partner dashboard:
  1. Go to https://partners.sticker.com/webhooks
  2. Select an event type
  3. Click “Send Test Webhook”
  4. 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
  • 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