Webhooks versus polling for support data
Both approaches lose data, in different ways, and the reliable designs use both. Choosing
one and trusting it is the mistake this skill exists to prevent.
- Webhooks are fast and lossy. Delivery is best-effort, retries eventually stop, and an
outage on your side during the retry window means those events are gone with no record
that they existed.
- Polling is slower and complete-ish. It will find anything that changed, but only in
the fields the list endpoint filters on, and it misses deletions entirely.
Use webhooks for latency and polling for truth. Webhooks drive the real-time path;
a scheduled reconciliation sweep catches whatever the webhooks lost. Almost every "our sync
is missing tickets" investigation ends at a missing reconciliation sweep.
Webhook properties you must design for
Assume all of these, because they are true of most helpdesk platforms and you will not be
told which:
- At-least-once delivery. The same event arrives twice. Every handler must be idempotent
— key on the event id where one exists, otherwise on the resource id plus a version or
timestamp, and make the write an upsert.
- Out-of-order delivery. An "updated" event can arrive before the "created" one, and a
status change can arrive after the change that superseded it. Never apply a webhook as a
delta. Treat it as a signal that a resource changed, then fetch the current state — that
single rule removes most ordering bugs.
- Truncated payloads. Webhook bodies frequently omit message bodies, custom fields, or
the full object. Do not build the record from the payload alone; fetch.
- Retries that give up. After a bounded number of attempts the platform stops. If your
endpoint was down for longer, those events are unrecoverable from the platform.
- No delivery for some changes. Bulk operations, admin edits, merges, deletions and
automation-driven changes often fire nothing.
- Signature verification, which is a security requirement rather than an optional step,
and it has to happen before the payload is parsed or trusted.
- A response deadline. Slow handlers get treated as failures and retried. Acknowledge
immediately, queue the work, and do the fetch asynchronously — a handler that does the
fetch inline will start timing out under load, which is exactly when you need it.
Polling properties you must design for
- Watermark on the field the API filters on, and know whether that field is
modification time or creation time. A
created_since sweep will never return the ticket
that was updated today and created last year — a very common silent gap.
- Overlap the window. Re-request a few minutes before your last watermark to absorb
clock skew and in-flight writes. Idempotent upserts make the overlap free.
- Advance the watermark from the data, not the clock. Use the maximum timestamp actually
returned. Advancing to "now" skips anything written during the request.
- Beware equal timestamps at a page boundary. Records sharing a timestamp can straddle
pages and be skipped or repeated. Page on a stable composite of timestamp plus id where
the API allows it.
- Cursor invalidation. Long paginated walks can have their cursor expire mid-run;
checkpoint so a restart resumes rather than starting over.
- Rate limits shared with production. A poll competing with the app's own traffic will
throttle both. Read the limit headers and back off on the platform's own hint, which is
frequently not the standard
Retry-After.
The reconciliation sweep, which is the part that makes it reliable
Neither mechanism catches deletions, and webhooks lose events silently. So:
- Periodically re-list ids over a window and diff against what you hold. Additions are
missed events; absences are deletions or merges.
- Compare counts against the source's own totals where an endpoint reports them. A count
mismatch is the cheapest possible detector of a broken sync.
- Run it on a window wide enough to cover your longest plausible outage, and a slower
full sweep periodically for anything outside that.
- Alert on the gap, not on the sweep completing. A sweep that finds 400 missing records
every night is working and telling you the webhook path is broken.
Ordering, and why event-time is not arrival-time
Store both. Arrival time tells you about your pipeline; event time tells you what happened.
Any analysis ordered by arrival time will be wrong after a backfill, and wrong in the most
damaging way — it can reverse cause and effect in a case timeline.
Where you must apply changes in order — status histories, assignment histories — use the
source's own sequence or version field if it has one, and if it does not, fetch current
state rather than reconstructing from the event stream.
Failure handling
- A dead-letter queue for events you cannot process, with the payload retained. Without
it, a parsing bug silently discards data for as long as it takes to notice.
- Replay from the dead-letter queue once the bug is fixed, which is why the payload has
to be kept.
- Backpressure: a queue between the webhook endpoint and the worker, so a slow
downstream does not turn into failed deliveries and exhausted retries.
- Monitor the absence of events. An integration that silently stops looks identical to
a quiet period. Alert on "no events for longer than expected for this hour of this
weekday", using a baseline that respects support traffic's strong weekly and intraday
seasonality — a flat threshold fires every weekend.
- Track sync lag as a metric, and put it where the people who trust the data can see it.
Guardrails
- Verify webhook signatures before parsing. An unauthenticated webhook endpoint accepts
forged support data from anyone who finds the URL.
- Do not put customer data in a URL or a query string anywhere in the pipeline.
- Webhook payloads are production PII and frequently end up in application logs by
default. Check what your logging captures.
- Do not use a webhook to trigger a customer-visible action without a human in the loop
or an idempotency guarantee — at-least-once delivery means a duplicate event sends a
duplicate message.
- Do not disable the reconciliation sweep because it keeps finding nothing. That is what
success looks like right up until the day it is not.
Present results to the user
- The chosen shape — webhooks for latency, polling for truth, reconciliation for
completeness — and which of the three is currently missing.
- Idempotency, and the key each handler dedupes on.
- The fetch-on-signal rule, and anywhere the payload is currently trusted as a delta.
- The watermark field, whether it is modification or creation time, and the overlap.
- The reconciliation design — window, cadence, what it diffs, and the alert on the gap.
- Deletion handling, which neither mechanism provides.
- Failure paths — dead-letter queue, replay, backpressure — and the absence-of-events
alert with its seasonal baseline.
- What can still be lost, stated plainly, and the maximum outage the design survives.
1---2name: cx-streaming-ingest3description: Use to choose between webhooks and polling for keeping support data in sync, and to close the gaps each one leaves. Trigger for "should we use webhooks or polling", "our sync is missing tickets", "webhook events are arriving out of order", real-time support data ingestion, missed events, or designing a helpdesk integration that must not lose data.4---56# Webhooks versus polling for support data78Both approaches lose data, in different ways, and the reliable designs use both. Choosing9one and trusting it is the mistake this skill exists to prevent.1011- **Webhooks** are fast and lossy. Delivery is best-effort, retries eventually stop, and an12 outage on your side during the retry window means those events are gone with no record13 that they existed.14- **Polling** is slower and complete-ish. It will find anything that changed, but only in15 the fields the list endpoint filters on, and it misses deletions entirely.1617**Use webhooks for latency and polling for truth.** Webhooks drive the real-time path;18a scheduled reconciliation sweep catches whatever the webhooks lost. Almost every "our sync19is missing tickets" investigation ends at a missing reconciliation sweep.2021## Webhook properties you must design for2223Assume all of these, because they are true of most helpdesk platforms and you will not be24told which:2526- **At-least-once delivery.** The same event arrives twice. Every handler must be idempotent27 — key on the event id where one exists, otherwise on the resource id plus a version or28 timestamp, and make the write an upsert.29- **Out-of-order delivery.** An "updated" event can arrive before the "created" one, and a30 status change can arrive after the change that superseded it. **Never apply a webhook as a31 delta.** Treat it as a signal that a resource changed, then fetch the current state — that32 single rule removes most ordering bugs.33- **Truncated payloads.** Webhook bodies frequently omit message bodies, custom fields, or34 the full object. Do not build the record from the payload alone; fetch.35- **Retries that give up.** After a bounded number of attempts the platform stops. If your36 endpoint was down for longer, those events are unrecoverable from the platform.37- **No delivery for some changes.** Bulk operations, admin edits, merges, deletions and38 automation-driven changes often fire nothing.39- **Signature verification**, which is a security requirement rather than an optional step,40 and it has to happen before the payload is parsed or trusted.41- **A response deadline.** Slow handlers get treated as failures and retried. **Acknowledge42 immediately, queue the work**, and do the fetch asynchronously — a handler that does the43 fetch inline will start timing out under load, which is exactly when you need it.4445## Polling properties you must design for4647- **Watermark on the field the API filters on**, and know whether that field is48 modification time or creation time. A `created_since` sweep will never return the ticket49 that was updated today and created last year — a very common silent gap.50- **Overlap the window.** Re-request a few minutes before your last watermark to absorb51 clock skew and in-flight writes. Idempotent upserts make the overlap free.52- **Advance the watermark from the data, not the clock.** Use the maximum timestamp actually53 returned. Advancing to "now" skips anything written during the request.54- **Beware equal timestamps at a page boundary.** Records sharing a timestamp can straddle55 pages and be skipped or repeated. Page on a stable composite of timestamp plus id where56 the API allows it.57- **Cursor invalidation.** Long paginated walks can have their cursor expire mid-run;58 checkpoint so a restart resumes rather than starting over.59- **Rate limits shared with production.** A poll competing with the app's own traffic will60 throttle both. Read the limit headers and back off on the platform's own hint, which is61 frequently not the standard `Retry-After`.6263## The reconciliation sweep, which is the part that makes it reliable6465Neither mechanism catches deletions, and webhooks lose events silently. So:6667- **Periodically re-list ids over a window and diff** against what you hold. Additions are68 missed events; absences are deletions or merges.69- **Compare counts against the source's own totals** where an endpoint reports them. A count70 mismatch is the cheapest possible detector of a broken sync.71- **Run it on a window wide enough to cover your longest plausible outage**, and a slower72 full sweep periodically for anything outside that.73- **Alert on the gap, not on the sweep completing.** A sweep that finds 400 missing records74 every night is working and telling you the webhook path is broken.7576## Ordering, and why event-time is not arrival-time7778Store both. Arrival time tells you about your pipeline; event time tells you what happened.79Any analysis ordered by arrival time will be wrong after a backfill, and wrong in the most80damaging way — it can reverse cause and effect in a case timeline.8182Where you must apply changes in order — status histories, assignment histories — use the83source's own sequence or version field if it has one, and if it does not, fetch current84state rather than reconstructing from the event stream.8586## Failure handling8788- **A dead-letter queue** for events you cannot process, with the payload retained. Without89 it, a parsing bug silently discards data for as long as it takes to notice.90- **Replay from the dead-letter queue** once the bug is fixed, which is why the payload has91 to be kept.92- **Backpressure**: a queue between the webhook endpoint and the worker, so a slow93 downstream does not turn into failed deliveries and exhausted retries.94- **Monitor the absence of events.** An integration that silently stops looks identical to95 a quiet period. Alert on "no events for longer than expected for this hour of this96 weekday", using a baseline that respects support traffic's strong weekly and intraday97 seasonality — a flat threshold fires every weekend.98- **Track sync lag as a metric**, and put it where the people who trust the data can see it.99100## Guardrails101102- **Verify webhook signatures before parsing.** An unauthenticated webhook endpoint accepts103 forged support data from anyone who finds the URL.104- **Do not put customer data in a URL or a query string** anywhere in the pipeline.105- **Webhook payloads are production PII** and frequently end up in application logs by106 default. Check what your logging captures.107- **Do not use a webhook to trigger a customer-visible action** without a human in the loop108 or an idempotency guarantee — at-least-once delivery means a duplicate event sends a109 duplicate message.110- **Do not disable the reconciliation sweep because it keeps finding nothing.** That is what111 success looks like right up until the day it is not.112113## Present results to the user1141151. **The chosen shape** — webhooks for latency, polling for truth, reconciliation for116 completeness — and which of the three is currently missing.1172. **Idempotency**, and the key each handler dedupes on.1183. **The fetch-on-signal rule**, and anywhere the payload is currently trusted as a delta.1194. **The watermark field**, whether it is modification or creation time, and the overlap.1205. **The reconciliation design** — window, cadence, what it diffs, and the alert on the gap.1216. **Deletion handling**, which neither mechanism provides.1227. **Failure paths** — dead-letter queue, replay, backpressure — and the absence-of-events123 alert with its seasonal baseline.1248. **What can still be lost**, stated plainly, and the maximum outage the design survives.