Home>Blog>Engineering
Engineering

API-First Architecture: Deploying Webhook Event Triggers on Enterprise Support Pipelines

ER
Elena Rostova
Published on April 15, 202610 min read
Share this article:

TL;DR / Quick Summary: Polling for document updates wastes bandwidth and leaves your assistant quoting last night's prices. An API-first, event-driven design flips the relationship: your CMS pushes a signed document.updated event the moment a page changes, and CustomerGPT re-chunks, re-embeds and upserts only that page — usually in under two seconds. This guide covers the event contract, delivery reliability, signature verification, and what to monitor once it is live.

Event-driven document sync: a CMS edit pushes a webhook to CustomerGPT, which re-embeds the page and refreshes the vector index in under two seconds

Support automation fails in a very specific, very embarrassing way: the docs are right and the bot is wrong. Someone updates the refund window from 14 days to 30, publishes it, and for the next several hours the assistant keeps confidently telling customers the old number — with a citation, which makes it worse, because the citation looks authoritative.

That gap between “published” and “retrievable” is an architecture choice, not a fact of life. Below is how to close it with webhook event triggers.

Why Polling Breaks Down at Documentation Scale

Scheduled crawling is the default because it is easy to reason about: every night, fetch everything, re-embed everything. It works fine at 50 pages. At 5,000 pages, three things go wrong at once.

  • Freshness is bounded by the interval, not by the edit. A nightly crawl means the worst-case staleness is 24 hours, and the average is 12.
  • Cost scales with the corpus, not with the change. Re-embedding 5,000 unchanged pages to catch the one that moved is the bulk of the bill.
  • Crawl windows collide with traffic. The re-index has to run somewhere, and a full pass long enough to matter is a full pass long enough to be noticed.
  • Deletions are invisible until the next pass. A retired page keeps getting cited until the crawler notices it 404s.
Figure 1 — Sync models

Scheduled polling

  • Staleness bounded by the crawl interval (hours to a day)
  • Re-embeds the whole corpus to catch a single diff
  • Deleted pages stay citable until the next pass
  • Cost grows with corpus size, every single night

Webhook event triggers

  • Staleness bounded by embedding latency (seconds)
  • Re-embeds exactly the page that changed
  • document.deleted removes chunks immediately
  • Cost grows with edit volume, which is far smaller
The same corpus, the same edit. Only the trigger differs.

The Event Contract: What a Sync Webhook Should Carry

Before writing any code, agree on the payload. A sync event needs to answer four questions: what happened, to which document, when, and is this the message you think it is.

FieldPurposeRequired
eventdocument.updated, document.deleted, collection.reindexedYes
eventIdStable id used as the idempotency key on retriesYes
chatbotIdWhich assistant's index to updateYes
url or sourceIdThe document that changedYes
occurredAtPublish timestamp; lets the consumer drop out-of-order eventsRecommended
contentHashSkips re-embedding when the body did not actually changeRecommended

Sending Your First Sync Event

On the Scale and Enterprise plans the push route is a single POST. Fire it from whatever already knows a page was published — a CMS post-publish hook, a CI job on your docs repo, or a database trigger.

// Triggering an automatic chatbot sync from an external system
await fetch('https://api.customergpt.ai/v1/webhooks/sync', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + process.env.CUSTOMERGPT_TOKEN,
    'Content-Type': 'application/json',
    'Idempotency-Key': event.id
  },
  body: JSON.stringify({
    chatbotId: 'bot_xyz',
    event: 'document.updated',
    eventId: event.id,
    url: 'https://mysite.com/docs/api-guide',
    occurredAt: new Date().toISOString(),
    contentHash: sha256(renderedHtml)
  })
});
Figure 2 — What happens after the POST
  1. 1Event acceptedThe endpoint validates the signature and returns 202 immediately — work happens off the request path.
  2. 2Fetch and diffThe page is re-fetched and compared against the stored content hash. Identical body, no work.
  3. 3Re-chunkContent is split along its heading hierarchy so a section stays in one retrievable piece.
  4. 4Upsert vectorsNew embeddings replace the old chunks in a single transaction — no window where the page is missing.
Only the changed document moves through the pipeline. The other 4,999 pages are never touched.

Making Delivery Reliable: Retries, Idempotency and Ordering

Webhooks are an at-least-once medium. Networks drop, receivers restart, and a well-behaved producer retries. Design for duplicates rather than hoping they do not arrive.

  1. Send a stable event id. Reuse the same id across every retry of the same logical event so the consumer can discard repeats.
  2. Retry with exponential backoff and jitter. A flat one-second retry loop from 40 publishing services is a self-inflicted thundering herd.
  3. Treat any 2xx as delivered. Do not parse the body for success; the status code is the contract.
  4. Drop stale events with occurredAt. If a retry from 14:02 arrives after the fresh event from 14:09, the older one must lose.
  5. Dead-letter after N attempts. Persist what you could not deliver, alert on the queue depth, and replay it after the fix.
