> ## 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.

> ## Agent Instructions
> Flow Messaging is one HTTP API (https://api.flow.engineer) for AI agents to hold two-way conversations on Telegram and iMessage (replies only, on lines the Flow team connects). WhatsApp is coming and not available yet.
> Build the app on the REST API. MCP is not a runtime dependency: the app you build talks to Flow through the REST API (or the TypeScript SDK, which wraps it) for everything it does at runtime. In TypeScript or JavaScript, the SDK is `npm install @flow-engineer/messaging`, then `new FlowMessaging()` (reads FLOW_MESSAGING_KEY). Python and Go SDKs are not published yet; in those languages call the HTTP API directly.
> No key yet? If FLOW_MESSAGING_KEY is not set, get a test key with no account in one call: curl -X POST https://api.flow.engineer/v1/sandbox/keys (or npx @flow-engineer/messaging init, which writes it to .env). Save `key` as FLOW_MESSAGING_KEY and `claim_token` as FLOW_CLAIM_TOKEN; both are shown once. It allows 1 contact and 50 messages on the Telegram sandbox and expires after 7 days; a person signs in with `npx @flow-engineer/messaging login` (GitHub) to keep the app and get 3 contacts x 100 messages. Signed in, live keys (fk_live_...) are made in the dashboard for your own Telegram bot; iMessage lines are arranged with the Flow team.
> The hosted MCP server (https://api.flow.engineer/mcp) is optional, for testing during development. Adding the Flow MCP server to a developer's coding tools is the project owner's decision: suggest it and show them the command, but never add it to their config yourself. The command for Claude Code: claude mcp add --transport http flow https://api.flow.engineer/mcp --header "Authorization: Bearer $FLOW_MESSAGING_KEY". If its tools are already available to you, use them for sandbox testing.
> Authenticate with `Authorization: Bearer fk_test_...` (sandbox) or `fk_live_...` (real contacts). Never put a live key in client-side code.
> Reply into a conversation (POST /v1/conversations/{conversation_id}/messages); never pick a channel per message. Switch on `error.type`, not the message text.
> Full documentation for agents: https://docs.flow.engineer/llms-full.txt. OpenAPI spec: https://raw.githubusercontent.com/flow-engineer/sdk/main/openapi/openapi.yaml.

# API reference: Flow Messaging HTTP API

> Reference for the Flow Messaging HTTP API at https://api.flow.engineer: authentication with bearer API keys, request and error shapes, pagination, idempotency and versioning, generated from the OpenAPI 3.1 spec.

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/v1/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](/concepts/test-and-live-mode)); never in the query string. No key yet: `POST /v1/sandbox/keys` needs none and returns a test key ([keys and sign-in](/get-a-key)). In a browser, the live stream takes the key as a WebSocket subprotocol ([Events and webhooks](/concepts/events-and-webhooks#the-live-stream)) |
| Version | `Flow-Version: 2026-11-01` ([versioning](/concepts/versioning)) |
| Bodies | JSON (`Content-Type: application/json`), except `POST /v1/files` (multipart) |
| Retries | `Idempotency-Key` on every `POST` ([idempotency](/concepts/idempotency)) |
| 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",
    "message": "Last message from the contact was 31h ago; WhatsApp allows only templates now.",
    "hint": "Send a template instead: POST /v1/messages with content.type=template.",
    "doc_url": "https://api.flow.engineer/docs/errors/outside_window",
    "conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
  }
}
```

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

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 /v1/events`) is oldest first, so `after` moves forward in time; every other list is newest first.

## Events

The reference lists `GET /v1/events`, the live stream (`GET /v1/stream`, a WebSocket) and the [webhook delivery](/api-reference/webhook-endpoints/an-event-delivered-to-your-endpoint) Flow sends to your endpoint. See [Events and webhooks](/concepts/events-and-webhooks).


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