Event webhooks
Event webhooks push activity from Yellow.ai to your own HTTPS endpoint as it
happens, so you react to changes instead of polling for them. You register an
endpoint, subscribe it to the events you care about, and we POST each one to you
— with automatic retries, per-attempt delivery logs, and health tracking that
disables an endpoint that has been failing for too long.
Today the events available are Inbox ticket events — created, assigned, resolved, edited and so on. The event list in the product is the source of truth for what you can subscribe to.
This is outbound: we call your endpoint. If you want the opposite — Yellow.ai receiving a notification from your system — see Custom Webhook.
This is the push counterpart to the Inbox Ticketing API: instead of polling for changes, you receive them within seconds.
Webhooks are enabled per account. If you don't see the Webhooks tile under Integrations, reach out to our team.
How it works
- Something happens to a ticket — an agent resolves it, a tag changes, a note is added.
- We match the event against your endpoints. An endpoint receives it only if it is enabled and subscribed to that event type.
- We
POSTthe event to your URL and read your response. - On failure we retry on a fixed schedule, backing off as attempts continue.
- Every attempt is written to Delivery logs with its status, latency and reason.
- An endpoint that fails continuously for 48 hours is disabled automatically, and we email you when that happens.
Events that match no endpoint are discarded — there is no queue waiting for you to subscribe later.
Set up an endpoint
The Webhooks screen lists your endpoints with their status, health, event count and when each last succeeded or failed.

-
Go to Integrations and open the Webhooks tile under Tools.
-
Select New endpoint.
-
Fill in the form:
Field Notes Name How the endpoint appears in the list. Description Optional — what the endpoint is for. Webhook URL Must be https://and publicly reachable — see Which URLs are accepted.Authentication See Authentication. Request timeout 3,000–30,000 ms. Default 10,000 ms. Enabled Turn off to pause delivery without deleting the endpoint. -
Under Events, pick the events this endpoint should receive. Search filters the list; Select all takes everything. At least one is required.
-
Select Create endpoint.

