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_KEYTip 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.
3. Search
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));{"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"}) # 1await ns.search("E[0-9]{3}", { regex: true, filter: { priority: { gte: 1, lt: 4 } } });
await ns.count("", { filter: { status: "open" } }); // 1More 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
- Shape your data well from the start: Data model.
- Load files: Importing files (CSV, NDJSON, Parquet).
- Give an agent access: Connect an agent and the agent skill.