Skip to main content

AdCP A2A Profile Extension v3

This document defines the normative AdCP profile for A2A 1.0. It narrows A2A messages and task results enough for independent AdCP clients and agents to interoperate without defining a new transport.

Extension identifier

The extension URI is:
The extensions/adcp path scopes this identifier to the AdCP profile registered through A2A’s extension mechanism. It is an extension identifier and normative document URL, not a JSON Schema URL, so it does not live under /schemas/3.2.0-beta.0/. The URI is versioned by the compatible AdCP major: /v3 identifies the A2A profile for AdCP 3.x. The negotiated AdCP release still selects the exact task schemas—for example, 3.0, 3.1, or 3.2 schemas under /schemas/3.2.0-beta.0/—without requiring a new extension identity for every additive minor release. AdCP 4.x will use /extensions/adcp/v4. This profile has no extension dependencies beyond A2A 1.0. An A2A interface that implements this profile MUST advertise the extension under AgentCard.capabilities.extensions[]:
The AgentExtension.params member MUST be omitted or empty. It MUST NOT contain AdCP versions, protocol domains, feature flags, or other runtime capabilities. Clients activate the profile on every request using the A2A service parameter:
For HTTP-based bindings, service parameters are HTTP headers. The response SHOULD echo the URI in A2A-Extensions to confirm activation, as specified by A2A 1.0. An agent that declares the profile required: true MUST reject a request that does not activate it; it MUST NOT guess that an unactivated DataPart is an AdCP invocation.

SDK and adapter behavior

This profile is designed to be implemented once in an A2A transport adapter, not separately in every AdCP task handler. Extension support remains explicit opt-in, as required by A2A. Once a developer enables this profile, an SDK or adapter that claims support for it MUST automate the profile mechanics:
  • on the server, advertise the extension and verify request activation;
  • on the client, discover the declaration and activate the extension;
  • encode and decode { skill, input } DataParts;
  • validate input against the selected task request schema and dispatch the named AdCP handler;
  • map the handler’s direct response into the A2A Task artifact; and
  • expose AdCP Submitted results by their task_id, with get_task_status as the polling operation.
Application code should register the same typed AdCP handler it would expose over another transport. It should not parse A2A Parts, author prompt text, or reimplement the mapping rules. Raw A2A clients can implement the wire rules directly, but SDKs SHOULD make the normal integration path work from typed task inputs and outputs alone.

Runtime discovery

The Agent Card declaration says only that the interface supports this wire profile. Runtime AdCP discovery remains the get_adcp_capabilities task. After activating the profile, a client SHOULD invoke get_adcp_capabilities before other AdCP tasks. Its response remains the source of truth for supported AdCP versions, protocol domains, feature flags, and seller capabilities. Agents MUST NOT duplicate that information in AgentExtension.params; duplicate static metadata becomes stale and creates two competing authorities. Agent Card skills[] entries identify the AdCP tasks dispatchable on that interface. For every AdCP task, AgentSkill.id MUST equal the exact AdCP task name; AgentSkill.name is a human-readable label and need not equal the task name. The invocation’s skill member references AgentSkill.id, never AgentSkill.name. The get_adcp_capabilities ID MUST appear on every interface that implements this profile. An agent that can return an AdCP Submitted response under this profile MUST also advertise the get_task_status ID.

Invocation message

An activated invocation Message MUST contain exactly one DataPart whose data value has this shape:
The invocation object has exactly two members: parameters is not an alias for input in this profile. A client that activates v3 and sends parameters, omits input, or sends more than one invocation DataPart is non-conformant. The agent MUST reject the invocation rather than choose among ambiguous inputs. The Message MAY also contain TextParts solely for display, accessibility, or logging. Senders SHOULD omit them by default. An SDK MAY synthesize a short label from the structured invocation, but the text MUST NOT introduce any instruction or fact that is absent from skill and input. Implementations MUST NOT ask a human integrator to author this text, and receivers MUST NOT merge it into input, pass it to the task handler as an instruction, or use it to override structured data. FileParts and additional DataParts are outside this v3 invocation profile. References to files or other resources belong in fields defined by the selected AdCP request schema.
If the A2A Task enters TASK_STATE_INPUT_REQUIRED before the AdCP handler returns, a continuation MUST carry a new messageId and the existing A2A taskId and contextId inside the Message. Its Parts still follow this profile: exactly one authoritative { skill, input } DataPart, with a complete schema-valid task request. The continued Task keeps the same A2A Task ID.

