Moving from A2A 0.3 to 1.0
Every breaking change between A2A 0.3 and 1.0, a before and after example, a step-by-step migration checklist, and how one endpoint can serve both versions.
A2A 1.0 keeps the concepts of 0.3 (agents, cards, tasks, messages, artifacts) and changes almost everything on the wire. Method names move to PascalCase, enum values move to ProtoJSON names such as TASK_STATE_COMPLETED and ROLE_USER, the kind discriminator disappears from parts and events, the card’s endpoint moves into supportedInterfaces, and errors carry typed google.rpc.ErrorInfo details. Version 1.0.0 was released on 12 March 2026 and the v1.0.1 patch on 28 May 2026. The protocol version string is 1.0.
Clients now declare their version with the A2A-Version header, and a request without it must be read as 0.3. That rule lets one endpoint serve both versions during a migration. This guide lists every breaking change from the specification’s migration appendix, the What’s New document and the v1.0.0 release notes, then gives a checklist and shows how a live agent answers both versions.
Method names
| v0.3 JSON-RPC method | v1.0 method |
|---|---|
message/send |
SendMessage |
message/stream |
SendStreamingMessage |
tasks/get |
GetTask |
No JSON-RPC method (0.3 listed tasks/list for gRPC and REST only) |
ListTasks, in every binding, with cursor pagination |
tasks/cancel |
CancelTask |
tasks/resubscribe |
SubscribeToTask |
tasks/pushNotificationConfig/set |
CreateTaskPushNotificationConfig |
tasks/pushNotificationConfig/get |
GetTaskPushNotificationConfig |
tasks/pushNotificationConfig/list |
ListTaskPushNotificationConfigs (now plural) |
tasks/pushNotificationConfig/delete |
DeleteTaskPushNotificationConfig |
agent/getAuthenticatedExtendedCard |
GetExtendedAgentCard |
Appendix A also renames the request and response types, which matters if your SDK exposes them: MessageSendParams became SendMessageRequest, SendMessageSuccessResponse became SendMessageResponse, SendStreamingMessageSuccessResponse became StreamResponse, SetTaskPushNotificationConfigRequest became CreateTaskPushNotificationConfigRequest, ListTaskPushNotificationConfigSuccessResponse became ListTaskPushNotificationConfigsResponse, and GetAuthenticatedExtendedCardRequest became GetExtendedAgentCardRequest.
Roles and states
| v0.3 | v1.0 |
|---|---|
user, agent |
ROLE_USER, ROLE_AGENT |
submitted, working |
TASK_STATE_SUBMITTED, TASK_STATE_WORKING |
input-required, auth-required |
TASK_STATE_INPUT_REQUIRED, TASK_STATE_AUTH_REQUIRED |
completed, failed, canceled, rejected |
TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED, TASK_STATE_REJECTED |
unknown |
No listed mapping; the v1.0 zero value is TASK_STATE_UNSPECIFIED |
gRPC users have one more rename. The v0.3 proto spelled TASK_STATE_CANCELLED with two Ls, and 1.0 standardized on the American spelling, TASK_STATE_CANCELED.
Parts, messages and events
Version 1.0 has one Part type instead of three, and the JSON member that is present says what kind of part it is.
| v0.3 | v1.0 |
|---|---|
{"kind": "text", "text": "..."} |
{"text": "..."} |
{"kind": "data", "data": {...}} |
{"data": {...}, "mediaType": "application/json"} |
{"kind": "file", "file": {"name", "mimeType", "uri"}} |
{"url": "...", "filename": "...", "mediaType": "..."} |
{"kind": "file", "file": {"name", "mimeType", "bytes"}} |
{"raw": "...", "filename": "...", "mediaType": "..."} |
mimeType |
mediaType, available on every part |
The v0.3 JSON schema named the file fields uri and bytes; the migration appendix uses the gRPC names fileWithUri and fileWithBytes for the same fields.
Stream events changed the same way. {"kind": "status-update", ...} became {"statusUpdate": {...}} and {"kind": "artifact-update", ...} became {"artifactUpdate": {...}}. The final flag on status updates is gone; the stream closing marks the end. Messages and artifacts gained an extensions list of extension URIs. Timestamps are ISO 8601 in UTC, with millisecond precision where available.
Agent Card
| v0.3 | v1.0 |
|---|---|
Top-level url and preferredTransport |
An entry in supportedInterfaces, each with url, protocolBinding and protocolVersion |
additionalInterfaces |
More entries in supportedInterfaces, in preference order |
Top-level protocolVersion, such as "0.3.0" |
protocolVersion per interface, as Major.Minor, such as "1.0" |
supportsAuthenticatedExtendedCard |
capabilities.extendedAgentCard |
| Implicit and password OAuth flows | Deprecated in the proto; use authorization code with PKCE, or the new device code flow |
| No tenant | Optional tenant per interface, sent by the client in every request |
The extended card flag moved twice during 1.0 development. It was first renamed to supportsExtendedAgentCard, then moved into capabilities. Appendix A shows that interim name as the legacy one, but a real 0.3 card uses supportsAuthenticatedExtendedCard. A client in transition can accept either legacy name.
The discovery path did not change. Version 0.3.0 had already moved the card from /.well-known/agent.json, the v0.2.x path, to /.well-known/agent-card.json. See Agent Cards explained for every v1.0 field.
Requests and bindings
SendMessageconfiguration:pushNotificationConfigbecametaskPushNotificationConfig, andblockinggave way toreturnImmediately. Blocking is the default in 1.0, and a blocking call returns at interrupted states too.- Push configs are flat. The 0.3 wrapper
{taskId, pushNotificationConfig: {...}}became one object withid,taskId,url,tokenandauthentication, andauthentication.schemes(a list) becamescheme(one value). - IDs are plain values. gRPC and HTTP requests that took resource names such as
tasks/{id}now take separate ID fields. - HTTP+JSON paths lost their
/v1prefix:POST /v1/message:sendis nowPOST /message:send. Since v1.0.1 the preferred content type isapplication/a2a+json. - gRPC: the proto package moved from
a2a.v1tolf.a2a.v1, and theSendMessageRequestfieldrequestis nowmessage, matching the other bindings.
Headers and errors
A2A-Version is new in 1.0. Clients must send it on every request, except 0.3 clients, which had no such header. Servers must read an empty value as 0.3, must process a request with the semantics of the version it names, and must return VersionNotSupportedError for one they don’t serve. Patch numbers don’t count in negotiation. The extension activation header was renamed too: 0.3’s guide used X-A2A-Extensions, and 1.0 uses A2A-Extensions.
Errors keep their JSON-RPC codes but change shape. In 0.3, error.data was free-form. In 1.0 it is an array of typed objects, and A2A errors include a google.rpc.ErrorInfo with a reason such as TASK_NOT_FOUND and the domain a2a-protocol.org. HTTP+JSON errors moved from RFC 9457 problem details (application/problem+json) to the google.rpc.Status JSON shape.
| Code | v0.3 name | v1.0 name |
|---|---|---|
-32001 to -32006 |
Unchanged | Unchanged |
-32007 |
AuthenticatedExtendedCardNotConfiguredError |
ExtendedAgentCardNotConfiguredError |
-32008 |
None | ExtensionSupportRequiredError |
-32009 |
None | VersionNotSupportedError |
Before and after
Illustrative: the same interrupted task in both versions. First v0.3:
{
"kind": "task",
"id": "task-51",
"contextId": "ctx-9",
"status": {
"state": "input-required",
"timestamp": "2026-09-26T15:00:00Z",
"message": {
"kind": "message",
"role": "agent",
"messageId": "msg-2",
"parts": [{ "kind": "text", "text": "Which pickup date should I quote?" }]
}
},
"artifacts": [
{
"artifactId": "draft-1",
"parts": [
{ "kind": "data", "data": { "lane": "Toronto-Chicago" } },
{ "kind": "file", "file": { "name": "rate-sheet.pdf", "mimeType": "application/pdf", "uri": "https://files.example.com/rate-sheet.pdf" } }
]
}
]
}
Then v1.0:
{
"id": "task-51",
"contextId": "ctx-9",
"status": {
"state": "TASK_STATE_INPUT_REQUIRED",
"timestamp": "2026-09-26T15:00:00.000Z",
"message": {
"role": "ROLE_AGENT",
"messageId": "msg-2",
"parts": [{ "text": "Which pickup date should I quote?" }]
}
},
"artifacts": [
{
"artifactId": "draft-1",
"parts": [
{ "data": { "lane": "Toronto-Chicago" }, "mediaType": "application/json" },
{ "url": "https://files.example.com/rate-sheet.pdf", "filename": "rate-sheet.pdf", "mediaType": "application/pdf" }
]
}
]
}
Migration checklist
For clients:
- Send
A2A-Version: 1.0on every request. - Rename every method call, using the table above.
- Compare states and roles against the
TASK_STATE_*andROLE_*values. Treat any value you don’t recognize as unknown instead of failing. - Read parts by member presence (
text,data,url,raw) and build them withoutkind. RenamemimeTypetomediaType. - Read stream events by member name, and treat the stream closing as the end.
- Pick an endpoint from
supportedInterfaces: the first entry whose binding and version you support. Send itstenantif it has one. Readcapabilities.extendedAgentCard. - Read
error.dataas an array and branch onErrorInfo.reason. Handle-32008and-32009. - Replace
blockingwithreturnImmediately, and send push configs in the flat shape. - Send extension URIs in
A2A-Extensions. - On HTTP+JSON, drop
/v1from paths. On gRPC, regenerate from the 1.0 proto.
For servers:
- Publish
supportedInterfaceswith one entry per binding and version, and remove the old top-level fields. - Move the extended card flag into
capabilities. - Re-sign the card if you sign it. The signature covers the canonical card, so any edit breaks the old one.
- Validate
A2A-Version: read empty as 0.3, reject unsupported versions with-32009. - Emit v1.0 shapes for v1.0 requests, with no
kind. The appendix recommends emitting only current forms. - Return errors with
ErrorInfodetails and the new names. - If you add
ListTasks, scope results to what the caller may see, as section 13.1 requires.
What’s New suggests three phases. First, a compatibility layer that parses both the old and new forms. Second, dual support: emit 1.0 everywhere, keep 0.3 readers, and add A2A-Version handling. Third, 1.0 only: remove the legacy parsing once your callers have moved. Its testing advice covers data in both formats, card signature checks, pagination edge cases such as empty and single-page results, the new error types, and required-extension checks. Section 3.6.3 adds a warning for clients: if you need 1.0 features, request 1.0 explicitly and don’t fall back to 0.3 automatically, or you lose those features without noticing.
Serving both versions at once
Emissar’s public agent at https://emissar.ai/a2a/v1 answers 0.3 and 1.0 on one JSON-RPC endpoint. Its behavior, as of 2026-09-26:
| Request | What the agent does |
|---|---|
A 1.0 method name, such as SendMessage |
Answers in 1.0 shapes |
A 0.3 method name: message/send, tasks/get or tasks/cancel |
Answers in 0.3 shapes: kind fields, lowercase states and roles |
A2A-Version of 1.0 or 0.3, with or without a patch number |
Accepted; the method name still decides the shapes |
No A2A-Version |
Accepted |
Any other A2A-Version |
-32009, before the method runs |
| 0.3 or 1.0 names for streaming, push configs or the extended card | The same refusals in both: -32004 or -32003 |
Both versions read and write one task store, so a task created over 1.0 can be read with tasks/get. Dispatching on the method name works because the two versions share no method names. The header check stops versions the agent doesn’t serve.
A real 0.3 call with no A2A-Version header, on 2026-09-26:
curl -s https://emissar.ai/a2a/v1 \
-H 'Content-Type: application/json' \
-d '{"jsonrpc": "2.0", "id": 8, "method": "message/send",
"params": {"message": {"kind": "message", "role": "user", "messageId": "smoke-test-docs-v03-1",
"parts": [{"kind": "text", "text": "What does Emissar do?"}]}}}'
{
"jsonrpc": "2.0",
"id": 8,
"result": {
"kind": "task",
"id": "02f322e1-48e5-4572-b044-c4c20982c1c3",
"contextId": "bbc62fd0-5b0c-4c55-8eaa-535f67dce4d2",
"status": {
"state": "completed",
"timestamp": "2026-09-26T20:21:18.079Z"
},
"artifacts": [
{
"artifactId": "adbe8179-58e6-4e3f-aa40-926b9b946e03",
"name": "Answer",
"parts": [
{
"kind": "text",
"text": "Emissar is building the network where AI agents from different companies find each other, prove who they represent, and settle requests directly, instead of talking over phone lines and chat widgets built for people. It builds on the open A2A protocol and adds what A2A leaves open: finding an agent from a phone number or name, verifying agents, scoped authorization, signed records, payments, and handoff to people."
}
]
}
],
"history": [
{
"kind": "message",
"role": "user",
"parts": [
{
"kind": "text",
"text": "What does Emissar do?"
}
],
"messageId": "smoke-test-docs-v03-1",
"taskId": "02f322e1-48e5-4572-b044-c4c20982c1c3",
"contextId": "bbc62fd0-5b0c-4c55-8eaa-535f67dce4d2"
}
],
"metadata": {
"skill": "about-emissar"
}
}
}
A SendMessage with A2A-Version: 0.5 returned -32009 with the reason VERSION_NOT_SUPPORTED. The bindings guide shows the full response.
Discovery is the harder part of serving both. The agent publishes its 1.0 card at /.well-known/agent-card.json and a 0.3-shaped card, with url and preferredTransport, at /.well-known/agent.json. A 0.3.0 client looks for agent-card.json, so it receives the 1.0 card, which has no top-level url. There are two ways to close that gap. One is to add the 0.3 top-level fields to the 1.0 card; section 5.7 says implementations should ignore fields they don’t recognize, so 1.0 clients should skip them. The other is to configure 0.3 clients with the endpoint directly. Test either choice against the SDKs your callers use.
Questions
- Did the Agent Card location change between 0.3 and 1.0?
- No. Version 0.3.0 moved the card from /.well-known/agent.json to /.well-known/agent-card.json, and 1.0 kept that path. Only v0.2.x agents used agent.json.
- What happens if a 1.0 client forgets the A2A-Version header?
- The server must treat the request as 0.3. A strict 0.3-only reading would not recognize a method such as SendMessage. Some servers are lenient and decide by method name, but a client should not rely on that: send A2A-Version: 1.0 on every request.
- Do I have to drop 0.3 support once I move to 1.0?
- No. An agent can expose several interfaces with different protocol versions, at the same URL or at different ones, and must process each request with the semantics of the version it names.
Sources
- A2A Protocol Specification, Appendix A: Migration and legacy compatibility (plus sections 3.6 and 5) (accessed )
- What's new in A2A v1.0 (A2A documentation) (accessed )
- A2A v1.0.0 release notes (accessed )
- A2A v1.0.1 release notes (accessed )
- A2A v0.3.0 release notes (well-known URI changed to agent-card.json) (accessed )
- A2A Protocol Specification v0.3.0 (accessed )
- A2A v0.3.0 JSON types (types.ts) (accessed )
- A2A v0.3.0 gRPC definition (a2a.proto) (accessed )
- A2A v0.3.0 extensions guide (X-A2A-Extensions header) (accessed )
- A2A protocol definition (a2a.proto), current (accessed )
- Emissar Agent Card (live example agent) (accessed )