A2A Protocol Versions
AdCP tracks the A2A specification under Linux Foundation governance. The 1.0 wire format is the target; v0.3 remains widely deployed and is supported through the compatibility period.What Changed in 1.0
| Area | v0.3 | 1.0 |
|---|---|---|
| Agent Card transport | url + protocolVersion at root | supportedInterfaces[] array with per-interface url, protocolBinding, protocolVersion |
Part discriminator | kind: "text" | "data" | "file" | No kind — content determined by which field is set (text, data, url, raw) |
| File fields | uri, name, mimeType | url (by reference) or raw (base64 bytes), filename, mediaType |
| Message role | "user" / "agent" | "ROLE_USER" / "ROLE_AGENT" (ProtoJSON canonical) |
| Task state | "completed", "working", … | "TASK_STATE_COMPLETED", "TASK_STATE_WORKING", … |
| Timestamps | ISO-8601 | ISO-8601 UTC with ms precision (YYYY-MM-DDTHH:mm:ss.sssZ) |
status field (returned by @adcp/sdk) continues to use the lowercase shorthand ("completed", "working", …) — that is an AdCP abstraction over the raw A2A status.state, not an A2A wire value.
Dual-Version Compatibility
Servers that need to serve both v0.3 and 1.0 clients advertise both interfaces in their Agent Card and enable explicit compatibility at the transport layer (e.g.enable_v0_3_compat=True in the Python SDK). Backward compatibility is not enabled by default.
Clients that speak 1.0 can talk to a v0.3 server when the SDK provides downward translation; the reverse (v0.3 client → 1.0-only server) requires the server to enable compat.
Examples in This Guide
Examples below use 1.0 wire format (nokind field, ProtoJSON enums). For a v0.3 server, the same Part becomes { kind: "text", text: "…" } and states become lowercase. AdCP extraction clients (see A2A Response Extraction) accept both shapes during the compatibility period.
A2A Client Setup
1. Initialize A2A Client
2. Verify Agent Card
3. Send Your First Task
Message Structure (A2A-Specific)
Multi-Part Messages
A2A’s key advantage is multi-part messages combining text, data, and files:Skill Invocation Methods
Natural Language (Flexible)
Explicit Skill (Deterministic)
Hybrid Approach (Recommended)
A2A Response Format
New in AdCP 1.6.0: All responses include unified status field.Canonical Response Structure
AdCP responses over A2A MUST include at least one DataPart (a Part carrying adata field) containing the task response. A TextPart (a Part carrying a text field) for human-readable messages is recommended but optional.
kind discriminator — the Part’s content type is implied by which field is set (text, data, url, or raw). For v0.3 servers/clients, the equivalent Part includes "kind": "text" / "kind": "data" / "kind": "file".
For complete canonical format specification, see A2A Response Format.
A2A-Specific Fields
- taskId: A2A task identifier for streaming updates
- contextId: Automatically managed by A2A protocol
- artifacts: Multi-part deliverables with text and data parts
- status: AdCP’s unified lowercase shorthand, mapped from A2A’s
status.state(see A2A Response Extraction)
Processing Artifacts
AdCP responses use the lastDataPart as authoritative when multiple data parts exist (e.g., from streaming operations):
Push Notifications (A2A-Specific)
A2A defines push notifications natively viaPushNotificationConfig. When you configure a webhook URL, the server will POST task updates directly to your endpoint instead of requiring you to poll.
Correlation: payload field, not URL
Correlate incoming notifications usingoperation_id (and task_type) from the payload body — never by parsing pushNotificationConfig.url. The URL is opaque to the server; the wire-level source of truth for correlation is the payload field. See Webhooks — Operation IDs and URL templates for the full normative wire contract (it applies to both MCP and A2A — every comparable async-notification protocol in ad tech makes the URL opaque to the firing entity).
Buyers MAY encode operation_id in the URL path or query as a routing aid for their own HTTP server — many web frameworks dispatch on path segments before parsing the body — but that’s a buyer-side server design choice, not part of the wire contract. A buyer’s server-routing template is not visible to the seller; the seller reads operation_id only from the buyer-supplied pushNotificationConfig.operation_id field and echoes it verbatim in the payload.
URL templates (buyer-side server routing only):
SSE Streaming (A2A-Specific)
A2A’s key advantage is real-time updates via Server-Sent Events: AdCP still owns the application-layer task lifecycle on A2A. A2ATask, taskId, SSE, and push-notification frames are transport delivery mechanics; the durable business operation remains the AdCP payload keyed by AdCP task_id. A completed A2A task can still carry an AdCP response whose payload says status: 'submitted'.
Task Monitoring
Real-Time Updates Example
A2A Webhook Payload Examples
Example 1:Task payload for completed operation
When a task finishes, the server sends the full Task object wrapped in the A2A 1.0 StreamResponse envelope. The task result lives in .artifacts:
completed, failed, or rejected status, the AdCP task result MUST be in .artifacts[0].parts[]. If the server has only a free-text fatal message (no structured payload), it MAY fall back to status.message.parts[] — clients handle both.
The A2A 1.0 StreamResponse oneof wraps every SSE frame and push-notification payload with exactly one of: { task }, { statusUpdate }, { artifactUpdate }, { message } (A2A 1.0 §3.2.3, §4.3.3). Non-streaming responses from tasks/get and v0.3 servers deliver the bare object. Clients unwrap before reading fields.
Example 2: TaskStatusUpdateEvent for progress updates
During execution, interim status updates can include optional data in status.message.parts[]. SSE/push frames wrap the event as { "statusUpdate": { … } }:
async-response-data.json. Note that interim status schemas are evolving and may change in future versions, so implementors may choose to handle them more loosely.
A2A Webhook Payload Types
Per the A2A 1.0 specification, the server sends different payload types wrapped in theStreamResponse oneof:
| Envelope Key | Inner Payload | When Used | What It Contains |
|---|---|---|---|
task | Task | Final states (completed, failed, canceled, rejected) or when full context needed | Complete task object with all history and artifact data |
statusUpdate | TaskStatusUpdateEvent | Status transitions during execution (working, input-required, auth-required, submitted) | Lightweight status change with message parts |
artifactUpdate | TaskArtifactUpdateEvent | Streaming artifact updates | Artifact chunk with append / lastChunk flags |
message | Message | Out-of-band agent messages | A message unattached to a task status transition |
{ task }for final results (completed,failed,rejected){ statusUpdate }for progress updates (working,input-required,auth-required)
tasks/get) deliver the bare payload — unwrapping a single-key envelope is a no-op there.
Envelope semantics:
{ artifactUpdate }frames carry incremental artifact chunks with boolean flagsappend(concatenate parts onto the named artifact) andlastChunk(marks the final chunk). AdCP clients consuming streams SHOULD accumulate these into the target artifact, then apply the extraction algorithm when the{ task }frame arrives with a terminal state. Clients consuming push notifications typically receive the already-mergedTaskobject and can ignore individualartifactUpdateframes. See A2A 1.0 §7.3.{ message }frames are out-of-band agent messages unattached to a task status transition. AdCP is task-oriented — task-facing clients SHOULD log and ignore baremessageenvelopes.
Webhook Trigger Rules
Webhooks are sent when all of these conditions are met:- Task type supports async (e.g.,
create_media_buy,sync_creatives,get_products) pushNotificationConfigis provided in the request- Task runs asynchronously — initial response is
workingorsubmitted
completed, failed, rejected), no webhook is sent—you already have the result.
Status changes that trigger webhooks:
working→ Progress update (task actively processing)input-required→ Human input neededauth-required(1.0) → Re-authentication challenge during executioncompleted→ Final result availablefailed→ Error detailsrejected(1.0) → Policy/validation rejection withadcp_errorcanceled→ Cancellation confirmed
Data Schema Validation
The DataPartdata field in A2A webhooks uses status-specific schemas:
| Status | Schema | Contents |
|---|---|---|
completed | [task]-response.json | Full task response (success branch) |
failed | [task]-response.json | Full task response (error branch) |
rejected (1.0) | [task]-response.json (error branch) | Policy/validation rejection with adcp_error |
working | [task]-async-response-working.json | Progress info (percentage, step) |
input-required | [task]-async-response-input-required.json | Requirements, approval data |
auth-required (1.0) | [task]-async-response-auth-required.json | Auth challenge (scheme, URL, scopes) |
submitted | [task]-async-response-submitted.json | Acknowledgment (usually minimal) |
async-response-data.json
Webhook Handler Example
Context Management (A2A-Specific)
Key Advantage: A2A handles context automatically - no manual context_id management needed.Automatic Context
Explicit Context (Optional)
Multi-Modal Messages (A2A-Specific)
A2A’s unique capability - combine text, data, and files in one message:Creative Upload with Context
Campaign Brief + Assets
Available Skills
All AdCP tasks are available as A2A skills. Use explicit invocation for deterministic execution: Task Management: For comprehensive guidance on tracking async operations across all domains, polling patterns, and webhook integration, see Webhooks.Skill Structure
Available Skills
- Protocol:
get_adcp_capabilities(start here to discover agent capabilities) - Media Buy:
get_products,list_creative_formats,create_media_buy,update_media_buy,sync_creatives,get_media_buy_delivery,provide_performance_feedback - Signals:
get_signals,activate_signal
Agent Cards
A2A agents advertise capabilities via Agent Cards at.well-known/agent.json.
Discovering Agent Cards
Sample Agent Card Structure (A2A 1.0)
In 1.0, the top-levelurl and protocolVersion fields from v0.3 are replaced by a supportedInterfaces array. Each entry advertises one transport binding and protocol version. supportsAuthenticatedExtendedCard moved to capabilities.extendedAgentCard.
Dual-Advertising for v0.3 Compatibility
Servers transitioning from v0.3 advertise both interfaces. Clients pick the version they understand:enable_v0_3_compat=True when constructing routes — backward compatibility is not enabled by default. See the A2A Python SDK 1.0 migration guide.
AdCP Extension
Recommended: Use
get_adcp_capabilities for runtime capability discovery. The agent card extension provides static metadata for agent registries and discovery services.extensions array to declare AdCP support programmatically.
The A2A protocol uses an extensions array where each extension has:
uri: Extension identifier (usehttps://adcontextprotocol.org/extensions/adcp)description: Human-readable description of how you use AdCPrequired: Whether clients must support this extension (typicallyfalsefor AdCP)params: AdCP-specific configuration (see schema below)
adcp-extension.json schema was used in v2 to describe these params, but was removed in v3. For v3+ agents, use the get_adcp_capabilities task for runtime capability discovery instead. The extension params object above shows the typical structure.
:::note
The adcp_version field in agent card metadata is a v2 convention and is not part of the v3 spec. For v3 version negotiation, the buyer sends release-precision adcp_version (e.g., "3.1") on every request, and the seller advertises supported releases via adcp.supported_versions on get_adcp_capabilities and echoes adcp_version at the envelope root on every response. The legacy integer-only adcp_major_version field is still accepted for backwards compatibility. See versioning.mdx § Version negotiation for the full contract.
:::
Benefits:
- Clients can discover AdCP capabilities without making test calls
- Declare which protocol domains you implement (media_buy, creative, signals)
- Enable compatibility checks based on version
Integration Example
A2A-Specific Considerations
Error Handling
Failed tasks carry structured AdCP errors in artifactDataPart under the adcp_error key. For the full extraction logic and recovery behavior, see Transport Error Mapping.
Creative Upload Error Handling
For uploading creative assets and handling validation errors, use thesync_creatives task. See sync_creatives Task Reference for complete testable examples.
The @adcp/sdk library handles A2A artifact extraction automatically, so you don’t need to manually parse the response structure.
Best Practices
- Use hybrid messages for best results (text + data + optional files)
- Check status field before processing artifacts
- Leverage SSE streaming for real-time updates on long operations
- Reference Core Concepts for status handling patterns
- Use agent cards to discover available skills and examples
Next Steps
- Core Concepts: Read Task Lifecycle for status handling and workflows
- Task Reference: See Media Buy Tasks and Signals
- Protocol Comparison: Compare with MCP integration
- Examples: Find complete workflow examples in Core Concepts