Security
Webhook reliability depends as much on your endpoint's behavior as on Unico's delivery guarantees. This page covers the three invariants your endpoint must respect: idempotency, concurrency limit, and error rate.
Idempotency
Unico's webhook implementation guarantees at-least-once delivery — the same status may be notified more than once for the same processId. Your endpoint must be idempotent.
Recommended pattern:
- On every webhook call, first check whether
processIdhas already been processed. - If it has, return
2xximmediately (the work is already done). - If not, apply your business logic and persist the fact that this
processIdwas processed.
// pseudo-code
async function handleWebhook(req, res) {
const { processId } = req.body;
if (await alreadyProcessed(processId)) {
return res.status(200).end();
}
await applyBusinessLogic(req.body);
await markAsProcessed(processId);
return res.status(200).end();
}
A non-idempotent endpoint that runs business logic on every delivery (e.g., charges a card, sends an email) will multi-fire when a retry happens — and retries are normal, not exceptional, in webhook delivery.
Concurrency limit
To protect your endpoint from spikes during high-volume periods, configure a maximum number of simultaneous in-flight deliveries (max: 500) when registering the webhook.
When the concurrency limit is reached, Unico queues additional deliveries and processes them as capacity becomes available. Combined with retries, this means a sustained spike can extend the effective delivery time of new webhooks.
Error rate
The error rate (responses outside the 200–299 range) should always be low. If your endpoint starts returning errors at scale, Unico automatically reduces the webhook throughput for that endpoint. Combined with the retry mechanism, this can significantly increase the execution time of new webhooks.
Operational guidance:
- Monitor non-2xx responses on your side. Alert on sustained error rates above your normal baseline.
- Treat your webhook handler as a critical path — it should be one of the most reliable services in your stack.
- For planned maintenance, prefer stopping intake at the load balancer rather than returning
503. Sustained non-2xx responses — including503— activate the automatic throughput throttling described above; when your endpoint recovers, the reduced throughput delays delivery of events that queued up during the outage. Do not return200for unprocessed events.
Status semantics
Treat the set of state and lastEvent values as evolvable configuration:
- React only to states / events you explicitly handle.
- Log unknown values — do not error out on them.
- New states may be added without a major version change.