// Producer-side retry with backoff and a dead-letter fallback
async function deliver(payload, attempt = 0) {
  const res = await post(payload);
  if (res.ok) return;

  if (attempt >= 5) return deadLetter.push(payload);

  const backoff = Math.min(2 ** attempt * 1000, 30_000);
  const jitter = Math.random() * 400;
  setTimeout(() => deliver(payload, attempt + 1), backoff + jitter);
}

Securing the Endpoint

A sync endpoint that accepts anonymous POSTs is a content-poisoning vector: anyone who guesses a chatbot id can point your assistant at a page you do not control. Two controls close that off.

  • Bearer token in the Authorization header — scoped to a single chatbot, rotatable, never committed to the docs repo that triggers it.
  • Signature over the raw body — an HMAC-SHA256 of the exact bytes plus a timestamp, so a replayed or edited payload fails verification.
// Consumer-side verification — compare in constant time, and bound the clock skew
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, header, secret) {
  const [ts, signature] = header.split(',');
  if (Math.abs(Date.now() - Number(ts)) > 5 * 60_000) return false;

  const expected = createHmac('sha256', secret)
    .update(ts + '.' + rawBody)
    .digest('hex');

  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Note that the signature is computed over the raw body. Verifying a re-serialized object is a classic way to ship a check that passes in tests and fails on the one payload where key order differs.

What to Monitor After You Ship

Event-driven sync fails quietly — the pipeline does not crash, it just stops receiving events, and nobody notices until a customer quotes an old price back at you. Four signals catch that.

Figure 3 — The dashboard that matters
< 5 sPublish-to-retrievable p95edit timestamp to index commit
0Dead-letter queue depthanything above zero is a page silently out of date
> 99%Delivery success on first attempta falling rate means an unhealthy receiver
1:1Publishes to sync eventsa widening gap means a hook stopped firing
Alert on the first two. The second two are for capacity planning.

Rollout Plan for an Existing Docs Site

You do not have to cut over in one step. This sequence keeps the assistant answerable the entire time.

Figure 4 — Migration checklist

From nightly crawl to event-driven sync

  • Do a full crawl once so the index has a complete baseline
  • Add the publish hook in your CMS behind a feature flag
  • Fire events for one low-traffic section first and watch the logs
  • Compare event count against publish count for a full week
  • Drop the nightly crawl to weekly reconciliation
  • Alert on dead-letter depth and on publish-to-retrievable p95
  • Document how to replay the dead-letter queue before you need to
Run both mechanisms in parallel for a week; the crawl becomes the reconciliation net rather than the primary path.

The result is a support assistant whose answers move at the same speed as your documentation. Your writers publish; the index follows within seconds; nobody has to remember to press a re-sync button.

References & Sources

  1. Webhooks Standard Guide: Event-Driven APIs
  2. Mozilla MDN Web Docs: HTTP POST Protocol Details
  3. IETF RFC 9421: HTTP Message Signatures
  4. Stripe Engineering: Designing Robust Webhook Delivery

Frequently Asked Questions

How fast does a webhook-triggered re-index actually land?

For a single page the round trip is dominated by embedding latency, not by your network hop: parse, chunk, embed and upsert typically finish in one to three seconds. The practical guarantee to design for is that the answer is fresh before the next visitor asks, not that the write is instantaneous.

Do I still need a scheduled crawl if I send webhooks?

Yes, but a much cheaper one. Keep a low-frequency reconciliation crawl (nightly or weekly) as a safety net for events that were dropped, for pages changed outside your CMS, and for sources with no event API at all. Webhooks handle freshness; the crawl handles drift.

What happens if my CMS fires the same event twice?

Nothing, if you send a stable event id. The ingest pipeline treats the id as an idempotency key, so a duplicate delivery is acknowledged and discarded instead of re-embedding the page and doubling your token spend.

How do I sync a page that was deleted rather than edited?

Send a document.deleted event with the same URL. The pipeline removes the associated chunks from the vector index so the assistant stops citing a page that no longer exists — the failure mode users notice fastest.

Which plans include webhook triggers?

Webhook sync endpoints are available on the Scale and Enterprise plans. Lower tiers can achieve similar freshness with scheduled re-crawls, at a coarser interval.

Ready to deploy secure, custom AI agents?

Train your ChatGPT experts in seconds on manual links, files, and PDFs. Get started for free.

Build Your Chatbot Free