# send_message

Source: https://modulify.ai/docs/api/chat/send-message

Sends a prompt to the agent that builds a site, starting a generation at once or adding it to the queue when the site is busy.

- Title: Send a message to a site
- Scope: `chat:write`
- Access: Makes changes
- Endpoint: `POST /v1/send_message`

Every message spends AI credits from the workspace that owns the site, so batch your instructions into one clear prompt rather than many small corrections. Use it for every instruction to the site agent, including answering a question the agent asked and approving or changing a plan. A `402` means the workspace has no AI credits left.

When the site is free, the generation starts at once and the response carries `queued:false` and a `jobId`. Poll `get_job` with that `jobId` until its `state` is no longer `running`.

Only one generation runs per site at a time, and this tool never fails because of that. When a generation is already running, or the last one was stopped, failed or ended part way through, the message is queued instead. The response then carries `queued:true`, the entry's `queueItemId`, the reason it was held in `queueReason`, whether that hold is resumable in `queueResumable` and its place in line in `queuePosition`. That is a success, so the tool tells the client not to resend it or retry in a loop.

With `queueResumable:false` the queue runs in order on its own as soon as the site is free. With `queueResumable:true` the queue stays parked on purpose, and nothing runs until somebody has looked at what went wrong: read the failure with `get_job`, then call `resume_queue`. An answer to the agent's question and a reply to a plan never queue, whatever is already waiting, because the agent is blocked until you reply.

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/send_message`, sending the inputs below as a JSON object. The token needs the `chat:write` scope.

It makes changes, so send an [Idempotency-Key](https://modulify.ai/docs/api/idempotency) header whenever you might retry it. A retry with the same key gets the first answer back instead of running again.

```bash
curl -X POST https://api.modulify.ai/v1/send_message \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID","prompt":"PROMPT"}'
```

Over MCP, the same method is the [send_message tool](https://modulify.ai/docs/mcp/chat/send-message).

## When it is refused

A full queue is refused. A site holds at most 20 waiting messages and at most 8 from any one person, and going over either comes back as a `429` saying which cap was hit. The tool tells the client to remove an entry with `remove_queued_message` rather than retrying.

The message is also refused rather than queued while the site is locked because the workspace holds more sites than its plan allows. The same goes while the GitHub repository behind the site blocks editing: while its code is being moved into GitHub or back to Modulify, when Modulify has lost access to the repository or it was archived or deleted, and when the code lives in the workspace's own GitHub but the workspace is on the Free plan. See [Site chat](https://modulify.ai/docs/build/site-chat) and [Message queue](https://modulify.ai/docs/build/message-queue).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id, from `list_sites` or `get_site`. |
| `prompt` | string | Yes | What the site agent should do, as specific as an instruction to a developer. It must not be empty and is refused over 500,000 characters. |
| `mode` | string | No | `build`, where the agent makes the change, or `plan`, where it proposes a plan for you to approve first. Defaults to `build`, and any other value is refused. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.