Core Protocol Specification
These are the key constraints of the A2A core protocol, seen from an implementer’s point of view. MUST / SHOULD / MAY carry their RFC 2119 meanings, and the items correspond to chapters 3 and 5 of the official specification.
The three-layer model
The specification has three layers, and the upper layers do not depend on the transport details of the lower ones:
- Canonical data model (Layer 1): objects such as
Task,Message,AgentCard,Part, andArtifact, defined in Protocol Buffers and independent of any protocol. - Abstract operations (Layer 2): the behaviors every A2A implementation must support, such as sending a message, getting a task, and canceling a task, regardless of how they are exposed.
- Protocol bindings (Layer 3): the mapping of the abstract operations to a concrete protocol: JSON-RPC, gRPC, HTTP+JSON/REST, or a custom binding.
a2a.proto
is the single authoritative definition of all protocol objects and request/response messages. Artifacts such as JSON Schema are derived conveniences for tooling; SDKs and schemas should be generated from the proto rather than edited by hand.
Core operations and binding mapping
All bindings must provide functionally equivalent behavior. The table below is the official method mapping (HTTP paths carry no /v1 prefix):
| Functionality | JSON-RPC method | gRPC method | HTTP+JSON endpoint |
|---|---|---|---|
| Send message | SendMessage | SendMessage | POST /message:send |
| Send streaming message | SendStreamingMessage | SendStreamingMessage | POST /message:stream |
| Get task | GetTask | GetTask | GET /tasks/{id} |
| List tasks | ListTasks | ListTasks | GET /tasks |
| Cancel task | CancelTask | CancelTask | POST /tasks/{id}:cancel |
| Subscribe to task | SubscribeToTask | SubscribeToTask | POST /tasks/{id}:subscribe |
| Create push notification config | CreateTaskPushNotificationConfig | CreateTaskPushNotificationConfig | POST /tasks/{id}/pushNotificationConfigs |
| Get push notification config | GetTaskPushNotificationConfig | GetTaskPushNotificationConfig | GET /tasks/{id}/pushNotificationConfigs/{configId} |
| List push notification configs | ListTaskPushNotificationConfigs | ListTaskPushNotificationConfigs | GET /tasks/{id}/pushNotificationConfigs |
| Delete push notification config | DeleteTaskPushNotificationConfig | DeleteTaskPushNotificationConfig | DELETE /tasks/{id}/pushNotificationConfigs/{configId} |
| Get extended Agent Card | GetExtendedAgentCard | GetExtendedAgentCard | GET /extendedAgentCard |
Key points of the three bindings:
- JSON-RPC: JSON-RPC 2.0 over HTTP(S), requests and responses use
Content-Type: application/json, method names are PascalCase, and streaming uses Server-Sent Events (text/event-stream). - gRPC: gRPC over HTTP/2 with TLS, Protocol Buffers v3, and an implementation of
A2AService. - HTTP+JSON/REST: resource-style URLs with standard HTTP verbs; requests and responses SHOULD use
application/a2a+json, and streaming also uses SSE.
An agent that supports several bindings must declare all of them in its Agent Card and keep functionality, behavior, error handling, and authentication consistent across them. Clients MAY choose any declared binding and SHOULD implement fallback logic. For the rules on custom bindings, see Custom Protocol Bindings .
Behavior of the key operations
SendMessage and SendStreamingMessage
- The agent MAY create a
Taskto process the message asynchronously, or MAY return a directMessage(simple interactions need no task tracking). - Streaming: if the agent returns a
Message, the stream contains exactly that one message and closes immediately. If it returns aTask, the stream begins with theTask, followed by zero or moreTaskStatusUpdateEventorTaskArtifactUpdateEventobjects, and closes when the task reaches a terminal state. - Blocking and non-blocking:
SendMessageConfiguration.return_immediatelydefaults tofalse, in which case the operation MUST wait until the task reaches a terminal state (COMPLETED,FAILED,CANCELED,REJECTED) or an interrupted state (INPUT_REQUIRED,AUTH_REQUIRED) before returning. When set totrue, the operation returns right after creating the task, and the caller follows up withGetTask,SubscribeToTask, or push notifications. The field has no effect when a directMessageis returned or for streaming operations. - Sending a message to a task that is already in a terminal state returns
UnsupportedOperationError.
GetTask, ListTasks, and historyLength
- An unset
historyLengthmeans no limit (the server decides the default amount);0means no history (thehistoryfield SHOULD be omitted); a value greater than0returns at most that many of the most recent messages. ListTasksuses cursor-based pagination (pageToken/nextPageToken), returns tasks in descending order of status timestamp, and returns only tasks visible to the calling client.pageSizedefaults to at most 50 and ranges from 1 to 100.includeArtifactsdefaults tofalse, in which case each task in the response MUST omit theartifactsfield entirely.nextPageTokenMUST always be present and is an empty string when there are no more results.
SubscribeToTask
- It applies only to tasks that are not in a terminal state; a terminal task returns
UnsupportedOperationError. - The first event MUST be a
Taskobject with the task’s current state, which prevents information loss betweenGetTaskand the subscription. - Several streams may exist for one task at the same time: events MUST be broadcast to all active streams in the order they were generated, closing one stream does not affect the others, and the task lifecycle is independent of any single stream.
CancelTask
It requests the cancellation of a task in progress, but success is not guaranteed. A task that cannot be canceled returns TaskNotCancelableError. Cancellation is idempotent, and a repeated request MAY return TaskNotFoundError if the task has already been canceled and purged.
GetExtendedAgentCard
It is available only when the public Agent Card declares capabilities.extendedAgentCard: true, and the client MUST authenticate with one of the schemes declared in the public card. After retrieving the extended card, the client SHOULD replace its cached public card with it for the duration of the authenticated session or until the card’s version changes.
Multi-turn interactions: contextId and taskId
- contextId logically groups related
TaskandMessageobjects. When an agent generates a newcontextId, it MUST return it in the response. If it cannot accept a client-providedcontextId, it MUST reject the request and MUST NOT generate a different one for the response. Clients SHOULD NOT invent acontextIdunless they understand how the server will handle it, and server-generated values should be treated as opaque. - taskId is always generated by the server. When a client message includes a
taskId, it MUST reference an existing task, otherwise the agent returnsTaskNotFoundError. Creating a new task with a client-providedtaskIdis not supported. - If only
taskIdis provided, the agent MUST infer thecontextIdfrom the task. A mismatchingcontextIdandtaskIdMUST be rejected. - Providing only a
contextId(without ataskId) starts a new task within an existing conversation context. To supply requested input, the client sends a new message with the sametaskIdandcontextId.referenceTaskIdsexplicitly references related tasks.
On the division of labor between messages and artifacts: Message is for communication (starting a task, clarification, status notes, extra input), and task results SHOULD be returned as Artifact objects. Messages are not a reliable delivery mechanism, so clients should not rely on them for critical information.
Update delivery
| Mechanism | Best for | Precondition |
|---|---|---|
Polling (GetTask) | Simple integrations, infrequent updates, restricted networks | Supported by all bindings |
Streaming (SendStreamingMessage, SubscribeToTask) | Interactive applications, live progress | capabilities.streaming is true |
| Push notifications (webhook) | Server-to-server integrations, long-running tasks | capabilities.pushNotifications is true; regardless of the binding, webhooks use HTTP POST with the JSON payloads defined by the HTTP binding |
Events MUST be delivered in the order they were generated and must not be reordered. For a fuller discussion, see Streaming and Asynchronous Operations .
Capability validation
Optional capabilities declared by an agent are constraints, not suggestions:
- When
pushNotificationsisfalseor absent, the four push notification config operations MUST returnPushNotificationNotSupportedError. - When
streamingisfalseor absent,SendStreamingMessageandSubscribeToTaskMUST returnUnsupportedOperationError. - When
extendedAgentCardisfalseor absent,GetExtendedAgentCardMUST returnUnsupportedOperationError; if support is declared but no extended card is configured, it returnsExtendedAgentCardNotConfiguredError. - When the server requires an extension marked
required: trueand the client did not declare support for it, the agent returnsExtensionSupportRequiredError.
Clients SHOULD check the Agent Card before using operations that depend on optional capabilities.
Errors and error codes
Servers MUST return appropriate errors across the authentication, authorization, validation, resource, and system categories, and SHOULD provide actionable information. Authorization and resource errors MUST NOT reveal whether a resource the client cannot access exists. A2A defines nine specific errors with canonical mappings across the three bindings (triggers, ErrorInfo.reason values, and a per-operation matrix are in A2A Error Codes
):
| A2A error | JSON-RPC | gRPC | HTTP |
|---|---|---|---|
TaskNotFoundError | -32001 | NOT_FOUND | 404 |
TaskNotCancelableError | -32002 | FAILED_PRECONDITION | 400 |
PushNotificationNotSupportedError | -32003 | FAILED_PRECONDITION | 400 |
UnsupportedOperationError | -32004 | FAILED_PRECONDITION | 400 |
ContentTypeNotSupportedError | -32005 | INVALID_ARGUMENT | 400 |
InvalidAgentResponseError | -32006 | INTERNAL | 500 |
ExtendedAgentCardNotConfiguredError | -32007 | FAILED_PRECONDITION | 400 |
ExtensionSupportRequiredError | -32008 | FAILED_PRECONDITION | 400 |
VersionNotSupportedError | -32009 | FAILED_PRECONDITION | 400 |
HTTP error responses use the JSON representation of google.rpc.Status. Because several A2A errors map to the same HTTP status code, an A2A-specific error MUST carry a google.rpc.ErrorInfo in error.details: reason is the UPPER_SNAKE_CASE name without the Error suffix (for example TASK_NOT_FOUND), and domain is always a2a-protocol.org. Example:
{
"error": {
"code": 404,
"status": "NOT_FOUND",
"message": "The specified task ID does not exist or is not accessible",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "TASK_NOT_FOUND",
"domain": "a2a-protocol.org"
}
]
}
}Service parameters and version negotiation
Service parameters are horizontal context passed with a request. Keys are case-insensitive, values are case-sensitive, and the transmission mechanism is defined by the binding (HTTP headers for the HTTP-based bindings, metadata for gRPC). There are two standard parameters:
| Name | Description |
|---|---|
A2A-Version | The protocol version the client uses; the server returns VersionNotSupportedError if it is not supported |
A2A-Extensions | Comma-separated extension URIs the client wants to use for this request |
Versioning rules:
- The protocol version is identified only by
Major.Minor(for example1.0). Patch versions do not affect compatibility, SHOULD NOT appear in requests, responses, or Agent Cards, and play no part in version negotiation. - Clients MUST send
A2A-Versionwith each request (it MAY also be passed as a request parameter). For 0.3 clients, an empty value is interpreted as 0.3. - Servers MUST process requests with the semantics of the requested version, and return
VersionNotSupportedErrorif the interface does not support it. The same transport MAY expose interfaces of several versions under the same or different URLs. - A client that needs the latest features should request a specific version and avoid automatic fallback to older versions, so it does not silently lose functionality.
Request example:
GET /tasks/task-123 HTTP/1.1
Host: agent.example.com
A2A-Version: 1.0
Authorization: Bearer <token>
Accept: application/a2a+jsonJSON and data conventions
- JSON fields always use camelCase (snake_case in the proto; for example
context_idbecomescontextId). Enum values are serialized per ProtoJSON as the string names defined in the proto (such asTASK_STATE_INPUT_REQUIREDandROLE_USER). - Timestamps use ISO 8601 in UTC with a
Zsuffix and SHOULD carry milliseconds, for example2025-10-28T10:30:00.000Z. - Fields marked
REQUIREDMUST be present, and implementations SHOULD ignore unrecognized fields for forward compatibility. - Why ProtoJSON: the Technical Steering Committee accepted ADR-001 (2025-11-18), which makes ProtoJSON the normative way to serialize JSON from the proto definitions. The ADR records the trade-offs: enum values in SCREAMING_SNAKE_CASE (a breaking change for earlier JSON payloads), and no round-tripping of unknown fields, because ProtoJSON does not preserve them.
Related pages
- Data Structures : the objects and fields mentioned here.
- Agent Discovery and the Agent Card .
- Authentication, Authorization, and Security Considerations .
- Protocol Bindings in Detail : service parameters, errors, and streaming per binding.
- Common Workflows and Examples : end-to-end request and response examples.
- Life of a Task .
- What Changed in v1.0 and How to Migrate .
Source: A2A official specification