# Send a message

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

Canonical: https://revnu.com/docs/agent-messages
Last updated: 2026-10-20

```bash
curl -X POST -H "Authorization: Bearer $REVNU_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"text":"What did we ship this week?","waitSeconds":90,"clientRequestId":"weekly-1"}' \
  https://revnu.com/api/v1/agent/messages
```

## Body

| Field | Type | Meaning |
|---|---|---|
| `text` | string, required | Up to 4,000 characters. See [Message length](#message-length). |
| `clientRequestId` | string | Up to 128 characters of `A-Za-z0-9_.:-`. A retry with the same id returns the original `requestId`. Never reuse an id after a `failed` message; send again with a new one. |
| `waitSeconds` | integer, 0 to 120 | Hold the request until the message is `done`: the agent replied or failed and any background research it started was reported. |
| `interrupt` | boolean, default `true` | A new message stops the agent's running turn. Send `false` to leave unfinished work alone: while this token's newest message is still queued or running, nothing is sent and the response names that request with `notSent: true`. |
| `queue` | boolean, default `false` | Send `true` to hand over another job without stopping the running one: the message is sent and the agent starts it once its current work is done. Use it when your software sends several jobs in a row, such as one list of companies per market. It stays `queued` for up to six hours while earlier work runs, then counts as `failed`. Cannot be combined with `interrupt`. |

## Message length

Two limits apply to `text`, checked in this order:

1. **8,000 bytes, checked first: `400`.** UTF-8 bytes, not characters. English is one byte a character, so this never bites before the second limit. Chinese, Japanese and Korean use three bytes a character, so a message of about 2,700 of those characters is rejected here.
2. **4,000 characters: `409` with `error: "rejected"`.** The same limit as the dashboard chat. Characters are counted as JavaScript counts them, so an emoji counts as two.

To stay clear of both, keep each message under 4,000 characters and, for non-Latin text, under about 2,600 characters. Split a longer list across several messages sent with `queue: true`.

## Responses

| Code | Meaning |
|---|---|
| 202 | `{ requestId, deduplicated, notSent?, message? }`. Queued; poll [the message](https://revnu.com/docs/agent-message-status.md). 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.

## Frequently asked questions

### How do I send many jobs in a row?

Send each with `queue: true` and its own `clientRequestId`. Each runs after the one before finishes, and a retry of any of them is not sent twice. See [Talk to Your Agent](https://revnu.com/docs/talk-to-your-agent.md#many-jobs-in-a-row).

### Does a new message stop the one Revnu is working on?

Yes, by default. Send `interrupt: false` to send nothing while this token's last message is unfinished, or `queue: true` to send it to wait its turn. The MCP tool `ask_revnu` defaults to `interrupt: false`.

### Why did a long message get a 400 instead of a 409?

The 8,000-byte check runs first. Text in Chinese, Japanese, Korean and other scripts takes several bytes a character, so it hits 8,000 bytes before 4,000 characters. Split it into shorter messages.

### Which scope does this need?

`agent:message`. A token without it gets `403` with `requiredScope` in the body. `GET /me` shows a token's scopes.

### Are responses cached?

No. Every response is `Cache-Control: no-store`, so what you read is current.
