> ## Documentation Index
> Fetch the complete documentation index at: https://docs.corti.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Send a message to an agent

> Learn how to send a message using the A2A HTTP+JSON binding, handle task and message responses, and manage context.

This guide shows you how to send a message to an agent and handle the response. You will learn about blocking vs. non-blocking requests, context management, and error handling.

## Prerequisites

* An existing agent (see [Create an agent](/agentic/guides/create-agent))
* An access token or client credentials
* Your tenant name

## Send a message

Use the HTTP+JSON binding to send a message:

```bash theme={null}
# Replace these with your values
AGENT_ID="<your-agent-id>"
ENVIRONMENT="<eu-or-us>"
TENANT="<your-tenant-name>"
TOKEN="<your-access-token>"

curl -X POST "https://api.${ENVIRONMENT}.corti.app/v2/agentic/agents/${AGENT_ID}/a2a/message:send" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Tenant-Name: ${TENANT}" \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 1.0" \
  -d '{
    "message": {
      "role": "ROLE_USER",
      "parts": [{ "text": "What is the ICD-10 code for asthma?" }]
    }
  }'
```

## Message structure

A message contains:

| Field              | Required | Description                                                |
| ------------------ | -------- | ---------------------------------------------------------- |
| `role`             | yes      | `ROLE_USER` or `ROLE_AGENT`                                |
| `parts`            | yes      | Ordered content parts (text, file, or data)                |
| `messageId`        | no       | Message identifier (UUID); server generates one if omitted |
| `contextId`        | no       | Context ID for conversation continuity                     |
| `referenceTaskIds` | no       | Task IDs this message references                           |
| `extensions`       | no       | URIs of A2A extensions                                     |
| `metadata`         | no       | Free-form metadata                                         |

The request body also accepts an optional `configuration` object:

| Field                 | Default | Description                                                                                                                            |
| --------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `returnImmediately`   | `false` | If `true`, return as soon as the task is submitted. If `false` (default), wait until the task reaches a terminal or interrupted state. |
| `historyLength`       | unset   | Cap the number of history messages returned per task                                                                                   |
| `acceptedOutputModes` | unset   | Output media types the client accepts                                                                                                  |

## Blocking vs. non-blocking

By default, `message:send` is blocking: the server waits for the task to complete before returning. Set `configuration.returnImmediately` to `true` to return as soon as the task is submitted:

```bash theme={null}
curl -X POST "https://api.${ENVIRONMENT}.corti.app/v2/agentic/agents/${AGENT_ID}/a2a/message:send" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Tenant-Name: ${TENANT}" \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 1.0" \
  -d '{
    "message": {
      "role": "ROLE_USER",
      "parts": [{ "text": "Generate a full clinical note for this encounter." }]
    },
    "configuration": {
      "returnImmediately": true
    }
  }'
```

With `returnImmediately: true`, the response returns immediately with the task in `TASK_STATE_SUBMITTED` or `TASK_STATE_WORKING` state. Poll the task endpoint or [subscribe via SSE](/agentic/guides/stream-responses) to get updates.

## Handling the response

The response contains either a `task` or a `message` object:

* **`task`**: The agent is performing long-running work. Check `task.status.state` for the current state. When `TASK_STATE_COMPLETED`, the agent's response is in `task.history` (the last `ROLE_AGENT` message). Artifacts are in `task.artifacts`.
* **`message`**: The agent responded directly with a message. The text is in `message.parts[0].text`.

```json theme={null}
{
  "task": {
    "id": "task.0192f4c8-...",
    "contextId": "ctx.0192f4c8-...",
    "status": {
      "state": "TASK_STATE_COMPLETED",
      "timestamp": "2026-05-19T12:00:01Z"
    },
    "history": [
      {"role": "ROLE_USER", "messageId": "msg.0192f4c8-...", "parts": [{"text": "What is the ICD-10 code for asthma?"}]},
      {"role": "ROLE_AGENT", "messageId": "msg.0192f4c8-...", "parts": [{"text": "J45.909"}]}
    ]
  }
}
```

## Context management

The server automatically creates a context if you don't provide a `contextId`. The response includes the `contextId` in the task object. To continue a conversation, include that `contextId` in subsequent messages:

```bash theme={null}
CONTEXT_ID="ctx.0192f4c8-..."

curl -X POST "https://api.${ENVIRONMENT}.corti.app/v2/agentic/agents/${AGENT_ID}/a2a/message:send" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Tenant-Name: ${TENANT}" \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 1.0" \
  -d '{
    "message": {
      "role": "ROLE_USER",
      "parts": [{ "text": "What about the code for acute exacerbation?" }],
      "contextId": "'"$CONTEXT_ID"'"
    }
  }'
```

See [Context and memory](/agentic/context-memory) for details on how context works.

## Using data parts for structured context

Pass structured data alongside text using data parts:

```bash theme={null}
curl -X POST "https://api.${ENVIRONMENT}.corti.app/v2/agentic/agents/${AGENT_ID}/a2a/message:send" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Tenant-Name: ${TENANT}" \
  -H "Content-Type: application/json" \
  -H "A2A-Version: 1.0" \
  -d '{
    "message": {
      "role": "ROLE_USER",
      "parts": [
        { "text": "Code this encounter:" },
        { "data": {
            "chiefComplaint": "Acute asthma exacerbation",
            "patientAge": 45,
            "vitalSigns": {"heartRate": 110, "respiratoryRate": 28}
          }
        }
      ]
    }
  }'
```

## Error handling

Errors follow the A2A `google.rpc.Status` error format:

```json theme={null}
{
  "error": {
    "code": 400,
    "status": "INVALID_ARGUMENT",
    "message": "Message must include at least one part.",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_REQUEST",
        "domain": "a2a-protocol.org",
        "metadata": {
          "timestamp": "2026-05-19T12:00:00Z"
        }
      }
    ]
  }
}
```

Common error codes:

| HTTP status | `status`           | Description                             |
| ----------- | ------------------ | --------------------------------------- |
| 400         | `INVALID_ARGUMENT` | Invalid request (malformed message)     |
| 401         | `UNAUTHENTICATED`  | Unauthorized (missing or invalid token) |
| 404         | `NOT_FOUND`        | Agent not found                         |

## Next steps

* Learn how to [stream responses](/agentic/guides/stream-responses) via SSE
* Understand the [task lifecycle](/agentic/task-lifecycle) for long-running work
* Read about [contexts](/agentic/guides/work-with-contexts) for conversation management
