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

# OpenFunnel Authentication (for agents)

> Self-serve an API key in two calls, then authenticate every request with X-API-Key. One key works across Product APIs, Agent Primitives, and the OpenFunnel MCP.

Base URL: `https://api.openfunnel.dev`

Every request authenticates with a single header:

* `X-API-Key: <your_api_key>`  (the key looks like `of_...`)
* `Content-Type: application/json`

There is no OAuth flow and no dashboard step. You can obtain a key programmatically in two calls.

The same `X-API-Key` authenticates every surface: Product APIs, Agent Primitives, and the OpenFunnel MCP. There are no per-surface keys or scopes — provision one key and reuse it everywhere.

## Step 1 — Request a verification code

```
POST /api/v1/agent/sign-up
Content-Type: application/json

{ "email": "founder@example.com" }
```

Sends a 6-digit code to the email. New emails create an account; existing emails use this to recover a lost key.

Response:

```
{ "email": "founder@example.com", "message": "Verification code sent to your email" }
```

## Step 2 — Verify and receive the key

```
POST /api/v1/agent/verify
Content-Type: application/json

{ "email": "founder@example.com", "otp_code": "123456" }
```

Response:

```
{
  "email": "founder@example.com",
  "api_key": "of_1234567890abcdef...",
  "is_new_user": true
}
```

Store `api_key` securely. It is returned only once and is not retrievable later. To recover it, call sign-up again with the same email.

## Step 3 — Authenticate every other request

```
POST /api/v1/signal/get-signal-list
X-API-Key: of_1234567890abcdef...
Content-Type: application/json

{}
```

## Errors

| HTTP | error\_code        | Meaning                                                    |
| ---- | ------------------ | ---------------------------------------------------------- |
| 400  | OTP\_EXPIRED       | No pending code. Call sign-up again.                       |
| 400  | OTP\_INVALID       | Wrong code. `details.remaining_attempts` shows tries left. |
| 429  | RATE\_LIMITED      | Too many sign-up attempts. `details.retry_after_seconds`.  |
| 429  | OTP\_MAX\_ATTEMPTS | Code exhausted (10 tries). Call sign-up again.             |
| 500  | INTERNAL\_ERROR    | Transient. Retry.                                          |

Verification codes expire after 24 hours and allow up to 10 attempts.

## Notes

* Full index of all docs: [https://docs.openfunnel.dev/llms.txt](https://docs.openfunnel.dev/llms.txt)
* Human-readable version of this page: [https://docs.openfunnel.dev/authentication](https://docs.openfunnel.dev/authentication)
