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

# authentication

> The API key is missing, malformed, unknown, revoked or expired.

# authentication

HTTP 401. The API key is missing, malformed, unknown, revoked or expired.

## What it means

The request carried no API key Flow recognises, so nothing was done.

## Why it happens

* No `Authorization` header, or not in the form `Bearer <key>`.
* The key was copied with quotes, spaces or a line break.
* The key was revoked or belongs to a deleted app.
* The environment variable holding the key is empty in this process.
* The key came from `POST /v1/sandbox/keys` and passed its `expires_at`, 7 days after it was made (`channel_code` `sandbox_key_expired`).

## How to fix it

Send `Authorization: Bearer fk_test_...` (or `fk_live_...`) with a current key. Print the first characters of the key your process actually uses to check it is set.

No key at all? Get a test key in one call, without an account. Save `key` (as `FLOW_MESSAGING_KEY`) and `claim_token`; both are shown once.

```bash theme={null}
curl -X POST https://api.flow.engineer/v1/sandbox/keys
curl https://api.flow.engineer/v1/app -H "Authorization: Bearer $FLOW_MESSAGING_KEY"
```

A sandbox key that expired can be revived by claiming its app within 30 days of its `expires_at`: a person signs in with GitHub through the device flow (`npx @flow-engineer/messaging login`, or `POST /v1/device/authorizations` with the `claim_token` or the expired key), which keeps the app and gives a new key that replaces the expired one (a claim through the `claim_url` in a browser gives no new key and makes the expired key work again). After those 30 days the expired key stays revoked: claim with the `claim_token` (the sign-in gives a new key), or get a new key as above. A key someone revoked is never revived. Keys of signed-in people are created and revoked in the dashboard (`https://api.flow.engineer/admin`).

Every error also carries `hint`, one sentence specific to your request, and
`doc_url`, this page. Coding agents connected to Flow's MCP server
(`https://api.flow.engineer/mcp`) can call `explain_error` with the type to read this page.


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