---
title: "Send a message"
method: POST
path: "/api/v1/agent/messages"
tags: ["API Reference"]
---

# Send a message

`POST /api/v1/agent/messages`

## Request

- Base URL: `https://revnu.com`
- URL: `https://revnu.com/api/v1/agent/messages`
- Auth: HTTP bearer

Message your agent exactly as the dashboard chat does, and optionally hold the request open for the reply.

Requires the `agent:message` scope.

**Response.** | Code | Meaning |
|---|---|
| 202 | `{ requestId, deduplicated, notSent?, message? }`. Queued; poll [the message](/docs/agent-message-status). With `waitSeconds`, `message` is the last state seen, and `waitEnded` (`unauthorized` or `poll_failed`) says when the wait stopped early. An `unauthorized` stop carries no `message`. |
| 200 | Only with `waitSeconds`: `message` is terminal and `replies` is filled. |
| 400 | Missing or empty `text`, `text` over 8,000 bytes, a non-string client id, a non-boolean `interrupt` or `queue`, `queue` together with `interrupt`, or a `waitSeconds` outside 0 to 120. |
| 409 | `rejected` with a `message`: `text` over 4,000 characters, a client id with characters outside `A-Za-z0-9_.:-`, or an account that can't take work right now (a trial waiting for a card, or paused for payment). |

With `interrupt: false` and an unfinished earlier message, either code can carry `notSent: true`: `requestId` and `message` are then the earlier request's, and nothing new was sent.

## Request body

- object

## Response `200`

Only with waitSeconds: message is terminal and replies is filled.

- object
  - `message` object, nullable, required
    - `interrupted` boolean
    - `failure` string
    - `requestId` string, required
    - `status` 'failed' | 'queued' | 'replied' | 'running', required
    - `done` boolean, required
    - `text` string, required
    - `sentAt` number, required
    - `replies` object[], required
      - `text` string, required
      - `at` number, required
    - `backgroundTasks` BackgroundTask[], required
      - `id` string, required
      - `label` string, nullable, required
      - `state` 'done' | 'failed' | 'running' | 'stopped', required
      - `startedAt` number, required
      - `endedAt` number
  - `requestId` string, required
  - `deduplicated` boolean, required
  - `notSent` boolean

## Other responses

- `202`: { requestId, deduplicated, notSent?, message? }. Queued; poll the message. With waitSeconds, message is the last state seen, and waitEnded (unauthorized or poll_failed) says when the wait stopped early. An unauthorized stop carries no message.
- `400`: Missing or empty text, text over 8,000 bytes, a non-string client id, a non-boolean interrupt or queue, queue together with interrupt, or a waitSeconds outside 0 to 120.
- `401`: Missing, malformed, unknown or revoked token.
- `402`: `setup_pending`: the account hasn't started its trial. Finish setup with `GET /setup`.
- `403`: The token lacks the scope in `requiredScope`.
- `409`: rejected with a message: text over 4,000 characters, a client id with characters outside A-Za-z0-9_.:-, or an account that can't take work right now (a trial waiting for a card, or paused for payment).
- `429`: Rate limited.
- `503`: Temporarily unavailable; retry the same call.

---

[API](https://skmtc.dev/revnu/apis/revnu-api.md) · [All operations](https://skmtc.dev/revnu/apis/revnu-api/llms.txt) · [OpenAPI document](https://skmtc.dev/revnu/apis/revnu-api/revisions/52e523c2db61?raw)
