Skip to main content

Webhooks

Two directions

DirectionAuthPages
Inbound (Sumeru receives)HMAC-verify the source's signatureShopify, WhatsApp, Marketplaces
Outbound (Sumeru sends)We sign; you verifyOutbound (Zapier)

Inbound: how it works

Latency contract

We always ack within 2 seconds (sources retry if slower). Processing happens async; the ack means "received, will process," not "fully processed."

Idempotency

Every webhook event has an event ID. Re-delivery (Shopify retry, replay) is detected via (source, event_id) dedup. Same event processed once.

Failure handling

If processing fails (DB down, etc.), event lands in DLQ:

bull:event-worker:failed

Auto-retry with exponential backoff. After 5 fails, surface in admin failures dashboard.

Outbound: how it works

Subscribing

curl -X POST \
-H "Authorization: Bearer copt_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhook",
"events": ["campaign.completed", "journey.exited"],
"secret": "auto"
}' \
"https://api.sumeru.systems/api/v1/webhook-subscriptions"

secret: auto returns a generated HMAC secret in response — you store + use it to verify signatures.

Verifying outbound webhooks

Header: X-Sumeru-Signature: sha256=<hex>

const crypto = require('crypto');

function verifySumeruWebhook(rawBody, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
try {
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
} catch {
return false;
}
}

Available events

EventFires when
campaign.launchedCampaign send begins
campaign.completedCampaign send + attribution window done
campaign.approved / .rejectedApproval workflow decision
journey.enrolledCustomer enters journey
journey.exitedCustomer exits journey
customer.created / .updatedCustomer 360 changes
lifecycle.changedStage transition
order.attributedAttribution complete for an order
anomaly.firedAnomaly detected
gdpr.completedErasure / export finished

Full event catalog with payload schemas: see per-event page.

Retry policy

5 retries with exponential backoff: 1s, 5s, 30s, 5min, 30min.

After 5 failures, event marked failed; surface in admin webhooks dashboard. Manual replay available.

Best practices

Always verify signatures. Unsigned webhooks = security hole.

Make endpoints idempotent. Same event may arrive twice (retries); your code shouldn't double-process.

Return 2xx fast. Process async if you need to do work; return 200 first.

Set up retry alerts. Failed-webhooks dashboard shows patterns; investigate sustained failure rates.

Don't reject 5xx — retry. If your service is down, return 5xx; we'll retry. Don't return 200 to "stop retries."

Don't use the body in routing logic before signature verification. Body should be opaque until verified.

See also