# Talk to Your Agent

> Send Revnu messages from code, wait for the reply inline or poll, hand over many jobs in a row without interrupting, and keep retries safe with a client request id.

Canonical: https://revnu.com/docs/talk-to-your-agent
Last updated: 2026-10-20

A message through the API does exactly what typing into the dashboard chat does. Revnu reads it, does the work with the same tools and Memory, and replies in one or more bubbles. Anything it wants approved lands in the [review queue](https://revnu.com/docs/review-list.md).

## One call, with the reply inline

Pass `waitSeconds` (up to 120) and the request stays open until the message is `done`: Revnu has replied or failed and any background research it started has been reported. Replies usually land in well under a minute. Real work, such as researching a list, can take longer.

```bash
curl -X POST -H "Authorization: Bearer $REVNU_API_TOKEN" \
  -H "content-type: application/json" \
  -d '{"text":"Which leads replied this week?","waitSeconds":90,"clientRequestId":"weekly-replies-2026-42"}' \
  https://revnu.com/api/v1/agent/messages
```

A `200` carries the finished `message` with its `replies`. If the wait runs out you get `202` with the last observed state and a `requestId` to keep polling.

## Or post and poll

Without `waitSeconds` the POST returns `202` immediately. Poll [`GET /agent/messages/{requestId}`](https://revnu.com/docs/agent-message-status.md) every few seconds. `status` moves `queued → running → replied`, or ends `failed` with a `failure` message.

Progress bubbles can arrive in `replies` while it is still `running`. `replied` means the turn is over. Long research can keep running after it as a background task, listed in `backgroundTasks`; `done` turns `true` once that result is reported too. The poll returns the newest bubbles.

> **Note:** Polling spends the agent-message limit, 30 calls a minute per token. Poll every 5 to 10 seconds rather than every second, or let `waitSeconds` do the waiting in one call.

## Safe retries

Pass `clientRequestId` (up to 128 characters of `A-Za-z0-9_.:-`). A retried POST with the same id returns the original `requestId` with `deduplicated: true` instead of sending a second message. Make the id from the job itself, such as `import-eu-fintech-2026-10-15`, so a crash and restart sends the same id.

A `failed` message should be re-sent with a new id. Reusing the old one returns the failed request.

## Interrupts

A new message stops whatever Revnu is still doing for this token and starts on the new one. That's right when you mean "stop, do this instead". It's wrong when a script fires jobs one after another. Two fields change it:

| Field | What happens while this token's last message is still queued or running |
|---|---|
| none (default) | The new message is sent and the running work stops. The old message is marked `interrupted: true`. |
| `"interrupt": false` | Nothing is sent. The response names the unfinished request with `notSent: true`. |
| `"queue": true` | The new message is sent and waits; Revnu starts it once the current work is done. |

`queue` and `interrupt` can't be combined. The MCP tool `ask_revnu` defaults to `interrupt: false`, so an assistant can't stop work by accident. The CLI's `revnu agent message` sends with the default, and takes `--queue`.

## Many jobs in a row

To hand over several jobs, such as one list of companies per market, send each with `queue: true` and its own `clientRequestId`:

```ts
const jobs = [
  { id: "markets-2026-10-15-uk", text: "Find 20 UK fintechs with 50 to 200 staff that sell to SMBs." },
  { id: "markets-2026-10-15-de", text: "Find 20 German fintechs with 50 to 200 staff that sell to SMBs." },
];
for (const job of jobs) {
  const res = await fetch("https://revnu.com/api/v1/agent/messages", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.REVNU_API_TOKEN}`, "content-type": "application/json" },
    body: JSON.stringify({ text: job.text, clientRequestId: job.id, queue: true }),
  });
  const { requestId } = await res.json();
  saveRequestId(job.id, requestId); // poll each later
}
```

Each job runs to the end before the next starts. A queued message waits up to six hours behind earlier work, then counts as `failed`, so don't queue a day's worth at once.

> **Tip:** Put a whole list in one message where you can. A single message holds up to 4,000 characters.

### A worked rate example

Say you have 40 jobs. The agent-message limit is 30 calls a minute per token, and sending a message, polling a message and reading the thread all spend it. [`GET /agent/status`](https://revnu.com/docs/agent-status.md) is a read and spends the separate read limit of 300 a minute.

### 1. Send the jobs at 20 a minute

The 40 jobs go out over two minutes. That leaves 10 message calls a minute spare.

### 2. Watch the account status

While they run, poll `GET /agent/status` every 10 seconds. That's 6 reads a minute and touches nothing in the message budget.

### 3. Check each job

Read [`GET /agent/messages/{requestId}`](https://revnu.com/docs/agent-message-status.md) for each job every minute or so, oldest first. Stop polling a job once `done` is `true`.

The jobs run one after another, so the batch takes as long as all 40 together. If each takes about five minutes, the last starts more than three hours after the first. Anything still waiting after six hours fails, so split a bigger batch across the day, or put several markets in one message.

### Keep research jobs from sending anything

A message can't promise "research only". Whether Revnu's work goes out depends on **What Needs Your Approval** in **Settings > Agent**.

To be sure a batch of research jobs only produces leads and drafts, set **Start Sequences**, **One-Off Emails**, **Connection Requests** and **Messages** to **Ask Me First** before you send the batch. Drafts then wait as cards in the [review queue](https://revnu.com/docs/review-list.md) until someone approves them.

> **Warning:** These settings don't recall a sequence that is already live: its later steps keep sending. To stop that too, see [Pause or Stop Everything](https://revnu.com/docs/pause-revnu.md).

To check whether Revnu is busy with anything on the account, including chat, Slack and scheduled work, read [`GET /agent/status`](https://revnu.com/docs/agent-status.md): `running` is `true` while a turn is in progress.

## Each token is its own conversation

Your dashboard and Slack threads are not visible through the API, and API messages do not appear in them. [`GET /agent/thread`](https://revnu.com/docs/agent-thread.md) returns this token's conversation, newest first. Revnu sees each message as coming from `API token "<label>"`, so give a bot or coding agent its own token and Revnu can tell it apart from you.

## Status questions without side effects

A message is a request for work. Telling Revnu "status only, don't change anything" is an instruction it follows, not a permission it can't break. For a status bot, read the numbers directly, with a token that holds only read scopes:

| Question | Read |
|---|---|
| Is LinkedIn paused, and until when? | [`GET /results`](https://revnu.com/docs/results.md): `linkedin.data.health.pausedUntil` and `pauseReason` |
| Did a blog post fail? | `GET /results`: `seo.data.postsFailed` |
| What is waiting for approval? | [`GET /review`](https://revnu.com/docs/review-list.md) |
| Is Revnu working right now? | [`GET /agent/status`](https://revnu.com/docs/agent-status.md) |
| What did a workflow run do? | [`GET /workflows/{id}/runs`](https://revnu.com/docs/workflow-runs.md) |

Some answers only Revnu can give. There is no endpoint for how a sending inbox's warm-up is going or when it will start sending, and none for why a post failed. Ask Revnu with a message, which needs `agent:message`:

```bash
curl -X POST -H "Authorization: Bearer $REVNU_QUESTIONS_TOKEN" \
  -H "content-type: application/json" \
  -d '{"text":"Are my sending inboxes ready to send yet? Which are still warming up?","waitSeconds":90,"interrupt":false}' \
  https://revnu.com/api/v1/agent/messages
