A2A in production - tasks, push, and security beyond the demo
The A2A features a hello-world skips but a real multi-agent system can't: push notifications, resubscription, security schemes on the agent card, and typed extensions.
By Patrick WaweruJul 15, 202611 min read

The A2A introduction gets you a working agent: an AgentCard, a streaming SendMessage, tasks and artifacts. It demos beautifully. Then you put it in front of real traffic and discover the gap between "works on my machine over a 30-second stream" and "runs a 20-minute job across a flaky network for a client who expects an audit trail."
As the protocol has matured, the parts that close that gap have become the interesting ones. None of them show up in a hello-world; all of them decide whether your multi-agent system is something you can operate. Here are the four we reach for on every production A2A deployment.
1. Push notifications — stop holding the stream open
Streaming is great for a chat that resolves in seconds. It's the wrong tool for a job that takes twenty minutes. Holding an HTTP/2 stream (or worse, an SSE connection through a load balancer) open for the whole duration is fragile: idle timeouts, scale-downs and client sleeps all kill it. A2A's answer is push notifications — the caller registers a webhook, hangs up, and the agent calls back when the task changes state.
{ "message": { "role": "USER", "parts": [{ "text": "Reconcile Q3 statements" }] }, "configuration": { "pushNotificationConfig": { "url": "https://caller.example.com/a2a/webhooks", "token": "opaque-correlation-id-for-this-task", "authentication": { "schemes": ["Bearer"] } } } } The agent persists that config against the task and POSTs the task's terminal (and optionally intermediate) states to the webhook. Two rules keep it safe in production: the webhook authenticates the caller back (the notification carries a signed token so a random POST can't spoof "your task is done"), and delivery is treated as at-least-once — so the handler is idempotent on the task id. Long jobs stop being a connection-management problem and become a queue.
2. Resubscription — streams drop, work shouldn't
Even for jobs you do want to watch live, the transport will drop: a deploy rolls the caller, a mobile client backgrounds, a proxy resets. In the intro this looks catastrophic — you lose the stream, so you lose the work. In production the task is server-side state, and the stream is just a view onto it. TasksResubscribe lets a caller reattach to an in-flight task by id and resume receiving events where it left off.
This is also exactly the mechanism that powers human-in-the-loop. A task that enters INPUT_REQUIRED can sit there for minutes while a person decides; the caller doesn't need to hold anything open. It supplies the answer, resubscribes, and the task resumes. Durable task state is what makes "pause and ask a human" a first-class move rather than a hack.
3. Security schemes — auth is declared, not assumed
The demo agent card says "here's what I can do." The production agent card also says "and here's how you prove you're allowed to ask." A2A borrows the security-scheme model from OpenAPI: the card advertises the auth it requires, so a caller (or an automated catalog) knows how to authenticate before it sends a single message.
{ "name": "reconciliation-agent", "version": "2.1.0", "capabilities": { "streaming": true, "pushNotifications": true }, "securitySchemes": { "oauth": { "type": "oauth2", "flows": { "clientCredentials": { "tokenUrl": "https://id.example.com/token", "scopes": { "agent.invoke": "call this agent" } } } } }, "security": [{ "oauth": ["agent.invoke"] }], "skills": [{ "id": "Reconcile", "name": "Reconcile statements", "tags": ["finance"] }] } Declaring auth on the card is what lets agents from different teams — or different companies — discover and call each other without a human wiring credentials by hand each time. It also dovetails with how we scope what an agent may actually do once it's through the door: see letting an agent act as you — safely.
4. Extensions & typed capabilities — without forking the protocol
Eventually you need something the base spec doesn't model — a domain-specific capability, an extra field two of your agents agree on. The wrong move is to fork the wire format; then your agents can't talk to anyone else's. A2A's extension mechanism lets an agent declare a capability on its card (by URI) and negotiate it, so the core stays interoperable while your agents opt into richer, typed behaviour with each other. You extend at the edges and keep the lingua franca intact.
The through-line: the task id is your spine
Notice what ties all four together. Push notifications key off the task id. Resubscription reattaches by task id. Security decides who may act on a task. Extensions ride on a task's messages. Once you're in production, the task_id stops being an implementation detail and becomes the thing you build observability, retries and audit around — one id that threads a piece of work across disconnects, humans, and agent boundaries.
That's the real difference between an A2A demo and an A2A system. The demo proves the messages flow. Production is everything that keeps a piece of work alive, authenticated and accountable from the first message to the last artifact — which is exactly what "agentic workflows at scale" has to mean if the phrase is going to mean anything.