You can register up to five endpoints, each with its own URL, authentication and event selection. Paused and auto-disabled endpoints still count toward the five — delete one to free a slot.
Changing an endpoint's event selection takes effect on the next event; it does not backfill.
Send a test event
The Send test event action on any endpoint posts a sample payload immediately and reports the HTTP status, latency and result. It's the fastest way to confirm your URL, firewall rules and response handling before real traffic arrives.
Test events are not recorded in Delivery logs.
Events
Fourteen ticket events are available, all under the Inbox category:
| Event | Fires when |
|---|---|
| Ticket created | A new ticket is created. |
| Ticket assigned | The ticket is assigned to an agent. |
| Ticket reassigned | The ticket moves from one agent to another. |
| Ticket transferred | The ticket moves to a different group. |
| Status changed | The status changes with no more specific event — for example moving to On hold or back to the queue. |
| Ticket resolved | The ticket is marked resolved. |
| Ticket reopened | A resolved ticket is reopened. |
| Ticket closed | The ticket is closed. |
| Ticket merged | The ticket is merged into another ticket. |
| Collaborators changed | A collaborator is added or removed. |
| Priority updated | The ticket priority changes. |
| Tags updated | The ticket tags change. |
| Custom field updated | A custom field on the ticket changes. |
| Note added | A note is added to the ticket. |
The picker only lists events that are actually emitted today. If an event isn't in the list, nothing would ever be sent for it — so you can't subscribe to silence.
Payload
Each delivery is an HTTPS POST with Content-Type: application/json and an
X-Yellow-Event-Id header carrying the event id.
The body is a Kapture-compatible envelope, so if you are migrating from Kapture you can point your existing webhook at us unchanged:
{
"request": {
"head": {
"version": "1.0",
"clientId": "your-client-id",
"function": "dana.kapture.ticket.manage",
"reqTime": "2026-08-06T09:17:54+00:00",
"clientSecret": "…",
"reqMsgId": "3da24fdc-fb26-482f-9146-e4a9be8d495b"
},
"body": {
"externalId": "TCK-10432",
"subject": "Refund not received",
"status": "RESOLVED",
"agentName": "Priya R",
"comment": "",
"externalCommentId": "",
"authorId": "u-8821",
"authorType": "agent",
"orderId": "",
"loginId": "",
"topic": "",
"subTopic": "",
"attachments": []
}
},
"signature": "…"
}
head.clientId and head.function are per-endpoint settings you control.
status carries our ticket status vocabulary as-is — it is not remapped.
Responding
Return a 2xx as soon as you have accepted the event. Don't do slow downstream
work before responding, or you risk hitting the request timeout and being sent a
retry for an event you already processed.
If your response body contains a resultInfo object we read it: resultStatus of
"S" is success and "F" is failure. A plain 2xx with no resultInfo is
treated as success.
Delivery guarantees
At-least-once, so build for duplicates. head.reqMsgId is the event id and
stays the same across every retry of that event — use it as your idempotency key.
Order is best-effort, not guaranteed. A retried event can arrive after a newer one. If sequence matters, order on the event's own timestamp rather than on arrival.
No replay or backfill. Once an event is dropped — because nothing was subscribed, the endpoint was disabled, or every attempt failed — it is not re-delivered, and there is no way to request it again. For workflows where a missed event is costly, reconcile periodically against the Inbox Ticketing API.
Retries
Every event gets up to 12 attempts — the first, plus 11 retries:
| Retry | Delay after the previous attempt |
|---|---|
| 1 | 15 seconds |
| 2 | 5 minutes |
| 3 | 30 minutes |
| 4 | 2 hours |
| 5 | 4 hours |
| 6–11 | 8 hours each |
Each delay carries up to ±20% of randomness so a backlog to one endpoint doesn't arrive as a single burst. After the twelfth failure the event is given up on.
Retry-After wins. If your response carries a Retry-After header — on a
429 or 503, for example — we schedule the next attempt then instead of using
the table, with a floor of 5 seconds. A Retry-After above 24 hours is refused
and the event is dropped, on the grounds that a day-late ticket event is no longer
useful.
What gets retried:
| Retried | Given up immediately |
|---|---|
| Timeouts and connection errors | 400, 410, 422 and other malformed-request responses |
429 rate limits | 501, 505 |
All 5xx except 501/505 | |
401, 403, 404, 408, 425 |
401, 403 and 404 are retried because in practice they're temporary — a
rotated credential, or a route that's missing for the length of a deploy — rather
than a permanent refusal.
Endpoint health
| State | Meaning |
|---|---|
| Unknown | Nothing delivered yet to judge on. |
| Healthy | The last delivery succeeded. |
| Degraded | Recent failures, still delivering. |
| Failing | Five consecutive failures. Delivery pauses for a 5-minute cooldown, then resumes — we stop hammering an endpoint that is clearly down. |
| Deregistered | 48 hours of continuous failure. The endpoint is disabled and stops receiving events. |
The 48-hour clock starts at the first failure and resets on any success. Rate
limiting (429) never counts against endpoint health, so an endpoint that only
ever rate-limits us is never disabled for it.
While an endpoint is deregistered its events are discarded, not held.
You are emailed when an endpoint is disabled
Deregistration is the one thing we notify you about, because it is the only state where events stop reaching you and nothing recovers on its own. The email goes to whoever created the endpoint and names it, the reason it failed, and when it last succeeded.
Nothing is sent for the states above it — an endpoint that is degraded or failing is still being retried, and most recover without anyone doing anything.
The email is sent to the address of the user who created the endpoint. If that person has left your organisation, nobody is notified — so check the Endpoint health column periodically rather than relying only on the email.
Re-enable a deregistered endpoint
Fix the endpoint, then select Re-enable on its row. This sends a test event and reactivates the endpoint only if that delivery succeeds — an endpoint that is still broken cannot be switched back on. Health reads Unknown until the first real delivery lands.
Delivery logs and metrics
Delivery logs record every attempt: timestamp, event type, resource id, status, result, attempt number, HTTP status, latency, payload size and failure reason. Filter by status or event type, search the failure reason, open a row for detail, or export the current view to CSV.

