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:

  1. Canonical data model (Layer 1): objects such as Task, Message, AgentCard, Part, and Artifact, defined in Protocol Buffers and independent of any protocol.
  2. 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.
  3. 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):

FunctionalityJSON-RPC methodgRPC methodHTTP+JSON endpoint
Send messageSendMessageSendMessagePOST /message:send
Send streaming messageSendStreamingMessageSendStreamingMessagePOST /message:stream
Get taskGetTaskGetTaskGET /tasks/{id}
List tasksListTasksListTasksGET /tasks
Cancel taskCancelTaskCancelTaskPOST /tasks/{id}:cancel
Subscribe to taskSubscribeToTaskSubscribeToTaskPOST /tasks/{id}:subscribe
Create push notification configCreateTaskPushNotificationConfigCreateTaskPushNotificationConfigPOST /tasks/{id}/pushNotificationConfigs
Get push notification configGetTaskPushNotificationConfigGetTaskPushNotificationConfigGET /tasks/{id}/pushNotificationConfigs/{configId}
List push notification configsListTaskPushNotificationConfigsListTaskPushNotificationConfigsGET /tasks/{id}/pushNotificationConfigs
Delete push notification configDeleteTaskPushNotificationConfigDeleteTaskPushNotificationConfigDELETE /tasks/{id}/pushNotificationConfigs/{configId}
Get extended Agent CardGetExtendedAgentCardGetExtendedAgentCardGET /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 Task to process the message asynchronously, or MAY return a direct Message (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 a Task, the stream begins with the Task, followed by zero or more TaskStatusUpdateEvent or TaskArtifactUpdateEvent objects, and closes when the task reaches a terminal state.
  • Blocking and non-blocking: SendMessageConfiguration.return_immediately defaults to false, 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 to true, the operation returns right after creating the task, and the caller follows up with GetTask, SubscribeToTask, or push notifications. The field has no effect when a direct Message is 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 historyLength means no limit (the server decides the default amount); 0 means no history (the history field SHOULD be omitted); a value greater than 0 returns at most that many of the most recent messages.
  • ListTasks uses cursor-based pagination (pageToken/nextPageToken), returns tasks in descending order of status timestamp, and returns only tasks visible to the calling client. pageSize defaults to at most 50 and ranges from 1 to 100. includeArtifacts defaults to false, in which case each task in the response MUST omit the artifacts field entirely. nextPageToken MUST 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 Task object with the task’s current state, which prevents information loss between GetTask and 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 Task and Message objects. When an agent generates a new contextId, it MUST return it in the response. If it cannot accept a client-provided contextId, it MUST reject the request and MUST NOT generate a different one for the response. Clients SHOULD NOT invent a contextId unless 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 returns TaskNotFoundError. Creating a new task with a client-provided taskId is not supported.
  • If only taskId is provided, the agent MUST infer the contextId from the task. A mismatching contextId and taskId MUST be rejected.
  • Providing only a contextId (without a taskId) starts a new task within an existing conversation context. To supply requested input, the client sends a new message with the same taskId and contextId. referenceTaskIds explicitly 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

MechanismBest forPrecondition
Polling (GetTask)Simple integrations, infrequent updates, restricted networksSupported by all bindings
Streaming (SendStreamingMessage, SubscribeToTask)Interactive applications, live progresscapabilities.streaming is true
Push notifications (webhook)Server-to-server integrations, long-running taskscapabilities.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 pushNotifications is false or absent, the four push notification config operations MUST return PushNotificationNotSupportedError.
  • When streaming is false or absent, SendStreamingMessage and SubscribeToTask MUST return UnsupportedOperationError.
  • When extendedAgentCard is false or absent, GetExtendedAgentCard MUST return UnsupportedOperationError; if support is declared but no extended card is configured, it returns ExtendedAgentCardNotConfiguredError.
  • When the server requires an extension marked required: true and the client did not declare support for it, the agent returns ExtensionSupportRequiredError.

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 errorJSON-RPCgRPCHTTP
TaskNotFoundError-32001NOT_FOUND404
TaskNotCancelableError-32002FAILED_PRECONDITION400
PushNotificationNotSupportedError-32003FAILED_PRECONDITION400
UnsupportedOperationError-32004FAILED_PRECONDITION400
ContentTypeNotSupportedError-32005INVALID_ARGUMENT400
InvalidAgentResponseError-32006INTERNAL500
ExtendedAgentCardNotConfiguredError-32007FAILED_PRECONDITION400
ExtensionSupportRequiredError-32008FAILED_PRECONDITION400
VersionNotSupportedError-32009FAILED_PRECONDITION400

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:

NameDescription
A2A-VersionThe protocol version the client uses; the server returns VersionNotSupportedError if it is not supported
A2A-ExtensionsComma-separated extension URIs the client wants to use for this request

Versioning rules:

  • The protocol version is identified only by Major.Minor (for example 1.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-Version with 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 VersionNotSupportedError if 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+json

JSON and data conventions

  • JSON fields always use camelCase (snake_case in the proto; for example context_id becomes contextId). Enum values are serialized per ProtoJSON as the string names defined in the proto (such as TASK_STATE_INPUT_REQUIRED and ROLE_USER).
  • Timestamps use ISO 8601 in UTC with a Z suffix and SHOULD carry milliseconds, for example 2025-10-28T10:30:00.000Z.
  • Fields marked REQUIRED MUST 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

Source: A2A official specification