Skip to main content
Transport-specific guide for integrating AdCP using the Agent-to-Agent Protocol. For task handling, status management, and workflow patterns, see Task Lifecycle.

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

AdCP’s own unified top-level 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 (no kind 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

Deterministic AdCP invocation on A2A 1.0 uses the AdCP A2A Profile Extension v3, identified by https://adcontextprotocol.org/extensions/adcp/v3. Clients activate it on every request with A2A-Extensions.

1. Initialize an A2A 1.0 client

2. Verify Agent Card

3. Send Your First Task

Message Structure (A2A-Specific)

Profile Invocation Messages

A profile invocation contains exactly one authoritative DataPart with { skill, input }. It may also contain advisory TextParts. Text never overrides the structured input:

Skill Invocation Methods

Natural Language (Separate Interface)

The Agent Card used above marks the AdCP profile required: true, so a text-only request is invalid on that interface. An agent that also supports generic conversation publishes a separate Agent Card/interface without the required profile. Context correlation does not turn text into typed AdCP input.

Explicit Skill (Deterministic)

Structured Invocation with Generated Display Text

The profile rejects parameters as an alias and rejects ambiguous messages with multiple invocation DataParts. SDKs should omit TextParts by default or generate a display-only label; implementers should never put instructions there. File and resource references belong in fields defined by the selected AdCP request schema. See the profile specification for the normative rules. Status Handling: See Task Lifecycle for complete status handling patterns.

A2A Response Format

New in AdCP 1.6.0: All responses include unified status field.

Normalized SDK Response Structure

AdCP responses over A2A MUST include at least one DataPart (a Part carrying a data field) containing the task response. A TextPart (a Part carrying a text field) for human-readable messages is recommended but optional. The following is the normalized @adcp/sdk client shape. It flattens raw A2A Task.status.state to lowercase status and exposes the A2A Task id as taskId; it is not the raw A2A 1.0 wire object.
The A2A 1.0 wire format carries no 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.

Normalized A2A Fields

  • taskId: A2A Task id, renamed by the SDK adapter
  • 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 last DataPart as authoritative when multiple data parts exist (e.g., from streaming operations):
For complete response structure requirements, error handling, and implementation patterns, see A2A Response Format.

Push Notifications and AdCP Webhooks

A2A transport notifications and AdCP application webhooks have different lifetimes. configuration.taskPushNotificationConfig asks A2A to deliver updates for the current A2A Task. It does not track a durable AdCP operation after that Task completes. For an AdCP Submitted result, put push_notification_config inside the task’s typed input; its operation_id is the durable webhook correlation key. Durable AdCP webhook:
When transport-level delivery is useful while the handler is still running, pass the separate A2A 1.0 configuration:
An initial SendMessage request does not set taskId in that configuration; the A2A server assigns the transport Task ID. A2A’s configuration has no AdCP operation_id field. For webhook payload formats, protocol comparison, and detailed handling examples, see Webhooks.

SSE Streaming (A2A-Specific)

A2A streaming uses the protocol operations SendStreamingMessage and SubscribeToTask, whose SSE events each contain a StreamResponse branch. Clients must send the same authentication, A2A-Version, and A2A-Extensions service parameters required by non-streaming calls. A bare browser EventSource cannot set those headers and is not a portable profile client. The minimal helper earlier in this guide implements non-streaming SendMessage. With the default returnImmediately: false, that operation waits for a terminal or interrupted A2A state. A streaming-capable adapter should expose the official streaming operations and parse { task }, { statusUpdate }, { artifactUpdate }, and { message } frames. If an AdCP handler ultimately returns status: "submitted", the final A2A Task is still completed; poll the durable operation with fresh typed get_task_status invocations.

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:
CRITICAL: For 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 the native A2A Get Task operation 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": { … } }:
Do not conflate the two submitted values. Native A2A TASK_STATE_SUBMITTED is an interim transport state and may appear in a TaskStatusUpdateEvent before an AdCP handler returns. An AdCP response whose DataPart contains status: "submitted" is instead pinned inside an A2A TASK_STATE_COMPLETED Task by the AdCP v3 profile. Observe that durable AdCP operation with get_task_status.

A2A Webhook Payload Types

Per the A2A 1.0 specification, the server sends different payload types wrapped in the StreamResponse oneof: For AdCP, most webhooks will be:
  • { task } for final results (completed, failed, rejected)
  • { statusUpdate } for progress updates (working, input-required, auth-required)
Clients unwrap the single-key envelope before reading fields. Non-streaming responses (for example, native A2A Get Task) deliver the bare payload — unwrapping a single-key envelope is a no-op there. Envelope semantics:
  • { artifactUpdate } frames carry incremental artifact chunks with boolean flags append (concatenate parts onto the named artifact) and lastChunk (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-merged Task object and can ignore individual artifactUpdate frames. 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 bare message envelopes.

Webhook Trigger Rules

Webhooks are sent when all of these conditions are met:
  1. Task type supports async (e.g., create_media_buy, sync_creatives, get_products)
  2. configuration.taskPushNotificationConfig is provided in the request
  3. The A2A transport task runs asynchronously — initial A2A state is working or native submitted
If the initial response is already terminal (completed, failed, rejected), no webhook is sent—you already have the result. An AdCP status: "submitted" DataPart does not keep the A2A Task open and does not turn A2A push notifications into AdCP-operation notifications. The profile returns it inside a completed A2A Task; use get_task_status (or an AdCP webhook explicitly defined by the task schema) for the durable operation. Status changes that trigger webhooks:
  • working → Progress update (task actively processing)
  • input-required → Human input needed
  • auth-required (1.0) → Re-authentication challenge during execution
  • completed → Final result available
  • failed → Error details
  • rejected (1.0) → Policy/validation rejection with adcp_error
  • canceled → Cancellation confirmed

Data Schema Validation

The DataPart data field in A2A webhooks uses status-specific schemas: Schema reference: async-response-data.json

Webhook Handler Example

Context Management (A2A-Specific)

A2A assigns contextId on the first exchange. A client continues that context by placing the returned value inside the next Message. The typed invocation remains complete and authoritative on every turn.

File and Multi-Modal Inputs

Generic A2A messages can combine text, data, and files. The activated AdCP v3 A2A profile deliberately narrows invocation messages to one structured DataPart plus optional advisory TextParts. Put resource references in the selected AdCP task’s typed input; do not add a FilePart that the task schema cannot validate.

Creative Upload with Context

If a task schema does not define a field for the file or resource, that input is not supported by the AdCP v3 A2A profile. Use a separate generic A2A interface or first transform the resource into schema-valid AdCP fields.

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, create_media_buy, update_media_buy, sync_creatives, get_media_buy_delivery, provide_performance_feedback
  • Signals: get_signals, activate_signal
Task Parameters: See Media Buy and Signals documentation for complete parameter specifications.

Agent Cards

A2A 1.0 agents advertise capabilities via Agent Cards at .well-known/agent-card.json.

Discovering Agent Cards

Sample Agent Card Structure (A2A 1.0)

In 1.0, the top-level url 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:
Python SDK servers must also pass 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

Use get_adcp_capabilities for runtime capability discovery. The Agent Card extension declaration identifies the A2A wire profile only.
Include the versioned AdCP profile under capabilities.extensions[] and activate it on every invocation with A2A-Extensions: https://adcontextprotocol.org/extensions/adcp/v3. The A2A protocol’s AgentExtension has:
  • uri: Extension identifier (https://adcontextprotocol.org/extensions/adcp/v3)
  • description: Human-readable description of how you use AdCP
  • required: true on an interface that requires the structured AdCP profile
  • params: Omitted or empty for this profile
The profile forbids copying AdCP versions, supported domains, or feature flags into extension params. Those values change at runtime and remain authoritative only in get_adcp_capabilities. The unversioned v2 adcp-extension.json capability payload is not part of this profile. :::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 negotiate one versioned, deterministic AdCP message shape
  • Runtime capability discovery has one authority: get_adcp_capabilities
  • Breaking profile changes negotiate through a new extension URI rather than ambiguous params

Integration Example

A2A-Specific Considerations

Error Handling

Failed tasks carry structured AdCP errors in artifact DataPart 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 the sync_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

  1. Use hybrid messages for best results (text + data + optional files)
  2. Check status field before processing artifacts
  3. Leverage SSE streaming for real-time updates on long operations
  4. Reference Core Concepts for status handling patterns
  5. Use agent cards to discover available skills and examples

Next Steps

For status handling, async operations, and clarification patterns, see Task Lifecycle - this guide focuses on A2A transport specifics only.