Health metrics shows delivered, succeeded and failed counts, retries, success rate, average latency, last success and last failure, plus a delivered-vs-failed trend.

Logs are retained for 30 days. We do not store the response body your endpoint
returns — only its status code and, where present, resultInfo.
Security
- HTTPS only.
http://URLs are rejected. - Your endpoint must be publicly reachable — see Which URLs are accepted.
- Credentials are never returned by the API. Where you supply one, it is shown only as a masked last-4 hint after saving.
- Response bodies from your endpoint are not persisted.
Which URLs are accepted
We deliver from inside our network, so a webhook URL that points at a private address would let a webhook reach services that aren't yours. Every URL is therefore checked when you save it, and again on each delivery.
| Rejected | Examples |
|---|---|
Anything other than https | http://, ftp:// |
| Private, loopback and link-local addresses | 127.0.0.1, 10.0.0.5, 172.16.0.1, 192.168.1.10, 169.254.169.254 |
| Carrier-NAT, multicast and reserved ranges | 100.64.0.1, 224.0.0.1 |
| The IPv6 equivalents | ::1, fe80::1, fd00::1, and IPv4-mapped forms like ::ffff:10.0.0.1 |
| Credentials in the URL | https://user:[email protected]/hook |
Two things worth knowing:
- Writing the address a different way doesn't get around the check. Decimal,
hexadecimal and octal spellings of the same address —
https://2130706433/,https://0x7f000001/,https://0177.0.0.1/— are all read as127.0.0.1and rejected. - Hostnames are judged on what they resolve to, not on how they look. A public name pointing at an internal address is refused when we try to deliver. If the name resolves to several addresses and any of them is internal, the delivery is refused rather than sent to one of the others.
Redirects are not followed. If your endpoint answers 301 or 302, that
response is the delivery outcome — point the endpoint at its final URL instead.
Saving a URL that fails these checks returns RELAY_WEBHOOK_URL_NOT_ALLOWED, so
you find out immediately rather than after events start failing.
Delivering to an endpoint inside a private network — over PrivateLink or VPC peering, say — is possible but not self-service. Reach out to our team; it needs an explicit allow-list entry for your host.
Authentication
| Type | What we send |
|---|---|
| Signature (RSA) | A signature field alongside the payload, plus your clientId and function in head. |
| None | No authentication header. |
| Bearer / Basic / API key | Your credential, as Authorization or X-Api-Key. |
The signature field is present in every payload but currently carries a
placeholder value — there is no public key published to verify it against, so do
not treat it as proof of origin. Until signature verification ships, authenticate
us by allow-listing our egress IPs or by putting an unguessable path segment in
your webhook URL.
Troubleshooting
Nothing is arriving. Check, in order: the endpoint is Enabled; it hasn't been Deregistered; the event you expect is actually ticked in its event list; and Delivery logs for that endpoint. An event that matched no endpoint leaves no trace, so an empty log usually means the subscription didn't match — not that delivery failed.
Deliveries show as failed with 2xx. Your response body contains a
resultInfo with resultStatus: "F". We classify on that, not on the status code.
Duplicates. Expected under at-least-once delivery — deduplicate on
head.reqMsgId.
Timeouts. Raise Request timeout (up to 30,000 ms), or acknowledge immediately and move the work off the request path. Timeouts count against endpoint health and will eventually deregister the endpoint.
The endpoint was disabled on its own. That's the 48-hour deregistration, and the email you received about it names the reason and the last successful delivery. Fix the cause, then Re-enable — it will only come back if a test event succeeds.
Two emails about the same endpoint. Each deregistration sends one email, so a second means the endpoint was re-enabled and then failed for another full window, not that the first was duplicated.
Saving fails with RELAY_WEBHOOK_URL_NOT_ALLOWED. The URL isn't publicly
reachable — most often a private or loopback address, or http:// instead of
https://. See Which URLs are accepted. If the host is
genuinely inside a private network reachable from us, contact our team.
Related
- Inbox Ticketing API — the pull counterpart to these events
- PRs: #4342, #4427 (destination validation)