Get started Markdown

Quickstart

Sign up, write documents, then search, filter, count, query with SQL and search by vector.

This takes a few minutes. You need curl (and jq for the first step), or Python 3 or Node.

1. Sign up

Signing up makes your account and its first tenant, and answers with your first API key. That key has full access (scope admin) and is shown only once: keep it somewhere safe. You can also sign up on the sign-up page and copy a key from the dashboard.

B=https://api.skimmerdb.com/v1
KEY=$(curl -s $B/signup -d '{"email": "ada@example.com", "name": "Ada", "password": "correct horse"}' | jq -r .key)
echo $KEY    # tb_...
# pip install skimmerdb
from skimmerdb import SkimmerDB

db = SkimmerDB.signup("ada@example.com", "correct horse")
print(db.key)   # tb_... : keep it; next time SkimmerDB("tb_...") or SKIMMERDB_KEY
// npm install skimmerdb
import { SkimmerDB } from "skimmerdb";

const db = await SkimmerDB.signup("ada@example.com", "correct horse");
console.log(db.key); // tb_... : keep it; next time new SkimmerDB("tb_...") or SKIMMERDB_KEY

Tip Give apps and agents narrower keys than this one: POST /v1/keys makes a write key by default, and a key can be read-only or limited to some namespaces. See Keys, scopes and tenants.

2. Write documents

A document is an id, the text you search, and meta you filter and group by. Writing to a namespace that doesn't exist makes it, and the answer says "created": true.

curl -s $B/namespaces/support/docs -H "Authorization: Bearer $KEY" -d '{
  "wait": true,
  "docs": [
    {"id": "t-1", "text": "Refund requested for order ACME-1042", "meta": {"status": "open", "priority": 3}},
    {"id": "t-2", "text": "Login fails with error E401 on mobile", "meta": {"status": "closed", "priority": 1}}
  ]}'
ns = db.namespace("support")
ns.write([
    {"id": "t-1", "text": "Refund requested for order ACME-1042", "meta": {"status": "open", "priority": 3}},
    {"id": "t-2", "text": "Login fails with error E401 on mobile", "meta": {"status": "closed", "priority": 1}},
], wait=True)
const ns = db.namespace("support");
await ns.write([
  { id: "t-1", text: "Refund requested for order ACME-1042", meta: { status: "open", priority: 3 } },
  { id: "t-2", text: "Login fails with error E401 on mobile", meta: { status: "closed", priority: 1 } },
], { wait: true });

The answer: {"written": 2, "deleted": 0, "version": 1, "stored_bytes": ..., "created": true}. A write is durable when it answers. wait makes it answer only once the documents are searchable too; without it they're searchable within about a second.

Plain text is matched literally, ignoring case. Hits come newest first, with the matched text and the line around it.

curl -s $B/namespaces/support/search -H "Authorization: Bearer $KEY" -d '{"q": "acme-1042"}'
for hit in ns.search("acme-1042").hits:
    print(hit.id, hit.match, hit.line)
const { hits } = await ns.search("acme-1042");
hits.forEach((h) => console.log(h.id, h.match, h.line));
answer
{"namespace": "support", "hits": [{"id": "t-1", "match": "ACME-1042", "line": "Refund requested for order ACME-1042",
  "meta": {"priority": 3, "status": "open"}, "written_at": "2026-10-05T01:30:12Z"}], "next": "", "docs": 2,
  "took_ms": 0.41, "partial": false, "temperature": "warm", "store_gets": 0, "store_bytes": 0}

4. Filter, regex and count

Filters match meta: equal, one of, a numeric range, not equal. Regex is opt-in (RE2). Counts are exact.

curl -s $B/namespaces/support/search -H "Authorization: Bearer $KEY" \
  -d '{"q": "E[0-9]{3}", "regex": true, "filter": {"priority": {"gte": 1, "lt": 4}}}'
curl -s $B/namespaces/support/count -H "Authorization: Bearer $KEY" -d '{"q": "", "filter": {"status": "open"}}'
ns.search("E[0-9]{3}", regex=True, filter={"priority": {"gte": 1, "lt": 4}})
ns.count(filter={"status": "open"})   # 1
await ns.search("E[0-9]{3}", { regex: true, filter: { priority: { gte: 1, lt: 4 } } });
await ns.count("", { filter: { status: "open" } }); // 1

More in Search and filters and the filter reference.

5. SQL

Every top-level meta key is a column, and id is one too.

curl -s $B/namespaces/support/sql -H "Authorization: Bearer $KEY" \
  -d '{"sql": "SELECT status, COUNT(*) AS n, AVG(priority) AS p FROM docs GROUP BY status ORDER BY n DESC"}'
r = ns.sql("SELECT status, COUNT(*) AS n, AVG(priority) AS p FROM docs GROUP BY status ORDER BY n DESC")
print(r.columns, r.rows)
const r = await ns.sql("SELECT status, COUNT(*) AS n, AVG(priority) AS p FROM docs GROUP BY status ORDER BY n DESC");
console.log(r.columns, r.rows);

See Analytics with SQL and the SQL reference.

6. Vectors

Give documents a vector (your embeddings) and search with one. The first write with vectors makes the namespace with their length and cosine similarity; q and filter narrow the candidates (hybrid search).

curl -s $B/namespaces/notes/docs -H "Authorization: Bearer $KEY" -d '{"wait": true, "docs": [
  {"id": "n-1", "text": "Webhook timeouts since Tuesday", "vector": [0.1, 0.0, 0.98], "meta": {"team": "api"}},
  {"id": "n-2", "text": "New logo for the landing page", "vector": [0.9, 0.4, 0.1], "meta": {"team": "design"}}]}'
curl -s $B/namespaces/notes/search -H "Authorization: Bearer $KEY" \
  -d '{"vector": [0.1, 0.0, 0.98], "limit": 10, "filter": {"team": "api"}}'
notes = db.namespace("notes")
notes.write([
    {"id": "n-1", "text": "Webhook timeouts since Tuesday", "vector": [0.1, 0.0, 0.98], "meta": {"team": "api"}},
    {"id": "n-2", "text": "New logo for the landing page", "vector": [0.9, 0.4, 0.1], "meta": {"team": "design"}},
], wait=True)
notes.search(vector=[0.1, 0.0, 0.98], limit=10, filter={"team": "api"})
const notes = db.namespace("notes");
await notes.write([
  { id: "n-1", text: "Webhook timeouts since Tuesday", vector: [0.1, 0.0, 0.98], meta: { team: "api" } },
  { id: "n-2", text: "New logo for the landing page", vector: [0.9, 0.4, 0.1], meta: { team: "design" } },
], { wait: true });
await notes.search("", { vector: [0.1, 0.0, 0.98], limit: 10, filter: { team: "api" } });

Hits come nearest first with a score. Real embeddings have hundreds of dimensions (up to 2,048). See Vector and hybrid search.

Next