All posts

Stop polling: how I design the trigger for every AI automation

· 6 min read · n8n, make, mcp, webhooks, automation

This week Vercel added events to its MCP server. An AI agent can now subscribe to things like deployment.succeeded or deployment.error and get a webhook when they happen. No more checking every few minutes.

Guillermo Rauch called it a missing piece of MCP: tools could read and write, but they couldn’t tell you later “this thing happened”.

If you’ve built automations in n8n or Make, this will sound familiar. It’s the same old choice: do you poll (check on a timer) or do you listen (get pushed an event)?

It’s also the first question I ask on every automation I build for a client. Not “which AI model”. Not “which tool”. Just this:

What starts it?

Here’s how I answer that, and the checks I add so the trigger doesn’t become the weakest part of the system.

Polling vs. push, in plain words

Polling means your workflow wakes up on a schedule and asks: “anything new?” Most of the time the answer is no.

Push means the other system calls you when something happens. Usually that’s a webhook: an HTTP POST to a URL you give it.

Polling is easier to set up. Push is almost always better once it’s running.

Why polling hurts:

  • You pay for empty checks. In Make, a scheduled trigger uses operations every time it runs, even when it finds nothing. In n8n, every run is an execution in your logs and on your server.
  • You react late. Check every 15 minutes and your “instant” invoice workflow is up to 15 minutes behind.
  • Failures hide. A loop that runs forever looks healthy even when the thing it’s waiting for broke an hour ago.

Why push is nicer:

  • The workflow runs only when there’s real work.
  • It reacts in seconds.
  • The event itself usually carries the data you need, so you make fewer API calls.

How I pick the trigger

When I scope a workflow, I go down this list in order:

  1. Does the source system send webhooks for this event? Stripe, Shopify, most CRMs, form tools, Slack, GitHub and a lot more do. If yes, use it.
  2. Is there an “instant” trigger in n8n or Make? In Make, look for triggers marked instant (they’re webhooks under the hood). In n8n, use the app’s trigger node if it’s webhook-based, or a plain Webhook node.
  3. Can the system send email? Plenty of old tools can’t call a webhook but can send a notification email. An inbox can be a trigger.
  4. Only then: poll. And poll smart. Pick the slowest schedule the business can live with, filter by “updated since last run”, and store the last ID or timestamp you processed.

For AI agents and MCP servers, it’s the same idea. If an agent needs to wait for something (a deploy, a payment, an approval), it shouldn’t sit in a loop asking. It should subscribe, and get woken up when it matters. That’s what the new MCP events work is about. It’s still early, but it’s the right direction.

The checks I add to every webhook

A webhook is a public URL that runs your workflow. So I treat it like a front door, not a back door. These are the boring checks I add every time.

1. Verify the signature

Most providers sign their webhooks. Usually it’s an HMAC of the request body with a shared secret, sent in a header. The Standard Webhooks spec (which Vercel uses for these MCP events) sends webhook-id, webhook-timestamp and webhook-signature headers.

In n8n I do this in a Code node right after the Webhook node: rebuild the signature from the raw body and the secret, compare it, and stop the workflow if it doesn’t match. Also reject anything with a timestamp that’s too old, so someone can’t replay an old request.

If a provider doesn’t sign webhooks, I at least put a long random token in the URL or a header, and I limit what that workflow is allowed to do.

2. Expect duplicates

Providers retry. Networks hiccup. You will get the same event twice. Sometimes three times.

So every workflow that does something real (creates a bill, sends an email, charges a card) checks first: “have I already handled this event ID?” I keep a tiny table with the event ID and when I processed it. A Supabase table works fine. So does a data store in Make.

If the ID is already there, the workflow ends quietly.

3. Answer fast, work later

Many providers give you only a few seconds to respond before they count it as failed and retry. Then you get duplicates (see above).

So the webhook workflow does the minimum: verify, save the event, respond 200. The heavy part (calling the AI model, reading a PDF, updating three systems) runs after that, in a separate workflow or a queue.

4. Have a backup sweep

Webhooks are great until one never arrives. The provider had an outage, your server restarted, a subscription expired.

So for anything important I add one slow polling job as a safety net. Once an hour or once a day, it asks the source system “what changed?” and compares that with what I processed. Anything missing gets handled and logged.

Yes, this is polling. That’s fine. Push for speed, a slow sweep for peace of mind.

5. Watch subscription expiry

Some webhook subscriptions expire and need to be renewed. Microsoft Graph subscriptions are a classic example. Vercel says it handles the renewals behind its MCP events for you, which is nice. When a platform doesn’t, I put the renewal in its own scheduled workflow and alert if it fails.

6. Log every event

Every incoming event gets one log row: when it arrived, the event ID, the type, and what happened (processed, duplicate, rejected, failed). When a client asks “did that invoice go through?”, I can answer in a minute instead of digging through execution history.

A real-world example

The AP invoice agent I built for a distribution company is a good example of why the trigger matters. When the agent isn’t confident (blurry scan, cropped page, confidence under 0.9), it sends the invoice to a human in Slack with the original PDF attached instead of guessing.

That human handoff only works if the trigger is reliable. A missed event isn’t a small bug. It’s an unpaid invoice.

Quick checklist

Before I call a trigger done:

  • Uses a webhook or instant trigger if one exists
  • Signature (or at least a secret token) is checked
  • Old timestamps are rejected
  • Duplicate event IDs are ignored
  • Responds fast, heavy work runs after
  • Backup sweep catches missed events
  • Subscription renewals are handled (if needed)
  • Every event is logged

Want this done for you?

Picking the trigger is the first thing I do in my n8n / Make AI automation package. And if you want your own AI agents to listen to your systems instead of polling them, that’s what my custom MCP server package is for.

Either way, start with one question: what starts it?