The 30-second rule
Any AdCP task can return one of these statuses. The server chooses based on what it knows about the work involved:| Expected duration | Status | What the caller does |
|---|---|---|
| Under 30 seconds | completed / failed | Result is inline — done |
| Over 30 seconds, server actively processing | working | Out-of-band progress signal. Connection stays open, result arrives when ready. Caller just waits |
| Blocked on external dependency | submitted | Truly async — configure a webhook via push_notification_config. Result may take hours or days |
| Blocked on human input | input-required | Caller provides the requested input to continue |
working is not async. It’s a progress signal the server sends out-of-band (via MCP status notifications or SSE) while it continues processing. The caller holds the connection and receives the result when it’s ready — no polling, no webhooks. Think of it as “this is taking a moment, but I’m on it.”
submitted is async. The operation is blocked on something outside the server’s control — publisher approval, human review, third-party processing. The caller should configure a webhook and move on.
:::tip Webhooks for submitted operations
Webhooks are the recommended approach for submitted operations — they work with any transport (MCP, A2A, REST) and handle operations that outlive a single session. See Push Notifications.
Polling via tasks/get works as a simpler alternative or backup. See the polling pattern below.
MCP Tasks handle async at the protocol level, but client support is still limited — most chat-based MCP clients (Claude Desktop, Cursor) don’t yet support task-augmented tool calls. If you’re building your own MCP client or using the JS SDK directly, MCP Tasks work well. See MCP Guide.
:::
Operation examples
Synchronous (instant)
| Operation | Description |
|---|---|
get_adcp_capabilities | Agent capability discovery |
list_creative_formats | Format catalog |
build_creative (library retrieval) | Resolving an existing creative_id |
May need human input
| Operation | Description |
|---|---|
get_products | When brief is vague or needs clarification |
create_media_buy | When approval is required |
build_creative (generation) | When creative direction or asset selection is needed |
May go async (submitted)
| Operation | Description |
|---|---|
create_media_buy | Publisher approval workflows |
sync_creatives | Asset review and transcoding pipelines |
build_creative (with review) | Human creative review before finalizing |
activate_signal | Platform deployment pipelines |
Timeout Configuration
Set reasonable timeouts based on status:working uses a connection timeout (how long to hold open), not a poll interval. The server sends progress out-of-band and delivers the result on the same connection. submitted uses a webhook delivery window — if you’re also polling as backup, use a 30-second interval.
Human-in-the-Loop Workflows
Design Principles
- Optional by default - Approvals are configured per implementation
- Clear messaging - Users understand what they’re approving
- Timeout gracefully - Don’t block forever on human input
- Audit trail - Track who approved what when
Approval Patterns
Common Approval Triggers
- Budget thresholds: Campaigns over $100K
- New advertisers: First-time buyers
- Policy-sensitive content: Certain industries or topics
- Manual inventory: Premium placements requiring publisher approval
Progress Tracking
Progress Updates
Long-running operations may provide progress information:Displaying Progress
Protocol-Agnostic Patterns
These patterns work with both MCP and A2A.Product Discovery with Clarification
Campaign Creation with Approval
Polling for submitted Operations
Polling is a backup for submitted operations when webhooks aren’t configured or as a fallback. Don’t poll for working — the server delivers the result on the open connection.
Asynchronous-First Design
Store State Persistently
Don’t rely on in-memory state for async operations:Handle Restarts Gracefully
Resume tracking after orchestrator restarts:Best Practices
- Design async first - Assume any operation could take time
- Persist state - Don’t rely on in-memory tracking
- Handle restarts - Resume tracking on startup
- Implement timeouts - Don’t wait forever
- Show progress - Keep users informed
- Support cancellation - Let users cancel long operations
- Audit trail - Log all status transitions
Next Steps
- Webhooks: See Webhooks for push notifications instead of polling
- Task Lifecycle: See Task Lifecycle for status handling details
- Orchestrator Design: See Orchestrator Design for production patterns