Webhook Delivery and Failure Handling
This page covers what happens after an event fires in Enate: how the message reaches you, what Enate does when your endpoint doesn't accept it, and the behaviours you need to design your receiving endpoint around.
How Delivery Works
When an event you've subscribed to occurs, Enate doesn't call your endpoint during the operation that caused it. It queues the message and delivers it separately, shortly afterwards. Saving a Case in Work Manager doesn't wait for your system to respond, and a slow or unavailable endpoint of yours never slows down or blocks work in Enate.
Delivery is a single HTTP POST to your SubscriberURL, carrying the x-enate-signature header and your optional custom header. See How a Webhook Message Is Sent for the full shape of the request.
Enate sends one POST per event per matching subscription. Two subscriptions that both match the same event produce two separate POSTs, each with its own signature and its own custom header.
What Counts as Success
Enate treats any 2xx response as success. Every other status code is a failure, and so is a connection that can't be established or a response that never arrives.
Point your SubscriberURL at the endpoint that does the work, rather than at something that redirects to it. A redirect adds a round trip to every message, and some redirect responses change the request method, so the endpoint at the end of the chain may not receive the POST body you're expecting.
Enate doesn't set a timeout of its own on the call, so the platform default of around 100 seconds applies. An endpoint that takes longer than that to reply is treated as a failure and the message is retried, even if your system went on to process it successfully. Acknowledge the message quickly with a 2xx and do your processing afterwards, rather than holding the connection open while you work.
Retries and Failed Deliveries
Maximum delivery attempts
10, including the first
What happens between attempts
The message goes back on the queue and Enate delivers it again
What happens after the tenth failed attempt
The message is discarded. It isn't retried further and won't reach your endpoint
Notification of a message that failed all 10 attempts
None. Enate doesn't email you, raise a Work Item, or mark the subscription
Effect on the subscription
None. It stays active and the next event is attempted normally
Messages Enate Doesn't Attempt at All
Two situations produce no message, and no failure either:
The subscribing account has lost permission. Enate re-checks the subscribing account's permission on the scoped object every time it prepares a message. If the account no longer has read access, that individual message is skipped silently. The subscription itself isn't deleted, so messages resume if the permission is restored.
The subscription no longer exists. PacketUpdated subscriptions are deleted automatically when the work item closes, so nothing is sent for it after that point.
Test Work Items Raise Webhooks Too
A work item running against a process version in Testing state raises exactly the same Webhook events as a live one. Enate doesn't suppress them, and the message body carries no field that tells you which kind you've received.
The practical way to keep test traffic out of a downstream system is to scope your subscriptions so it never matches in the first place. Subscriptions are matched on the Company, Contract, Service or process definition you name when you subscribe, so running your process trials under a Contract or Service you haven't subscribed to keeps them off the Webhook entirely. If you can't separate them that way, keep the Webhook subscription pointed at a non production endpoint until the process goes live.
Throughput
Enate delivers Webhook messages with limited concurrency per Enate instance, so a burst of events is delivered over a short period rather than all at once. The limit scales with the size of your Enate instance, and isn't something that can be set per customer. Treat the exact figure as subject to change, and design your endpoint so that it doesn't depend on one.
In practice this matters in two ways:
A large batch operation, for example starting several hundred work items at once, produces a stream of messages spread over time rather than a simultaneous flood at your endpoint.
Your endpoint is still the slower half of the exchange in most cases. An endpoint that takes several seconds per message will hold up the queue for that subscription, because the messages waiting behind it can't be delivered until the in-flight ones finish.
If you're integrating at high volume, accept quickly and process asynchronously. That keeps Enate's delivery moving and keeps you well clear of the timeout.
Delivery Guarantees, Ordering and Duplicates
Expect duplicates
Delivery is at-least-once, so your endpoint has to tolerate receiving the same event more than once. The common causes:
Retries after a partial success. If your endpoint processes a message and then fails to return a 2xx, for example it times out while replying, Enate counts that as a failure and sends the same message again.
Several updates in quick succession. Each update to a work item is its own event, so a burst of changes produces a burst of near identical PacketUpdated messages.
One business event raising two Webhooks. An incoming email linked to a Ticket raises NewCommunication for the email, and, if the email also changes the Ticket, a separate PacketUpdated for the Ticket. If you hold both subscriptions you receive both.
Overlapping subscriptions. A SpecificBusinessObjectUpdated subscription and a BusinessObjectTypeUpdated subscription that both cover the same Company each produce their own message.
Make your handler idempotent. For NewCommunication, the GUID field identifies the communication and is a reliable deduplication key. For Packet events the GUID is the work item rather than the change, so it repeats across every update to that work item. If you need to detect repeats there, compare the payload you've just received against the last one you stored for that work item.
Don't rely on ordering
Messages are not guaranteed to arrive in the order the events happened, and a retry of an earlier message can land after a later one has already been delivered. Two consequences worth designing for:
A PacketUpdated message can arrive carrying an older state than one you've already processed. Treat each message as a snapshot at the time it was produced rather than as a sequential change feed.
If you need the authoritative current state of a work item, call the Enate API for it rather than assuming the last message you received is the latest.
Worked Example: A Resilient Endpoint
A typical receiving endpoint for a NewCommunication subscription on Ticket 200243-T would:
Check the
x-enate-signatureheader against the signature returned when the subscription was created, and reject the request with a 403 if it doesn't match.Read the
GUIDfrom the body, for example31fbfa65-dc39-4c9c-a1f4-47dfef636bea.Check whether that GUID has already been handled. If it has, return 200 and stop.
Write the message to your own queue or table.
Return 200.
Process the message from your own store, outside the request.
That order matters. Steps 4 and 5 are quick, so Enate gets its 2xx well inside the 100 second timeout, and step 3 means a retry costs you nothing. If step 6 fails you can retry it yourself, rather than depending on Enate to send the message again.
Note what the endpoint above does not do: it doesn't return a 4xx when it dislikes a message. A message it can't use is accepted with a 200 and discarded, because a 4xx would simply bring the same message back up to nine more times.
Other limits that apply across the platform, including the rate limits on Enate's APIs, are listed on the Maximum Limits in Enate page:
Maximum Limits in EnateLast updated
Was this helpful?