Skip to main content
A small JSON-over-HTTPS API, no SDK. It covers three things: messages into your bot’s conversations, files to attach to them, and hosted Pages your bot or backend publishes.

Base URL

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

Keys

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

Token in the path

/api/v1/responses/{token} carries its own key. Send no Authorization header. It expires after 45 minutes.

Bearer key

Everything else takes Authorization: Bearer mac_live_…. One key per chatbot, and it never expires. Writing Pages also needs Pages write turned on for the key.
See Authentication for how to get each one.

Endpoints

Messages

Files

Pages

Reads see every Page in the workspace. Writes only touch Pages owned by the key’s own bot.

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.
  • Error codes on the Pages endpoints are always UPPER_SNAKE (INVALID_API_KEY, RATE_LIMITED). The messages and files endpoints mix cases (invalid_api_key, PAYLOAD_TOO_LARGE). Match on the exact string.

Errors

One shape everywhere:
Block Kit failures add an issues list that points at each problem:
Full list: Limits and errors.

Rate limits

A 429 tells you how long to wait: retry_after on the messages and files endpoints, retry_after_seconds on the Pages endpoints.

Sizes

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. That matters, because Make, n8n, and Zapier all retry. See Updating messages. Pages are retry-safe by design: PUT /pages/by-slug/{slug} creates on the first call and updates after that, and content identical to the current version is skipped rather than stored twice.