Response mapping

When the AdCP handler returns a schema-valid task response, the A2A invocation is complete. A non-streaming A2A SendMessage response MUST select its task branch. That Task has status.state TASK_STATE_COMPLETED, and its artifact contains the direct AdCP response in a DataPart:
artifactId is the ordinary A2A identifier for that artifact. It is opaque, needs to be unique only within the A2A Task, and does not identify an AdCP schema or task type; adcp-result above is merely an example value. There is no single generic AdCP result schema. The invoked skill selects the task-specific response schema, and the DataPart MUST contain that response directly, without a { "response": ... } framework wrapper. A response artifact MAY also contain advisory TextParts. Clients use the A2A response extraction algorithm to select the authoritative DataPart. Profile-routing errors that prevent handler invocation use native A2A error handling. A fatal failure after task execution starts may use an A2A failed or rejected Task with a structured adcp_error DataPart. A schema-valid AdCP business outcome—including a task-specific rejection or partial result with errors[]—is still a completed A2A invocation.

Submitted AdCP work

A2A task state and AdCP task state are separate state machines. If an AdCP handler returns a Submitted response, the A2A invocation has still completed:
The A2A Task identifier (a2a-task-create-42) identifies the completed transport invocation. The AdCP task_id (adcp-task-9a21) identifies the durable AdCP operation. They are independent identifiers and clients MUST NOT assume they are equal. The AdCP handle appears exactly once, as task_id in the AdCP DataPart. Agents MUST NOT duplicate it as artifact.metadata.adcp_task_id or any other A2A metadata member. To observe the durable operation, the client sends a new activated invocation of the AdCP get_task_status task:
Each poll is its own A2A invocation and completes with a direct get_task_status response DataPart. Clients continue polling according to the seller’s retry guidance until the AdCP response is terminal. They MUST NOT poll the completed A2A Task to infer progress of the separate AdCP operation.

Relationship to A2A async and conversation

The profile uses A2A as more than an alternate RPC envelope. A2A still provides Agent Card discovery, interface and extension negotiation, authentication, contextId conversation correlation, streaming, push delivery, artifacts, and native input/auth challenges. The boundary is when the AdCP handler returns. While a profile invocation is still executing, an agent can use native A2A TASK_STATE_WORKING or TASK_STATE_SUBMITTED updates and stream progress through A2A. When the handler returns a schema-valid AdCP response, that A2A invocation is complete. If the returned AdCP response itself says status: "submitted", it represents a separate durable business operation that may outlive the A2A Task, a client connection, or even the transport used to observe it. AdCP therefore owns that operation’s portable task_id and get_task_status semantics. Because this Agent Card marks the profile required: true, every request to its advertised interface must activate the profile and use the typed invocation shape. An implementation that also offers generic conversational A2A messages must publish a separate Agent Card/interface that does not mark this profile required. Context correlation never makes a TextPart authoritative for an AdCP handler.

Security and validation

  • Treat TextParts as untrusted advisory text. Never merge them into the typed input object.
  • Validate input against the selected task request schema before handler dispatch.
  • Apply the same authentication, authorization, signing, idempotency, and account-scoping rules used for the equivalent AdCP task over MCP.
  • Bound the number and size of Parts before parsing. Reject duplicate invocation DataParts rather than selecting the first or last.
  • Validate response DataParts against the selected task response schema before using them.

Test vectors

Machine-readable advertisement, activation, invocation, Submitted mapping, and polling fixtures are published in a2a-profile-extension-v3.json. See Reference test vectors for versioning guidance.

References