```

`interrupt: false` means a question never stops a job this token started. If one is still running, nothing is sent and the response says `notSent: true`. The message is still a request Revnu can act on, so keep it to a question and use a separate token for it. [A status bot that can also explain](https://revnu.com/docs/authentication.md#a-status-bot-that-can-also-explain) has the full setup.

## Frequently asked questions

### Can Revnu do work from an API message, not just answer?

Yes. It is the same Revnu with the same tools. Ask it to draft outreach and the draft lands in the review queue like any other. Whether it then sends on its own follows your approval settings.

### How do I send several jobs without each one stopping the last?

Send each with `"queue": true` and its own `clientRequestId`. Revnu starts each one when the one before has finished.

### How do I stop an API job from sending emails?

Set the sending kinds of work to Ask Me First in Settings → Agent, under What Needs Your Approval. Words in the message, such as "don't send anything", are an instruction Revnu follows, not a lock. The setting is the lock.

### Is POST /agent/messages idempotent?

Yes, with `clientRequestId`. The same id from the same token returns the original `requestId` and `deduplicated: true`, and nothing is sent twice.

### Is there an API endpoint for inbox warm-up progress?

Warm-up progress comes through a message. Ask Revnu: > Are my sending inboxes ready to send yet? Then read the reply. In the dashboard, the account menu at the top of **Inbox** shows **Warming up** next to inboxes that aren't ready.

### How do I know Revnu is even up?

`GET /agent/status` reports the sandbox state, whether a turn is running, and the next scheduled wake.

### Why did my message come back failed?

Read `failure` for the reason. A queued message also fails after six hours waiting behind other work, and `interrupted: true` means a later message stopped it. Re-send it with a new `clientRequestId`.
