# API reference

> The SkimmerDB REST API: base URL, authentication, conventions, pagination, errors, rate limits, metering, and every endpoint by area.

SkimmerDB is a REST API with JSON in and JSON out, plus an MCP server for AI agents over the same engine. Every operation is described in one OpenAPI 3.1 document, which these pages, the "Try it" consoles and the [Python and TypeScript clients](/sdks) are generated from.

## Base URL

```text
https://api.skimmerdb.com/v1
```

`https://skimmerdb.com/api/...` (and `https://api.skimmerdb.com/api/...`) serves the same operations under their older prefix. It is deprecated and kept working; new code should use `/v1`. The MCP endpoint is `https://api.skimmerdb.com/mcp` (also `https://skimmerdb.com/mcp`): see [Connect an agent](/mcp).

## The OpenAPI document

- JSON: [https://api.skimmerdb.com/openapi.json](https://api.skimmerdb.com/openapi.json)
- YAML: [https://api.skimmerdb.com/openapi.yaml](https://api.skimmerdb.com/openapi.yaml)

It lists every operation, request schema, answer schema, example and error, and is generated from the server's code, so it matches what the API answers. Generate a client in any language from it, or import it into Postman or Insomnia.

## Authentication

Send an API key on every request except signup, login and health:

```sh title="curl"
curl -s https://api.skimmerdb.com/v1/me -H "Authorization: Bearer $KEY"
```

```python title="Python"
from skimmerdb import SkimmerDB

db = SkimmerDB("tb_...")      # or SKIMMERDB_KEY in the environment
print(db.me())
```

```ts title="TypeScript"
import { SkimmerDB } from "skimmerdb";

const db = new SkimmerDB("tb_...");   // or SKIMMERDB_KEY in the environment
console.log(await db.me());
```

| Credential | Header | Use |
|---|---|---|
| API key (`tb_...`) | `Authorization: Bearer tb_...` or `X-API-Key: tb_...` | Everything: apps, agents, scripts |
| Login token (`POST /v1/login`) | `Authorization: Bearer <token>`, and `X-Tenant: <id>` to act for another of your tenants | Managing the account: tenants, keys, billing. Lasts a day |
| OAuth access token (`tbo_...`) | `Authorization: Bearer tbo_...` | Only `/mcp`: what an agent gets when a person approves it |

Keys have a scope (`read` < `write` < `admin`) and may be limited to some namespaces. Signup's key is `admin`: give apps and agents narrower keys. See [Keys, scopes and tenants](/guides/keys).

## Requests and answers

- **JSON bodies** with `Content-Type: application/json`, except imports, whose body is the file. Answers are JSON (`application/json`), except a sidecar file's bytes.
- **Names in paths.** A namespace name is 1 to 64 of `a-z 0-9 - _ .`. A document id may contain slashes: `GET /v1/namespaces/{name}/docs/{the rest of the path}`.
- **Writes are by id.** Writing an id again replaces the document, so retrying a write, update or delete is safe: the same request gives the same result. There's no separate idempotency key.
- **Every query reports its cost.** Search, count and SQL answers carry `took_ms`, `temperature` (`warm`, `local` or `cold`), `store_gets` and `store_bytes` (what it read from object storage) and `cpu_ms`.
- **Partial answers say so.** `"partial": true` means some data couldn't be read in time or at all: the answer is incomplete, never wrong.

## Pagination

| Listing | Ask for | Answer has | Next page |
|---|---|---|---|
| Namespaces (`GET /v1/namespaces`) | `limit` (default 100) | `next` | Pass `next` as `after` |
| Search and listing documents (`POST .../search`) | `limit` (default 20) | `next` | Pass `next` as `cursor` |

An empty `next` means there are no more. Search cursors stay valid while the namespace is compacted; documents written since the first page appear in a new search, not mid-way.

## Errors

Every error is `{"error": "a sentence", "code": "a_word"}`, plus `fields` for invalid input and `retry_after` with `write_busy`. Branch on `code`. Every status and code, and what to do about each: [Errors](/reference/errors).

## Rate limits

Answers that count against a rate carry `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` and `RateLimit-Policy`; a 429 carries `Retry-After`. Each plan's rates and concurrency: [Limits and plans](/reference/limits).

## Metering

| Calls | Metered as |
|---|---|
| Search, count, get, warm, SQL, sidecar reads | One query each |
| Write, update, delete, import | The documents written or deleted, and their bytes |
| Queries' object-storage reads | `store_gets`, `store_bytes` |
| Storage | GB-months of what the namespaces hold |
| MCP tool calls | The same as their REST call, counted apart as `mcp_queries` / `mcp_writes` |

`GET /v1/usage` shows the period so far and its bill.

## Versions and beta

The API is versioned in the path (`/v1`). New fields and operations are added to answers over time, so clients should ignore fields they don't know. Operations marked **beta** (SQL today) may still change: SQL's dialect is growing.

## Endpoints

| Area | What |
|---|---|
| [Accounts](/api/accounts) | Sign up, log in, who you are |
| [Keys](/api/keys) | API keys: scopes, namespaces, caps |
| [Tenants](/api/tenants) | A tenant owns namespaces, keys, usage and a bill |
| [Namespaces](/api/namespaces) | Named sets of documents, one per user, task or project |
| [Documents](/api/documents) | Write, update, delete, read, import |
| [Search](/api/search) | Text, regex, filters, vectors, counts, warm |
| [SQL](/api/sql) (beta) | SQL over the documents' metadata |
| [Usage](/api/usage) | What you used and what it costs |
| [Billing](/api/billing) | Plans and Stripe |
| [Linked namespaces](/api/linked-namespaces) | Indexes linked by reference |
| [MCP](/api/mcp) | The endpoint for AI agents |
| [Meta](/api/meta) | Health and the OpenAPI document |
