Guides Markdown

Keys, scopes and tenants

Who can do what - API keys with scopes, keys limited to some namespaces, caps and rates, tenants, and the keys MCP connections get.

Every request acts for one tenant (an account: it owns namespaces, keys, usage and a bill) with one key. A key has a scope, may be limited to some namespaces, and may carry its own rate and caps. Give every app and agent its own narrow key; keep the full-access one to yourself.

Sending a key

Send the key as Authorization: Bearer tb_... (or X-API-Key: tb_...). The clients read SKIMMERDB_KEY from the environment.

curl -s https://api.skimmerdb.com/v1/me -H "Authorization: Bearer $KEY"
from skimmerdb import SkimmerDB
db = SkimmerDB("tb_...")        # or SkimmerDB() with SKIMMERDB_KEY set
print(db.me())
import { SkimmerDB } from "skimmerdb";
const db = new SkimmerDB("tb_...");   // or new SkimmerDB() with SKIMMERDB_KEY set
console.log(await db.me());

GET /v1/me says who you are, the tenant you act for, its plan, your scope and (for a limited key) its namespaces.

Your first key

Signing up (POST /v1/signup, or the sign-up page) makes you, your first tenant and its first key: scope admin, full access, shown only once. Use it to make narrower keys, not inside apps or agents.

Scopes

ScopeMay
readList namespaces, search, count, get documents, warm, SQL, usage
writeAlso create and delete namespaces; write, update, delete and import documents
adminAlso make, list, change and revoke keys, and billing

A request the key's scope doesn't allow is a 403 forbidden.

Making keys

POST /v1/keys with {"name", "scope", "namespaces", "rate_per_s", "cap_queries", "cap_writes"}. The answer has the key; it's shown only here.

curl -s https://api.skimmerdb.com/v1/keys -H "Authorization: Bearer $ADMIN_KEY" \
  -d '{"name": "support bot", "scope": "read", "namespaces": ["help-center"]}'
# {"id": 7, "name": "support bot", "key": "tb_...", "prefix": "tb_Ab3dE", "scope": "read", "namespaces": ["help-center"]}
key = db.create_key("support bot", scope="read", namespaces=["help-center"])
const key = await db.createKey("support bot", { scope: "read", namespaces: ["help-center"] });
FieldMeaning
nameA label.
scoperead, write (the default) or admin.
namespacesThe namespaces the key may use: names, or prefix* ("agent-7-*"). Default: all.
rate_per_sRequests a second for this key (0: none of its own; the tenant's plan still applies).
cap_queriesQueries a billing period (0: none). Past it: 429.
cap_writesDocuments written or deleted a billing period (0: none). Past it: 429.
  • GET /v1/keys lists the tenant's live keys (connected_app marks one made by an MCP/OAuth approval).
  • PUT /v1/keys/{id}/limits changes namespaces, rate_per_s, cap_queries and cap_writes, at once.
  • DELETE /v1/keys/{id} revokes it at once (and disconnects an MCP connection that uses it).

Who can manage keys

Only an admin key without namespace limits or caps (signup's key is one), or the owner's login, can make, list, change or revoke keys. So a read or write key handed to an app or an agent can't make more keys, and an admin key limited to some namespaces can't make an unlimited one.

Keys limited to namespaces

A key limited to ["help-center"] or ["mem-u-17", "agent-7-*"] sees only those. Every other namespace answers exactly like a name nobody has: 404, and left out of GET /v1/namespaces. The same holds over MCP. This is how you give each user's agent its own memory and nothing else; see Agent memory.

Tip Name namespaces with a prefix per owner or purpose (agent-7-..., mem-..., kb-...) so one prefix* covers every namespace an agent creates for itself.

Tenants

A tenant owns namespaces (stored under its own prefix in object storage), keys, usage and a bill. One tenant never sees another's namespaces: a name another tenant has answers exactly like a name nobody has.

  • A person can own or belong to several tenants. GET /v1/tenants lists yours (with your role); POST /v1/tenants {"name"} makes one you own. Both need a login.
  • POST /v1/login {"email", "password"} answers a token valid for a day, for managing the account. It acts for your default tenant, or the one named by X-Tenant: <id>.
  • DELETE /v1/tenants/{id} deletes a tenant, its namespaces, keys and usage for good (its owner only; not your account's own).

API keys belong to exactly one tenant, so a key never needs X-Tenant.

MCP connections

An agent that connects to https://api.skimmerdb.com/mcp with OAuth sends you to a consent page where you sign in and pick the tenant, read-only or read-and-write, and optionally the namespaces it may use. The connection gets a key of its own, limited that way; it appears in GET /v1/keys with connected_app, and revoking it disconnects the agent. An agent can also connect with a key you made. See Connect an agent.

Limits

Each tenant's plan sets requests a second and requests in flight (per server); a key's own rate_per_s can only be tighter. Answers that count against a rate carry RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset and RateLimit-Policy, and every 429 has Retry-After. See Limits and plans.