Quickstart
1. Get an API key
Sign in to create your account, then on the dashboard give a new key a label and choose Mint key. The full key is shown exactly once, so copy it somewhere safe. The dashboard is also where you mint more keys (one per integration is a good habit), revoke them, and watch your usage.
$ export TAGLYDB_API_KEY="sk-..." # the key from your dashboard2. Write something, read it back
The quickest path is a standalone item: one value, no index needed, fetched back by its key.
# Store one JSON value under a key you choose
$ curl -X POST https://api.taglydb.com/items \
-H "Authorization: Bearer $TAGLYDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "key": "hello", "tags": { "kind": "greeting" }, "data": { "message": "Hello, TaglyDB" } }'
{
"id": "0199c4e2-7a31-7c40-9f1e-5d2b8a6c1e07",
"key": "hello",
"tags": { "kind": "greeting" },
"createdAt": "2026-09-23T09:12:44.518Z",
"sizeBytes": 28,
"storedBytes": 32,
"encoding": "br",
"contentType": "application/json"
}
# Read it back: the response body is exactly the value you stored
$ curl https://api.taglydb.com/items/by-key/hello \
-H "Authorization: Bearer $TAGLYDB_API_KEY"
{ "message": "Hello, TaglyDB" }3. Build a collection you can filter
When you'll have many related items and want to query them by tag, put them in an index.
# Create an index to hold a filterable collection of JSON items
$ curl -X POST https://api.taglydb.com/indexes \
-H "Authorization: Bearer $TAGLYDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "key": "support-tickets", "type": "json" }'
{ "id": "0199c4e3-01b2-7d9a-8c55-3f0e6a9b2d14", "key": "support-tickets", "tags": {}, "type": "json", "createdAt": "..." }
$ IDX=0199c4e3-01b2-7d9a-8c55-3f0e6a9b2d14
# Add a tagged item to it
$ curl -X POST https://api.taglydb.com/indexes/$IDX/items \
-H "Authorization: Bearer $TAGLYDB_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "tags": { "team": "billing", "priority": "high" }, "data": { "subject": "Refund request", "amount": 42.5 } }'
# Every high-priority billing ticket, with its data
$ curl "https://api.taglydb.com/indexes/$IDX/items/data?tag=team=billing&tag=priority=high" \
-H "Authorization: Bearer $TAGLYDB_API_KEY"The same thing in Python
The taglydb Python client wraps the same API in typed methods — see the Python client guide.
import os
from taglydb import Tagly
with Tagly.build(api_key=os.environ["TAGLYDB_API_KEY"]) as client:
# A standalone item: no index to create first
client.simple_items.create_json(
key="hello", tags={"kind": "greeting"}, data={"message": "Hello, TaglyDB"}
)
print(client.simple_items.get_json_by_key("hello")) # {'message': 'Hello, TaglyDB'}
# An index, a tagged item, and a filtered read with data
index = client.indexes.create(key="support-tickets", type="json")
client.items.create_json(
index.id,
tags={"team": "billing", "priority": "high"},
data={"subject": "Refund request", "amount": 42.5},
)
tickets = client.items.list_with_data(
index.id, tags={"team": "billing", "priority": "high"}
)Concepts
Your account and API keys
Everything you store belongs to your account, and every request authenticates as that account with an API key in an Authorization: Bearer sk-… header. All of your keys see the same data; separate keys exist so each integration can be revoked on its own and its usage shows up separately. A key looks like sk-<key id>-<secret> and has a label that is unique in your account — a label stays taken even after that key is revoked. A revoked key can take up to about 30 seconds to stop working everywhere. Your key list also includes the one key the dashboard uses to act on your behalf; the dashboard won't let you revoke that one.
Nothing in another account is ever visible to you: an id that belongs to someone else behaves exactly like one that doesn't exist.
Indexes and standalone items
An item — one stored value — lives in one of two places:
- In an index. An index is a collection you create up front. Its items can be listed, paginated, filtered by tag or key, and fetched in bulk together with their data. Use one whenever you'll want to ask “which items match these tags?”
- Standalone.
POST /itemsstores an item that belongs to no index at all — for “store this one thing, look it up later”. A standalone item is fetched by its id or its key; standalone items can't be listed or filtered.
The two are addressed by separate routes: an indexed item lives under /indexes/:indexId/items/… and isn't reachable under /items/…, and a standalone item is the other way round. Item ids are unique across both.
JSON items and blob items
- A JSON item holds any JSON value — an object, but also an array, string, number, boolean or
null. You send it as thedatafield of anapplication/jsonbody, and get it back verbatim asapplication/json. - A blob item holds arbitrary bytes — a PDF, an image, a model checkpoint. You upload it as
multipart/form-data; theContent-Typeyou give the file part is remembered and served back when you download it.
An index is permanently one type or the other, chosen when you create it. A standalone item's type follows the Content-Type of the request that created it.
Keys and tags
Indexes and items can each carry an optional key — a stable name you choose, so you can fetch something without keeping its id around — and optional tags, a flat map of string keys to string values. Keys are unique within their scope: an index key among your indexes, an indexed item's key within its index, a standalone item's key among your standalone items.
Tag filters combine two ways: repeat the same tag key to OR its values, use different tag keys to AND them — the convention AWS resource tags and Kubernetes label selectors use.
# OR: the same tag key repeated
?tag=team=billing&tag=team=support
# AND: different tag keys
?tag=team=billing&tag=priority=high
# Both: (team is billing OR support) AND priority is high
?tag=team=billing&tag=team=support&tag=priority=highGetting data back
- Raw — fetching an item returns its payload itself: the JSON value, or the blob's bytes with its own
Content-Type. - Full — adding
/fullreturns one JSON object with the item's metadata and its payload in adatafield. A blob's bytes travel base64-encoded there, as{"b64": "…"}. - Listing an index's items returns metadata only, a page at a time. To get every match with its data in one call, use the index's
/items/dataendpoint.
Items don't change
Indexes and items are immutable: there are no update or delete endpoints. To record a new version of something, write a new item — ids are time-ordered and listings return oldest first, so the newest match is always the last one. Deleting your account from the dashboard permanently deletes everything in it.
Signed URLs
To hand one item to something that shouldn't hold your API key — a browser, a teammate, a CDN — mint a signed URL for it. The URL works with no Authorization header until it expires (one hour by default, at most seven days), can be cached publicly, and stops working if the key that minted it is revoked.
Credits and usage
Requests consume credits. Reads are metered by how much stored data TaglyDB has to scan to answer the request, not by how much it returns — 1 credit per 1,000 rows scanned — so a narrow filter, or a smaller, well-scoped index, costs less than a broad filter over one huge index. Writes are metered by the size of the payload you send: 1 credit per MB, with every write rounded up to a whole KB. Every request costs at least 0.01 credits, and what you keep stored costs 50 credits per GB per day.
Every account starts on the Free plan: 1,000 credits a month (resetting on the 1st, UTC) and 100 MB of storage. Once the month's credits are spent, every request except GET /usage is refused with 402 credits-exhausted until they reset; a write that would go past 100 MB is refused with 413 storage-limit-exceeded. Paid plans are coming soon.
Usage is attributed to the API key that spent it, and appears on your dashboard and through the /usage endpoints shortly after each request, rather than in the request's own response.