# Why Your AI Agent Should Not Poll PostEverywhere (Use Webhooks) > An agent that polls for publish status burns tokens, burns rate limit and still reacts late. Connect PostEverywhere webhooks instead and the agent is woken by the event rather than asking for it. The pattern, and when polling is still right. **Source:** https://posteverywhere.ai/blog/ai-agents-webhooks-not-polling **Author:** Jamie Partridge **Published:** 2026-09-12 --- AI agent webhooks are the part most agent tutorials skip. They end at the schedule call. The agent drafts something, calls the tool, gets a `post_id` back, and the example stops there. In production that is the halfway point, because the agent still has to learn whether the thing actually published. The instinctive fix is a loop: call `GET /v1/posts/{id}` every thirty seconds until the status changes. It works, and it is the wrong shape for an agent specifically. Polling costs an LLM far more than it costs a script. Every check is a tool call, every tool result re-enters the context window, and the agent pays tokens to be told "still pending" over and over. Then it reacts late anyway, because the news arrives at the next poll rather than the moment it happens. Connect PostEverywhere webhooks instead and the relationship inverts: the event wakes the agent. *Written by Jamie Partridge, Founder.* ## Table of Contents 1. [What polling actually costs an agent](#what-polling-actually-costs-an-agent) 2. [How PostEverywhere webhooks change the agent's shape](#how-posteverywhere-webhooks-change-the-agents-shape) 3. [The PostEverywhere events an agent should subscribe to](#the-posteverywhere-events-an-agent-should-subscribe-to) 4. [Wiring PostEverywhere webhooks into an agent runtime](#wiring-posteverywhere-webhooks-into-an-agent-runtime) 5. [When polling PostEverywhere is still the right call](#when-polling-posteverywhere-is-still-the-right-call) 6. [Combining PostEverywhere webhooks with the MCP connectors](#combining-posteverywhere-webhooks-with-the-mcp-connectors) 7. [FAQs](#faqs) ## What polling actually costs an agent A script polling the [social media API](/social-media-api) costs one HTTP request. An agent polling the same endpoint costs considerably more: **Tokens.** Each poll is a tool call plus a tool result in the context window. Thirty polls waiting on a video upload is sixty additional messages the model reads on every subsequent turn. **Rate limit.** The [API allows 60 requests per minute per key](/blog/social-media-api-rate-limits), and every platform underneath has its own, from X to Meta's Graph API. One agent polling every few seconds across a dozen scheduled posts consumes a meaningful share of that for no information. **Latency.** Poll every 30 seconds and you learn about a failure an average of 15 seconds after it happened, and up to 30. That is fine for a dashboard and poor for an agent meant to react. **Context rot.** This is the underrated one. Filling the window with "status: pending" degrades the agent's attention on everything else in the conversation. The polling loop does not just cost money, it makes the agent worse at the task it was doing. > **Running an agent against PostEverywhere?** Webhooks, the REST API and the [hosted MCP server](/mcp) all run on one key, included on [every plan from $9/mo](/pricing). [Start a 7-day free trial](https://app.posteverywhere.ai/signup): card required, $0 charged today. ## How PostEverywhere webhooks change the agent's shape With polling, the agent is a loop that owns the waiting. With webhooks, the agent becomes a handler that is invoked when there is something to do. ``` Polling agent → schedule → poll → poll → poll → poll → react Webhooks agent → schedule → (sleep) event → wake agent with the outcome → react ``` The practical difference is that the agent's turn **ends** after scheduling. It is not holding a loop open, not burning context, not billing you to wait. When `post.failed` arrives hours later, your infrastructure starts a fresh turn with the failure as the input. That also makes the agent's job easier to reason about. "Here is a failed destination, decide what to do" is a far better prompt than "here is a status object you have now seen eleven times". ## The PostEverywhere events an agent should subscribe to Not all twelve emitted events are useful to an agent. Four carry most of the value: | Event | Why the agent cares | |---|---| | `post.published` | Confirm success, store `platform_post_id`, move to the next step | | `post.failed` | Decide whether to retry, rewrite, or escalate to a human | | `post.partially_failed` | Reconcile at destination level rather than retrying the whole post | | `account.reconnect_needed` | Stop queueing into a dead connection before more posts fail | `account.reconnect_needed` is the highest-value subscription for an autonomous agent, because it is the only one that arrives **before** the damage. An agent that receives it can pause that account's queue and ask a human to reconnect, rather than cheerfully scheduling a week of posts into a connection that cannot publish. The approval events (`post.approval_requested`, `post.approved`, `post.changes_requested`) matter if a human reviews agent output before it ships, which for brand accounts is usually the right arrangement. [Giving an agent access safely](/blog/ai-agent-access-to-social-media) covers where to put that boundary. ## Wiring PostEverywhere webhooks into an agent runtime The receiver is an ordinary HTTP endpoint. What differs is what it does after verifying. ```ts export async function POST(req: Request) { // 1. Raw body first, or the HMAC will not match. const rawBody = await req.text(); if (!verifyWebhook(rawBody, req.headers.get('x-posteverywhere-signature') || '', SECRET)) { return new Response('Invalid signature', { status: 401 }); } // 2. Dedupe: delivery is at-least-once. const eventId = req.headers.get('x-posteverywhere-event-id'); if (await seen(eventId)) return new Response('OK', { status: 200 }); // 3. Return fast. You have 10 seconds. await queue.add('agent-turn', JSON.parse(rawBody)); return new Response('OK', { status: 200 }); } ``` The webhook handler must not invoke the agent inline. A model call routinely takes longer than the **10-second** delivery timeout, so an inline agent turn guarantees a timeout, which triggers our retry ladder, which delivers the same event again, which starts a second agent turn. You will have built an accidental fork bomb powered by your own inference budget. Enqueue, return `200`, and let a worker start the agent turn with the event as input. Verification is non-negotiable before any of it: the full walkthrough is in [verifying PostEverywhere webhook signatures](/blog/verify-posteverywhere-webhook-signatures). ## When polling PostEverywhere is still the right call Webhooks are not universally better, and three cases genuinely favour polling. **The three reserved events.** `post.publishing`, `post.updated` and `account.connected` are declared but not currently emitted. If you need those transitions, poll `GET /v1/posts/:id` or `GET /v1/accounts` after the action. Building a handler for an event that never fires is a silent failure. **Interactive conversations.** If someone is sitting in a chat asking "did it go out?", one status check is the correct answer. Webhooks serve unattended work; a person waiting for an answer should get a direct one. **No public endpoint.** A local agent on someone's laptop has nowhere for us to deliver. HTTPS is required in production and localhost and private IPs are refused as SSRF protection, so a local-only agent polls, or tunnels through a public HTTPS hostname. The honest rule: **unattended and long-running favours webhooks; interactive and short favours a direct call.** Most real agents do both. ## Combining PostEverywhere webhooks with the MCP connectors If your agent runs inside an assistant rather than your own code, the two halves complement each other. The connector speaks the Model Context Protocol, and workflow runners like n8n and Make can receive the same webhook events without an agent at all. The [MCP connector](/blog/connect-claude-to-social-media) gives the assistant tools to schedule and publish on request. Webhooks give your infrastructure the outcomes without the assistant having to ask. A common production setup: the assistant drafts and schedules through the connector, while a small service receives `post.failed` and `account.reconnect_needed` and raises anything that needs attention. Connect PostEverywhere to [ChatGPT](/blog/connect-chatgpt-to-social-media), [Claude](/blog/connect-claude-to-social-media) or [Grok](/blog/connect-grok-to-social-media) for the conversational half; use webhooks for the part nobody should have to watch. The [agents page](/agents) covers the wider set of patterns, and the full [webhooks reference](/docs/webhooks) carries every payload shape. > **Prefer to see the tools before wiring any of it?** The [MCP server page](/mcp) lists all 38 tools by group and the [developer docs](/developers) cover the REST equivalents. For recovery specifics, [when social media posts fail](/blog/when-social-posts-fail-webhooks) covers the retry and reconnect loop end to end. ## FAQs ### Should an AI agent poll for social media publish status? Generally no. Polling costs tokens on every check, consumes rate limit, reacts late, and fills the context window with repeated status objects that degrade the agent's performance on its actual task. Webhooks let the event wake the agent instead. ### Which PostEverywhere webhook events matter most to an agent? `post.published`, `post.failed`, `post.partially_failed` and `account.reconnect_needed`. The last is the most valuable for autonomous agents because it arrives before the next post fails, so the agent can pause the queue rather than discover the problem afterwards. ### Can I call my agent directly from the webhook handler? No. Deliveries time out after 10 seconds and a model call frequently exceeds that, which triggers our retry ladder and delivers the event again, starting another agent turn. Verify, dedupe, enqueue, return `200`, and run the agent in a worker. ### Does using webhooks mean I never need to poll PostEverywhere? Not quite. Three declared events are not currently emitted (`post.publishing`, `post.updated`, `account.connected`), so poll for those transitions. Interactive questions from a human are also better answered with one direct status call. ### How does an agent running locally receive webhooks? It cannot directly. Production deliveries require public HTTPS, and localhost and private IPs are refused for SSRF protection. Either run the receiver on a public host and pass events to the agent, or expose a tunnel with a public HTTPS hostname during development. ### Do webhooks work alongside the MCP connectors? Yes, and they complement each other. The MCP connector gives an assistant tools to schedule on request; webhooks give your infrastructure the outcomes without the assistant asking. Many setups use the connector for drafting and webhooks for unattended failure handling. ### Do PostEverywhere webhooks cost extra? No. Webhooks, the REST API, the Node SDK, the CLI and the hosted MCP server are included on every plan from $9/mo. The 7-day free trial covers everything, though a card is required to start and there is no free plan. --- An agent that polls is an agent you are paying to wait. Subscribe to four events, return `200` fast, and run the turn in a worker: the agent stops asking, and starts being told. [Start your 7-day free trial](https://app.posteverywhere.ai/signup) and point a webhook at your agent's queue. The [PostEverywhere webhooks guide](/blog/posteverywhere-webhooks) covers every event and payload, and [building an AI social media agent](/blog/build-an-ai-social-media-agent-with-posteverywhere) walks a full pipeline.