---
title: Send a message
description: POST /api/developer/chat/messages — send a message to an agent and read its reply.
---

```text
POST /api/developer/chat/messages
```

Sends one message into an existing session and returns the agent's reply. Create
the session first with [Create a chat session](./chat-sessions.md).

## Request

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `agentId` | string | Yes | The agent to talk to. |
| `sessionId` | string | Yes | The session returned when you created the conversation. |
| `message` | string | Yes | What the user said. |
| `variableValues` | object | No | Values for the agent's variables. See below. |

```bash
curl --request POST "https://api.chatley.ai/api/developer/chat/messages" \
  --header "Authorization: Bearer $CHATLEY_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "agentId": "YOUR_AGENT_ID",
    "sessionId": "YOUR_SESSION_ID",
    "message": "What appointment times are available?"
  }'
```

## Agent variables

If your agent's instructions reference variables, pass their values with the
message:

```json
{
  "agentId": "YOUR_AGENT_ID",
  "sessionId": "YOUR_SESSION_ID",
  "message": "Hello",
  "variableValues": {
    "customerName": "Jane Doe",
    "planTier": "Pro"
  }
}
```

This is how you hand the agent what your application already knows — the signed-in
customer's name, their plan, an order number — so it does not have to ask.

## Response

`200 OK`

```json
{
  "success": true,
  "data": {
    "chatId": "chat-id",
    "sessionId": "YOUR_SESSION_ID",
    "response": "We have Tuesday at 10am or Thursday at 2pm. Which suits you?",
    "isSession": true,
    "createdAt": "2026-07-03T12:34:56.000Z",
    "updatedAt": "2026-07-03T12:34:57.000Z"
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `response` | string | The agent's reply. This is the field to show your user. |
| `chatId` | string | Identifies this single exchange. |
| `sessionId` | string | The session the message belongs to, echoed back. |
| `isSession` | boolean | Always `true` for this endpoint. |
| `createdAt` / `updatedAt` | string | ISO 8601 timestamps for the exchange. |

The response also carries the conversation so far and the cost of the exchange,
which is useful if you want to render the full transcript rather than track it
yourself. Read `response` for the reply and treat the rest as additive — build
against the fields documented above.

## Errors

| Status | `error` | What to do |
| --- | --- | --- |
| 400 | `Agent ID, message, and session ID are required` | All three fields must be present and non-empty. |
| 400 | `Agent does not have chat enabled` | Open the agent in Chatley and turn chat on. |
| 404 | `Agent not found` | The ID does not match an agent on your account. |
| 401 / 403 | see [Authentication](./authentication.md#error-responses) | Fix the API key or its type. |
| 500 | `Internal server error` | Retry. If it persists, contact support. |

As with sessions, a failure from the underlying chat service comes back as
`Chat provider error` carrying that service's status code — retry `429` and
`5xx` with backoff.

## Holding a conversation

```text
POST /chat/sessions   → sessionId
POST /chat/messages   → reply    (same sessionId)
POST /chat/messages   → reply    (same sessionId)
```

Send each user turn as its own request with the same `sessionId`. The agent
already has the earlier turns — do not replay the transcript in `message`.
