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

> ## Agent Instructions
> Neuroencoder is a hosted EEG embeddings API (https://api.neuroencoder.com/v1). The model runs only on its servers. Python package `neuroencoder` on PyPI: client, command line tool and MCP server; it does not contain the model. A trial key comes from `neuroencoder login --email <address>` or the HTTP device flow (POST /v1/signup with "device": true, then POST /v1/signup/token); a person approves the emailed link once. Main endpoint: POST /v1/embeddings with an EDF, BDF, FIF or NPY file or a JSON array; any montage, any sampling rate; one 768-dimensional vector per window. Errors are JSON with a `fix` field. Reference: https://docs.neuroencoder.com/api. Guide for AI agents: https://docs.neuroencoder.com/agents. OpenAPI: https://api.neuroencoder.com/v1/openapi.json. Research use only; not a medical device.

# For AI agents

> Use the Neuroencoder EEG embeddings API from an AI agent: llms.txt, skill file, OpenAPI, CLI, MCP server, error contract

Everything an agent needs is available as plain text, a key can be obtained from a terminal, and a local MCP server exposes the API as tools.

## Machine-readable entry points

| What | Where |
| - | - |
| Index of these docs | [`/llms.txt`](https://docs.neuroencoder.com/llms.txt) |
| All docs in one file | [`/llms-full.txt`](https://docs.neuroencoder.com/llms-full.txt) |
| Agent skill (usage, limits, retries in one page) | [`/skill.md`](https://docs.neuroencoder.com/skill.md) |
| Any page as Markdown | append `.md`, e.g. [`/api.md`](https://docs.neuroencoder.com/api.md) |
| API summary for agents | [`https://api.neuroencoder.com/llms.txt`](https://api.neuroencoder.com/llms.txt) |
| OpenAPI | [`https://api.neuroencoder.com/v1/openapi.json`](https://api.neuroencoder.com/v1/openapi.json), interactive at [`/v1/docs`](https://api.neuroencoder.com/v1/docs) |

## Get a key from a terminal

```bash theme={null}
pip install neuroencoder
neuroencoder login --email you@lab.org
```

The command prints a short code and emails a link to that address. A human opens the link and approves only if the page shows the same code; the command then receives the key and saves it to `~/.config/neuroencoder/api_key` (mode 600, `$XDG_CONFIG_HOME` respected). The mail does not contain the code; the human compares the code on the page with the one in the terminal. In Python: `neuroencoder.login("you@lab.org")`.

The same device flow over HTTP:

```bash theme={null}
curl -X POST https://api.neuroencoder.com/v1/signup -H "content-type: application/json" -d '{"email": "you@lab.org", "device": true}'
# -> device_code (keep it secret), user_code (show it to the human), interval 5, expires_in 1800
curl -X POST https://api.neuroencoder.com/v1/signup/token -H "content-type: application/json" -d '{"device_code": "<device_code>"}'
# every 5 s: {"status": "pending"} until the link is approved, then the key exactly once
```

An agent that can read the mailbox may approve a signup it started itself by posting the token from the link, `POST /v1/verify` with `{"t": "<token>"}`: for a device signup this approves it and the key still goes to `/v1/signup/token`; for a signup without `"device": true` the response is the key itself.

A trial key is valid 30 days with 100 h of EEG per month, 30 requests per minute, 2,000 windows per minute, 2 requests in flight and 1 job at a time. Signing up again while the address has a live trial key replaces it: the new key keeps the same limits, expiry and this month's usage, and the old key is revoked when the new one is issued. The key is looked up as the `api_key` argument, then `NEUROENCODER_API_KEY`, then the saved file; keep it out of logs and URLs (send it only in the `Authorization: Bearer` header). A key you already have can be saved with `echo "$KEY" | neuroencoder login --key -`. If the email does not arrive, email [contact@neuroencoder.com](mailto:contact@neuroencoder.com).

## Command line

```bash theme={null}
neuroencoder whoami                             # tier, limits, usage this month, expiry
neuroencoder inspect night.edf                  # free, no upload: channels -> regions, duration, windows and seconds embed would bill
neuroencoder embed night.edf -o night.npz       # bills; [--stride 30] [--no-filter] [--force]
neuroencoder --json embed night.edf -o night.npz
neuroencoder logout                             # delete the saved key file
```

`--json` prints exactly one JSON object on stdout; a failure prints `{"error": {"code", "message", "fix"}}` and exits 1 (2 for usage errors). `embed` writes `embeddings` (float32 `[n, 768]`), `t_start` (`[n]`, seconds) and `meta` (a JSON string with model, source, sfreq, stride, channels used and usage) to one `.npz`, and does not overwrite without `--force`. `.npy` input needs `--sfreq` and, unless it has the 8 regional rows, `--channels Fp1,C3,...`.

## MCP server

A local MCP server on stdio. It reads recordings on the machine it runs on, so files are never passed through the model.

```bash theme={null}
pip install 'neuroencoder[mcp]'
```

```json theme={null}
{"mcpServers": {"neuroencoder": {"command": "neuroencoder", "args": ["mcp"]}}}
```

| Tool | Cost | What it does |
| - | - | - |
| `inspect_recording(path, stride_seconds=30, sfreq, channel_names)` | free, local | Header only: rate, duration, channel-to-region mapping, unmatched channels, and the windows and seconds `embed_recording` would bill. `problem` is set when embedding would fail. |
| `embed_recording(path, stride_seconds=30, output, sfreq, channel_names)` | bills 30 s of EEG per window | Uploads the recording and writes `<stem>.npz` next to it (never overwrites). Returns the path, window count, time range, regions and billed seconds. |
| `find_similar(embeddings, window or time_seconds, k=5, corpus)` | free, local | Cosine top-k for one window of an `.npz`, within the same recording (skipping windows that overlap the query) or across the `.npz` files in `corpus`. |
| `plot_embeddings(embeddings, output, color="time")` | free, local | Writes a PNG of a 2-D PCA of an `.npz`. |
| `account()` | free | Tier, rate limit, monthly quota, usage and expiry of the key in use (key shown as prefix...last4). |

Vectors are written to `.npz` files and never returned to the model; tools return paths and summaries. The server reads only `.edf`, `.bdf`, `.fif`, `.npy` and its own `.npz` files, writes only `.npz` and `.png`, and uploads only the recording given to `embed_recording`. Use absolute paths. Tool errors arrive as `code: message Fix: ...`.

## Error contract

Every API error is JSON with the same shape; `param` names the offending field and `fix` says what to change:

```json theme={null}
{"error": {"message": "Invalid or missing API key.", "type": "authentication_error", "code": "invalid_api_key",
           "param": null, "fix": "Send 'Authorization: Bearer ne_live_...' (56 characters). Get a key with `pip install neuroencoder && neuroencoder login --email you@lab.org`, or POST https://api.neuroencoder.com/v1/signup {\"email\": ..., \"device\": true}; docs https://docs.neuroencoder.com/agents"}}
```

Branch on `code`, apply `fix`, and quote the `x-request-id` response header when reporting a problem. The full list of codes is in the [API reference](https://docs.neuroencoder.com/api.md#errors). The Python client raises the same fields as `.status`, `.code`, `.param` and `.fix`.

## Retries and idempotency

Send `Idempotency-Key: <uuid4>` with every `POST /v1/embeddings` and reuse it when retrying the same request: a repeated request is never billed twice, and the same key with a different request is a 409 `idempotency_key_reused`. Retry 503 `overloaded` and 429 `rate_limit_exceeded`, `concurrency_limit_exceeded` and `windows_rate_limit_exceeded` after `Retry-After`. A 429 without a JSON `code` comes from the gateway or firewall: back off exponentially with jitter. Do not retry `quota_exceeded` or `too_many_queued_jobs`. The Python client, the CLI and the MCP server (2.2.0) retry 503 and `rate_limit_exceeded` themselves; other 429s raise an error. Details: [Retries and idempotency](https://docs.neuroencoder.com/api.md#retries-and-idempotency).

## Limits

1,024 windows per request (8.5 h at the default 30 s stride), `sfreq` 50 to 20,000 Hz, 256 channels, 512 MB per upload, 120 s per request including the upload. The Python client, CLI and MCP server split longer recordings into several requests (EDF, BDF and FIF files over 32 MiB need `pip install mne` for that). Billing is per window, 30 s of EEG each, so a smaller `stride_seconds` bills more. Full table: [Limits](https://docs.neuroencoder.com/api.md#limits).

**Long recordings over HTTP.** A whole recording of up to 24 h is one job, so a full night needs no splitting: `POST /v1/files` gives an upload URL, PUT the file there, `POST /v1/jobs`, poll `GET /v1/jobs/{id}` every `Retry-After` seconds, then download `result.url` (an `.npy` `[windows, 768]`). A 23 h Sleep-EDF recording (2,802 windows) took 65 s from upload to result. Results are kept 7 days and the upload is deleted when the job ends. The Python client, CLI and MCP server 2.2.0 do not use jobs yet. Steps and limits: [Jobs for long recordings](https://docs.neuroencoder.com/api.md#jobs-for-long-recordings).

## Tested recipe

[Similarity search](https://docs.neuroencoder.com/similarity-search.md) is a complete script that was run as printed, with its results.


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