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

# HTTP API

> Authentication, pagination, errors and versioning for the Unified Messaging API.

This reference documents every endpoint of the Flow Messaging HTTP API, generated from its [OpenAPI 3.1 spec](https://github.com/flow-engineer/sdk/blob/main/openapi/openapi.yaml).

```bash theme={null}
curl https://api.flow.engineer/v0/app \
  -H "Authorization: Bearer fk_test_..." \
  -H "Flow-Version: 2026-11-01"
```

## Basics

| | |
| - | - |
| Base URL | `https://api.flow.engineer` |
| Authentication | `Authorization: Bearer fk_test_...` or `fk_live_...` ([test and live mode](https://docs.flow.engineer/unified-messaging-api/concepts/test-and-live-mode.md)); never in the query string. No key yet: `POST /v0/sandbox/keys` needs none and returns a test key ([keys and sign-in](https://docs.flow.engineer/unified-messaging-api/get-a-key.md)). In a browser, the live stream takes the key as a WebSocket subprotocol ([Events and webhooks](https://docs.flow.engineer/unified-messaging-api/concepts/events-and-webhooks.md#the-live-stream)) |
| Version | Paths start with `/v0` (API V0; `/v1` is kept for 1.0). `Flow-Version: 2026-11-01` ([versioning](https://docs.flow.engineer/unified-messaging-api/concepts/versioning.md)) |
| Bodies | JSON (`Content-Type: application/json`), except `POST /v0/files` (multipart) |
| Sends | One endpoint per message kind: `POST /v0/conversations/{conversation_id}/basic`, `/buttons`, `/list`, ... Each page opens with the channels it works on ([message kinds](https://docs.flow.engineer/unified-messaging-api/concepts/content-types.md)) |
| Retries | `Idempotency-Key` on every `POST`, one per call ([idempotency](https://docs.flow.engineer/unified-messaging-api/concepts/idempotency.md)) |
| Spec | [openapi.yaml](https://github.com/flow-engineer/sdk/blob/main/openapi/openapi.yaml) |

## Errors

Errors share one shape. Switch on `error.type`, a closed list; never parse `message`.

```json theme={null}
{
  "error": {
    "type": "outside_window",
    "channel": "whatsapp",
    "message": "Last message from the contact was 31h ago; WhatsApp allows only templates now.",
    "hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
    "doc_url": "https://api.flow.engineer/docs/errors/outside_window",
    "conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
  }
}
```

| Status | `type` |
| - | - |
| 400 | [`invalid_request`](https://docs.flow.engineer/unified-messaging-api/errors/invalid_request) |
| 401 | [`authentication`](https://docs.flow.engineer/unified-messaging-api/errors/authentication) |
| 403 | [`permission`](https://docs.flow.engineer/unified-messaging-api/errors/permission) |
| 404 | [`not_found`](https://docs.flow.engineer/unified-messaging-api/errors/not_found) |
| 409 | [`idempotency_conflict`](https://docs.flow.engineer/unified-messaging-api/errors/idempotency_conflict), [`outside_window`](https://docs.flow.engineer/unified-messaging-api/errors/outside_window) |
| 422 | [`unsupported_content`](https://docs.flow.engineer/unified-messaging-api/errors/unsupported_content), [`file_blocked`](https://docs.flow.engineer/unified-messaging-api/errors/file_blocked) |
| 429 | [`new_contact_limit`](https://docs.flow.engineer/unified-messaging-api/errors/new_contact_limit), [`sender_throttled`](https://docs.flow.engineer/unified-messaging-api/errors/sender_throttled), [`rate_limited`](https://docs.flow.engineer/unified-messaging-api/errors/rate_limited) |
| 501 | [`not_implemented`](https://docs.flow.engineer/unified-messaging-api/errors/not_implemented) |
| 502 | [`channel_error`](https://docs.flow.engineer/unified-messaging-api/errors/channel_error) |
| 500, 503 | [`api_error`](https://docs.flow.engineer/unified-messaging-api/errors/api_error) |

Every error carries `hint`, one sentence saying what to change; for a `422 unsupported_content` it says what to send instead, `param` names what was refused and `channel` the conversation's channel. Errors that clear by themselves carry `retry_after` in seconds; every error carries `request_id`; quote it when asking for help.

## Pagination

Lists take `limit` (1 to 100, default 20) and `after` or `before`, set to the ID of an item you already have, and answer `{ "data": [...], "has_more": true }`. The event log (`GET /v0/events`) is oldest first, so `after` moves forward in time; every other list is newest first.

## Events

The reference lists `GET /v0/events`, the live stream (`GET /v0/stream`, a WebSocket) and the [webhook delivery](https://docs.flow.engineer/api-reference/webhook-endpoints/an-event-delivered-to-your-endpoint.md) Flow sends to your endpoint. See [Events and webhooks](https://docs.flow.engineer/unified-messaging-api/concepts/events-and-webhooks.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.