A2A Protocol
How to call Claix with A2A
Endpoint
https://claix.dev/a2aClaix is an Agent-to-Agent (A2A) agent. Another agent, an orchestrator, or a script sends a JSON-RPC 2.0 message, and Claix replies with a task: extract a document, list schemas, ask a persisted document, and so on.
You do not need MCP, and you do not need to rewrite REST calls. Use the same API key. The flow is always: discover the agent, authenticate, send message/send, then read the result on the task.
1. Discover the agent
Before you send work, fetch the Agent Card. It is public JSON (no API key) that says who Claix is, where to POST, and which skills exist.
| Method | URL | What it is for |
|---|---|---|
| GET | /.well-known/agent.json | Agent Card. No authentication. |
| GET | /.well-known/agent-card.json | The same card (alternate path). |
| POST | /a2a | Every JSON-RPC call. Requires an API key. |
Fetch the card:
curl -sS "https://claix.dev/.well-known/agent.json"
It is also at https://claix.dev/.well-known/agent-card.json. In the JSON, look at:
url/supportedInterfaces: the URL you mustPOSTto (https://claix.dev/a2a).skills: the skill list. Each entry has anid, name, description, and payload examples.capabilities.pushNotifications:true. Long tasks notify a webhook; there is no SSE streaming.
If you use an A2A client or inspector, point it at the site origin https://claix.dev (not at /a2a) so it can resolve the card under /.well-known/ on its own.
2. Authentication
Every POST /a2a uses the same API key as the rest of Claix. The Agent Card does not.
Recommended:
x-api-key: <YOUR_API_KEY>
Alternative:
Authorization: Bearer <YOUR_API_KEY>
Either header is enough. Missing or invalid key: HTTP 401 and JSON-RPC -32001. Limit: 60 requests per minute per API key (HTTP 429, Retry-After header).
3. Anatomy of a call
Every operation hits the same place: POST https://claix.dev/a2a, Content-Type: application/json. The body is a JSON-RPC 2.0 envelope:
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": { }
}
}Envelope fields:
| Field | What to send |
|---|---|
| jsonrpc | Always "2.0". |
| id | Your request id (number or string). We echo it on the response so you can correlate. |
| method | To create work: "message/send". |
| params.message | The A2A message (next table). |
Inside params.message:
| Field | Required | What to send |
|---|---|---|
| role | Yes | "user". |
| messageId | Yes | A unique id for this message (you choose it). |
| kind | Yes | "message". |
| parts | Yes | Array with at least one part: a DataPart (JSON) or a TextPart (text). |
| contextId | No | Thread id. Reuse it on later messages in the same dialogue. |
There are two ways to ask for work. If you already know the skill and its parameters, send a DataPart. If you only have a natural-language instruction, send a TextPart.
4. Structured call (DataPart)
This is the most predictable path. Send a part with kind: "data" and a JSON object that includes "skill" (the id from the Agent Card) plus the fields that skill expects.
Minimal example — list schemas:
curl -X POST "https://claix.dev/a2a" \
-H "Content-Type: application/json" \
-H "x-api-key: <YOUR_API_KEY>" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-list-schemas",
"kind": "message",
"parts": [
{ "kind": "data", "data": { "skill": "list-schemas" } }
]
}
}
}'Example with a file — extract a PDF. A2A has no multipart: send the file as file_base64 (Base64 or a data URL) or file_path (a public https URL).
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-extract-pdf",
"kind": "message",
"parts": [
{
"kind": "data",
"data": {
"skill": "extract-pdf",
"schema_id": "<your-schema-uuid>",
"file_base64": "JVBERi0xLjQK..."
}
}
]
}
}
}If a value you can still supply is missing (for example the schema or the file), the task stays in input-required instead of failing. Send another message/send on the same contextId with the missing field. If the skill id does not exist or a parameter has an invalid format, you get JSON-RPC -32602 (Invalid params) and no task is created.
5. Natural-language call (TextPart)
If you do not have typed parameters yet, send text. Claix interprets the request, picks the skill, and fills in the arguments.
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-nl",
"kind": "message",
"parts": [
{
"kind": "text",
"text": "List my schemas and tell me which one to use for PDF invoices."
}
]
}
}
}Use this to explore, or for agents that speak in natural language. Once you know the skill and its fields, prefer a DataPart: it is more stable and does not depend on how the sentence is phrased.
6. How to read the response
A successful call does not put the business JSON at the root. result is an A2A Task. The useful payload is in artifacts.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "<taskId>",
"contextId": "<contextId>",
"status": { "state": "completed" },
"artifacts": [
{
"name": "list-schemas-result",
"parts": [
{
"kind": "data",
"data": { "success": true, "schemas": [] }
}
]
}
]
}
}Store result.id (the task) and result.contextId (the thread). Then read result.status.state:
| state | What it means | What to do |
|---|---|---|
| completed | Finished in this response. | Read artifacts[].parts[].data. |
| working | Still running (long tasks: extractions, Agent mode, query-space…). | Do not drop the thread. Wait for the push webhook or poll with tasks/get. |
| input-required | A value you can supply is missing. | Send message/send again with the requested field, same contextId. |
| failed | The operation could not complete. | Read the status message / error artifact. |
| canceled | You canceled the task. | Nothing else; create a new one if needed. |
To look up a task that already exists:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tasks/get",
"params": { "id": "<taskId>" }
}To cancel it: method: "tasks/cancel" with the same params.id.
7. Protocol errors
If the JSON-RPC envelope or authentication fails, there is no Task. You get error:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "Invalid params: schema_id — …"
}
}| HTTP | code | When |
|---|---|---|
| 401 | -32001 | The API key is missing or invalid. |
| 429 | -32000 | More than 60 requests/minute. See Retry-After. |
| 400 | -32602 | Unknown skill or a parameter with an invalid format. |
8. Long tasks and push
Extracting a PDF, using Agent mode, or querying a space with many documents does not wait on the HTTP connection. The first response often arrives with status.state: "working". Do not use SSE: streaming is off.
Register an A2A webhook to receive the final Task (completed or failed) with the artifact. You can send it with the message:
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-extract-pdf",
"kind": "message",
"parts": [
{
"kind": "data",
"data": {
"skill": "extract-pdf",
"schema_id": "<uuid>",
"file_base64": "JVBERi0xLjQK..."
}
}
]
},
"configuration": {
"pushNotificationConfig": {
"url": "https://your-agent.example/a2a/push",
"token": "optional-token-to-authenticate-the-webhook"
}
}
}
}Or register it later, once you have the taskId:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tasks/pushNotificationConfig/set",
"params": {
"id": "<taskId>",
"pushNotificationConfig": {
"url": "https://your-agent.example/a2a/push"
}
}
}Claix will POST the Task to that URL when it finishes. Your endpoint must accept the A2A notification payload.
9. How to keep the thread
Every Task includes a contextId. That is the dialogue id between your agent and Claix. If you omit the field, Claix assigns a new one. If you reuse it on the next message/send, you continue the same conversation (for example: list schemas → extract with the schema_id just returned).
{
"jsonrpc": "2.0",
"id": 4,
"method": "message/send",
"params": {
"message": {
"role": "user",
"messageId": "msg-follow-up",
"contextId": "the-same-contextId-as-before",
"kind": "message",
"parts": [
{
"kind": "text",
"text": "Use that schema and extract the PDF I am sending now."
}
]
}
}
}A new contextId starts a new conversation. The same value keeps the same thread. Do not share it across accounts or unrelated agents.
10. Available skills
A DataPart must include "skill": "<id>". The ids and a short summary come from the Agent Card; this table is the same list:
| Skill | What it does |
|---|---|
| extract-excel | Convert Excel or CSV to JSON using a schema |
| convert-json-to-excel | Convert JSON documents into an Excel file |
| extract-pdf | Extract structured data from a PDF using a schema |
| extract-doc | Extract structured data from a text document using a schema |
| extract-img | Extract structured data from an image using a schema |
| extract-txt | Extract structured data from plain text, HTML, or XML |
| get-document | Return the raw content of a persisted document |
| query-document | Answer questions about a persisted document |
| query-space | Answer questions across every document in a knowledge space |
| create-space | Create a knowledge space on the API key account |
| delete-space | Delete a knowledge space |
| delete-document | Delete a persisted document |
| agent-extract-excel | Excel/CSV to JSON with Agent mode reasoning |
| agent-extract-pdf | PDF to JSON with Agent mode reasoning |
| agent-extract-doc | Document to JSON with Agent mode reasoning |
| agent-extract-img | Image to JSON with Agent mode reasoning |
| agent-extract-txt | Text/HTML/XML to JSON with Agent mode reasoning |
| list-schemas | List every schema on the API key account |
| create-schema | Create a schema on the API key account |
| delete-schema | Delete a schema on the API key account |
Concrete JSON fields for each skill are in the Agent Card, under skills[].examples.
11. JSON-RPC methods and clients
| Method | Use |
|---|---|
| message/send | Create or continue a task. |
| tasks/get | Read the status and artifacts of a task. |
| tasks/cancel | Cancel a running task. |
| tasks/pushNotificationConfig/set | Register the webhook for a long-running task result. |
There is no message/stream. Long tasks do not keep the HTTP connection open.
- TypeScript SDK:
@a2a-js/sdk - Inspector: a2aproject/a2a-inspector against
https://claix.dev - Any A2A 0.3 / 1.0 JSON-RPC client with push notifications
MCP remains at https://claix.dev/mcp. REST remains on the API routes. They are separate interfaces; pick one per integration.