Agent Identity
← GUIDES · EVENTS

Webhooks vs polling vs durable events: which should an AI agent use?

By Naol Ketema, founder · · Markdown

SHORT ANSWER

Use long-poll waits on a durable event log when your agent is a long-running process, webhooks when it runs on a server or serverless function that should be called, and polling only for occasional batch checks. The durable log is what makes the first two reliable: waits can resume from a cursor, and missed webhook deliveries can be replayed. Agent Identity offers both on the same log.

The three options in one sentence each

  • Polling: the agent calls a list endpoint on a timer and checks for anything new.
  • Webhooks: the platform sends an HTTP POST to a URL you registered whenever a matching event happens.
  • Durable events with long-poll waits: the agent makes one request that the server holds open until a matching event is appended to an ordered, append-only log, then re-arms.

All three answer the same question: how does the agent learn that a reply arrived, a message bounced, or another agent finished a task?

How they compare

  • Latency. Polling: half the poll interval on average. Webhooks: near immediate. Long-poll wait: near immediate.
  • Requests. Polling: one per interval, mostly empty. Webhooks: one per event, made by the platform. Long-poll wait: about one per event, plus one per timeout window.
  • Needs a public URL. Polling: no. Webhooks: yes, reachable from the internet. Long-poll wait: no.
  • Needs a running process. Polling: yes. Webhooks: no, a function can be invoked per delivery. Long-poll wait: yes.
  • Missed events. Polling: you diff lists yourself. Webhooks: the platform retries, then you replay. Long-poll wait: resume from a since cursor.
  • Security work. Polling: just your API key. Webhooks: you must verify signatures and dedupe. Long-poll wait: just your API key.

When polling is fine

Polling is the simplest thing that works when checks are rare. A nightly job that reads yesterday's replies, or a script you run by hand, does not need anything more. It becomes a problem when the interval gets short, the number of agents grows, or you start writing code to remember which items you already handled.

When webhooks fit best

Webhooks fit agents that live behind an HTTP server or run as serverless functions. Nothing sits idle: the platform calls you when there is work. The cost is operational:

  • You need a public HTTPS endpoint.
  • You must verify each delivery's signature, because anyone can POST to a URL.
  • Deliveries are retried, so the same event can arrive more than once. Handlers must be idempotent.
  • Slow handlers fail. Acknowledge with a 2xx quickly and do the agent's work asynchronously.

When durable events with long-poll waits fit best

Long-poll waits fit an agent that is a process: a worker, a script, a notebook, a loop on a laptop with no public URL. The code reads top to bottom: send, wait, act. There is no endpoint to expose, no signature to check, and no second process to hand events to.

The word durable matters. If the log only held events for whoever was listening at the moment, a restart would lose replies. With a durable, ordered log the agent passes the timestamp of the last event it handled and gets the next one, even if it arrived while the agent was down.

A quick way to decide

  • Is the agent a long-running process with no public URL, such as a worker or a script on a laptop? Use long-poll waits.
  • Does it run behind a web server or as a serverless function? Use webhooks, and verify every delivery.
  • Do you only check once an hour or once a day? Polling a list endpoint is fine.
  • Do several consumers need the same events? Register a webhook per consumer, or give each its own wait loop. Both read the same log.

Whatever you pick, make handlers idempotent. Retries, replays and restarts all mean the same event can be handled twice, and an agent that sends email or moves money must not act twice.

How Agent Identity does both on one log

Every state change in Agent Identity appends an event to an append-only log per organization: mail.received, mail.bounced, a2a.task.created, a2a.sent_task.updated, and so on. Waits read from it and webhooks are its push side, so you can mix them: a webhook for the support inbox, a wait inside a script that hands a task to another agent.

import { AgentClient } from "@agentidentity/sdk";

const client = new AgentClient({ baseUrl: "https://api.agent-identity.dev", apiKey: process.env.AID_KEY! });

// Pull: block until the next reply, up to 55 seconds, then re-arm.
const { event, timedOut } = await client.events.wait({
  type: "mail.received",
  identityId: agentId,
  since,
  timeoutMs: 55_000,
});

// Push: have the same events POSTed to you instead.
const hook = await client.webhooks.create({
  url: "https://example.com/aid-events",
  identityId: agentId,
  eventTypes: ["mail.received", "mail.bounced"],
});
hook.secret; // returned once; use it to verify signatures

Webhook deliveries count as successful on any 2xx and time out after 10 seconds. Failed ones are retried, then moved to dead_letter. GET /v1/webhooks/deliveries shows attempts and errors, and POST /v1/events/{id}/replay re-sends a missed event once your endpoint is healthy. Deduplicate on x-aid-event-id, since a replay looks the same as a retry.

Trade-off to know: a wait matches exactly one event type and returns at most one event per request. If one process needs many types at once, a webhook or several concurrent waits is cleaner.

FAQ

Are long-poll waits the same as WebSockets or server-sent events?

No. A long-poll wait is an ordinary HTTP request held open until an event arrives or a timeout passes, then the client re-arms. It needs no special client and passes through most proxies, at the cost of one request per event.

Can I use webhooks and waits at the same time?

Yes. Both read the same event log, so a webhook endpoint and a waiting agent see the same events. Use whichever suits each consumer.

What happens to webhook deliveries while my server is down?

They are retried and, after the maximum attempts, marked dead_letter. Nothing re-drives them automatically; replay each missed event with POST /v1/events/{id}/replay.

Which should I start with?

If your agent is a script or worker, start with client.events.subscribe(). Add a webhook when you move to a serverless or HTTP-first deployment.

Related guides

Give your agent its own identity in a couple of minutes. Get started free → · Docs · All guides