Skip to main content

Overview

Webhooks notify your server when events happen in Shoppex. Use them to:
  • Fulfill orders automatically
  • Update your database
  • Send custom notifications
  • Integrate with external services

Setting Up Webhooks

1

Create Endpoint

Create an HTTP endpoint on your server that accepts POST requests:
app.post('/webhooks/shoppex', (req, res) => {
  const event = req.body;
  // Handle event
  res.status(200).send('OK');
});
2

Register in Dashboard

Go to Settings → Webhooks → Add Endpoint and enter your URL.
3

Select Events

Choose which events you want to receive:
  • invoice.* - All invoice events
  • subscription.* - All subscription events
  • Or select specific events

Webhook Payload

All webhooks follow this structure:
{
  "event": "order:paid",
  "data": {
    "uniqid": "abc123def456",
    "type": "PRODUCT",
    "status": "COMPLETED",
    "gateway": "STRIPE",
    "total": 29.99,
    "currency": "USD",
    "customer_email": "[email protected]",
    // ... more event-specific fields
  },
  "created_at": 1705314650
}
Timestamps are Unix timestamps (seconds since epoch), not ISO strings.

Available Events

Order Events

EventDescription
order:paidOrder/invoice paid successfully
order:cancelledOrder cancelled or expired
order:paid:productOrder paid (includes full product data)
order:cancelled:productOrder cancelled (includes full product data)

Subscription Events

EventDescription
subscription:createdNew subscription started
subscription:cancelledSubscription cancelled

Verifying Webhooks

Always verify webhook signatures to ensure authenticity. Shoppex signs webhooks using HMAC-SHA512:
import crypto from 'crypto';

function verifyWebhook(payload: string, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac('sha512', secret)  // Note: SHA512, not SHA256
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

app.post('/webhooks/shoppex', (req, res) => {
  const signature = req.headers['x-shoppex-signature'] as string;
  const isValid = verifyWebhook(req.rawBody, signature, WEBHOOK_SECRET);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Process webhook based on event type
  const { event, data } = req.body;

  switch (event) {
    case 'order:paid':
      // Handle successful payment
      break;
    case 'order:cancelled':
      // Handle cancellation
      break;
  }

  res.status(200).send('OK');
});

Webhook Headers

HeaderDescription
X-Shoppex-EventThe event type (e.g., order:paid)
X-Shoppex-SignatureHMAC-SHA512 signature
X-Shoppex-DeliveryUnique delivery ID for deduplication

Retry Policy

If your endpoint returns an error (non-2xx status), we retry:
AttemptDelay
1Immediate
25 minutes
330 minutes
42 hours
524 hours
After 5 failed attempts, the webhook is marked as failed. You can manually retry from the dashboard.
Your endpoint must respond within 30 seconds or the request will timeout.

Best Practices

Process webhooks asynchronously. Return 200 immediately and handle the event in a background job.
Webhooks may be delivered more than once. Use the id field to deduplicate.
Always verify webhook signatures in production to prevent spoofing.