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
| Scope | May |
|---|---|
read | List namespaces, search, count, get documents, warm, SQL, usage |
write | Also create and delete namespaces; write, update, delete and import documents |
admin | Also 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"] });| Field | Meaning |
|---|---|
name | A label. |
scope | read, write (the default) or admin. |
namespaces | The namespaces the key may use: names, or prefix* ("agent-7-*"). Default: all. |
rate_per_s | Requests a second for this key (0: none of its own; the tenant's plan still applies). |
cap_queries | Queries a billing period (0: none). Past it: 429. |
cap_writes | Documents written or deleted a billing period (0: none). Past it: 429. |
GET /v1/keyslists the tenant's live keys (connected_appmarks one made by an MCP/OAuth approval).PUT /v1/keys/{id}/limitschangesnamespaces,rate_per_s,cap_queriesandcap_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/tenantslists 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 byX-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.