> ## Documentation Index
> Fetch the complete documentation index at: https://docs.my-aichatbot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Introduction

> Base URL, keys, rules, and rate limits for the v1 API.

A small JSON-over-HTTPS API. Six endpoints, no SDK.

## Base URL

```text theme={null}
https://app.my-aichatbot.com
```

Every endpoint lives under `/api/v1`. HTTPS only.

## Keys

Two ways to prove who you are, depending on the endpoint.

<CardGroup cols={2}>
  <Card title="Token in the path" icon="link">
    `/api/v1/responses/{token}` carries its own key. Send **no** `Authorization` header. It expires after 45 minutes.
  </Card>

  <Card title="Bearer key" icon="key">
    Everything else takes `Authorization: Bearer mac_live_…`. One key per chatbot, and it never expires.
  </Card>
</CardGroup>

See [Authentication](/authentication) for how to get each one.

## Endpoints

| Method  | Path                                                                              | Key   |
| ------- | --------------------------------------------------------------------------------- | ----- |
| `POST`  | [`/api/v1/responses/{token}`](/api-reference/post-response)                       | Token |
| `POST`  | [`/api/v1/responses/{token}/files`](/api-reference/upload-response-file)          | Token |
| `POST`  | [`/api/v1/conversations/{conversation_id}/messages`](/api-reference/post-message) | Key   |
| `GET`   | [`/api/v1/conversations/{conversation_id}/messages`](/api-reference/get-messages) | Key   |
| `PATCH` | [`/api/v1/messages/{message_id}`](/api-reference/patch-message)                   | Key   |
| `POST`  | [`/api/v1/bots/{chatbot_id}/files`](/api-reference/upload-file)                   | Key   |

## Rules

* **JSON in, JSON out.** Send `Content-Type: application/json` — except on the file upload endpoints, which take `multipart/form-data`.
* **snake\_case** everywhere.
* **Times** are ISO 8601 in UTC (`2026-07-17T03:15:12.398Z`).
* **Ids** are plain strings. Do not try to read meaning into them.
* **Success** includes `"ok": true`. Failure includes `"ok": false` and an `error` object. The `GET` history endpoint is the one exception — it returns the data directly.

## Errors

One shape everywhere:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "conversation_taken_over",
    "message": "An operator has taken over this conversation."
  }
}
```

Block Kit failures add an `issues` list that points at each problem:

```json theme={null}
{
  "ok": false,
  "error": {
    "code": "BLOCK_VALIDATION_FAILED",
    "message": "1 issue(s) found in your Block Kit payload.",
    "issues": [
      {
        "code": "INSECURE_URL",
        "path": "/messages/0/blocks/2/url",
        "message": "URLs must use https:// (got http://).",
        "severity": "error"
      }
    ]
  }
}
```

Full list: [Limits and errors](/block-kit/limits-and-errors).

## Rate limits

| Scope              | Limit                |
| ------------------ | -------------------- |
| Response URL token | 30 requests / minute |
| API key — writes   | 120 / minute         |
| API key — reads    | 300 / minute         |
| File uploads       | 20 / minute          |

A `429` includes `retry_after` in seconds:

```json theme={null}
{
  "ok": false,
  "error": { "code": "rate_limited", "message": "Too many requests.", "retry_after": 12 }
}
```

## Sizes

| Thing              | Limit  |
| ------------------ | ------ |
| Request body       | 256 KB |
| Messages per call  | 10     |
| Blocks per message | 25     |
| Image upload       | 10 MB  |
| File upload        | 25 MB  |

## Safe retries

Give a message a `mid`, and sending it again **updates** instead of duplicating. Build the `mid` from the event's `event_id`, and your whole integration becomes safe to retry — which matters, because Make, n8n, and Zapier all retry.

See [Updating messages](/sending-messages/updating-messages).
