Skip to main content

Webhooks Overview

Webhooks allow you to receive real-time notifications when order status changes occur in Courimax.

How Webhooks Work

  1. Configure Webhook URL: Set your endpoint URL when creating an API key
  2. Events Occur: Order status changes trigger webhook events
  3. HTTP POST: Courimax sends POST requests to your endpoint
  4. Process Events: Your application processes the events

Configuring Webhooks

Set your webhook URL when creating an API key:

curl -X POST "https://api.courimax.com/api/provisioning/organizations/org-uuid/api-keys" \
-H "X-Provisioning-Secret: your_secret" \
-H "Content-Type: application/json" \
-d '{
"name": "Production API Key",
"platform": "yango",
"webhookUrl": "https://your-app.com/webhooks/courimax"
}'

Webhook Security

HTTPS Required

All webhook endpoints must use HTTPS. HTTP endpoints will be rejected.

Signature Verification

Each webhook request includes a signature in the X-Courimax-Signature header:

X-Courimax-Signature: sha256=abc123...

Verify the signature to ensure the request is authentic:

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');

return `sha256=${expectedSignature}` === signature;
}

// In your webhook handler
app.post('/webhooks/courimax', (req, res) => {
const signature = req.headers['x-courimax-signature'];
const payload = JSON.stringify(req.body);

if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}

// Process webhook
handleWebhook(req.body);
res.status(200).send('OK');
});

IP Whitelisting

For additional security, whitelist Courimax webhook IPs:

52.86.0.0/16
54.239.0.0/16

Contact support for the complete list of webhook source IPs.

Retry Policy

If your endpoint returns a non-2xx response, Courimax will retry:

  • Attempt 1: Immediate
  • Attempt 2: After 1 minute
  • Attempt 3: After 5 minutes
  • Attempt 4: After 30 minutes
  • Attempt 5: After 2 hours

After 5 failed attempts, the webhook is marked as failed and can be manually replayed.

Timeout

Webhook requests timeout after 30 seconds. Your endpoint should:

  1. Respond quickly with 200 OK
  2. Process events asynchronously
  3. Handle idempotency (events may be delivered multiple times)

Monitoring Webhook Deliveries

Check webhook delivery status via the admin API:

curl -X GET "https://api.courimax.com/api/admin/integrations/webhook-deliveries?limit=50" \
-H "Authorization: Bearer your_jwt_token"

Response:

[
{
"id": "delivery-uuid",
"event": "order.delivered",
"webhookUrl": "https://your-app.com/webhooks/courimax",
"status": "success",
"responseCode": 200,
"attemptedAt": "2026-08-19T12:00:00.000Z",
"responseTime": 150
}
]

Replaying Failed Webhooks

Manually replay failed webhook deliveries:

curl -X POST "https://api.courimax.com/api/admin/integrations/webhook-deliveries/delivery-uuid/replay" \
-H "Authorization: Bearer your_jwt_token"

Best Practices

Respond Quickly

Return 200 OK immediately and process events asynchronously:

app.post('/webhooks/courimax', async (req, res) => {
// Respond immediately
res.status(200).send('OK');

// Process asynchronously
try {
await processWebhookEvent(req.body);
} catch (error) {
logger.error('Webhook processing failed', error);
}
});

Handle Idempotency

Webhooks may be delivered multiple times. Use the event ID to deduplicate:

const processedEvents = new Set();

app.post('/webhooks/courimax', (req, res) => {
const eventId = req.body.id;

if (processedEvents.has(eventId)) {
return res.status(200).send('Already processed');
}

processedEvents.add(eventId);
handleWebhook(req.body);
res.status(200).send('OK');
});

Verify Signatures

Always verify webhook signatures to prevent spoofing:

if (!verifyWebhookSignature(payload, signature, secret)) {
logger.warn('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}

Log Everything

Log all webhook deliveries for debugging:

app.post('/webhooks/courimax', (req, res) => {
logger.info('Webhook received', {
event: req.body.event,
id: req.body.id,
timestamp: req.body.at
});

handleWebhook(req.body);
res.status(200).send('OK');
});

Monitor Failures

Set up alerts for webhook failures:

app.post('/webhooks/courimax', async (req, res) => {
try {
await processWebhookEvent(req.body);
res.status(200).send('OK');
} catch (error) {
logger.error('Webhook processing failed', error);
// Send alert
sendAlert('Webhook processing failed', error);
res.status(500).send('Processing failed');
}
});

Testing Webhooks

Local Testing

Use ngrok to test webhooks locally:

ngrok http 3000

Set your webhook URL to the ngrok URL:

https://abc123.ngrok.io/webhooks/courimax

Test Events

Trigger test events by creating test orders in sandbox environment.

Webhook Inspector

Use the admin dashboard to inspect webhook deliveries and replay failed events.

Next Steps