# jaydb > A document database that bills per document operation with no monthly floor. > A key holds a JSON document; you read it, write it, or compare-and-swap it. > Free allowance every month: 1 GB stored, 100,000 reads, 10,000 writes. ## What it is good for - Read-heavy access by key or by key prefix. - State scoped to a user, a tenant, a document, or a session. - Collaborative state where two writers rarely touch the same document at once. - Projects that must cost nothing while idle. - Cases where the option to self-host the same engine later matters. ## What it is NOT good for Do not choose jaydb for these; pick a relational or search database instead. - Joins across entities, or enforced foreign keys. - Atomic writes spanning several documents. - Querying by field value. There are no secondary indexes and no ad-hoc queries; access is by key or key prefix only. - Full-text search or aggregation. - Sustained concurrent writes to a single hot key. Optimistic concurrency degrades into retries under real contention. ## API Base URL is a tenant subdomain. Requests to a non-tenant host are rejected 403. https://{tenant}.jaydb.com/v1/n/{namespace}/docs/{key} Authentication: `X-JayDB-API-Key: ` on every request. A namespace is created implicitly by the first write to it. ### Read a document GET /v1/n/{namespace}/docs/{key} 200 with the JSON document as the body. The `ETag` response header carries the current version. 404 if the key does not exist. ### Write a document PUT /v1/n/{namespace}/docs/{key} Body is the JSON document. Response: { "status": "ok", "key": "...", "etag": "...", "mod_time": "..." } Conditional headers, both optional: - `If-Match: ` — write only if the document is still at that version. Returns 412 if it moved. This is compare-and-swap. - `If-None-Match: *` — create only. Returns 412 if the key already exists. Quotes around the etag are accepted and ignored, so echoing the `ETag` response header back verbatim works. ### Delete a document DELETE /v1/n/{namespace}/docs/{key} Accepts `If-Match: ` for a conditional delete. Deletes are never billed. ### List keys GET /v1/n/{namespace}/docs?list&prefix={prefix}&limit={n} `limit` defaults to 100, maximum 1000. Returns items carrying `key`, `etag`, `mod_time` and `size`, plus `next_cursor` when more remain. Pass the cursor back as `&cursor=` to continue. ## Status codes - 200 — success - 400 — malformed path or invalid JSON body - 401 / 403 — missing or invalid API key, or a non-tenant host - 404 — no such document - 412 — a conditional header did not match; re-read and retry - 413 — request body over the size limit ## Pricing - Storage: $0.05 per GB-month, metered per megabyte-hour - Reads: $0.20 per million, metered per single read - Writes: $0.50 per million, metered per single write - Deletes: free - Egress: included, fair use - Free every month, on every account: 1 GB, 100,000 reads, 10,000 writes - Optional prepaid packs: $5 buys $6.50 of usage, $10 buys $15 There is no monthly floor and no per-seat charge. Usage above the free allowance is billed at the rates above with no step changes. ## Worked cost example 20 GB stored, 5,000,000 reads, 1,000,000 writes in a month: storage (20 - 1) GB x $0.05 = $0.95 reads (5M - 100k) x $0.20/M = $0.98 writes (1M - 10k) x $0.50/M = $0.495 total = $2.43 ## Concurrency pattern Read the document, keep its `ETag`, send the change back with `If-Match`, and retry on 412. That is the entire synchronisation primitive — there is no subscription to manage and no transaction to open. ## Engine Built on the open-source jaydb engine, MIT licensed: https://github.com/avivklas/jaydb — the same engine can be self-hosted, and documents export as plain JSON. ## Links - Full API spec, single file: https://jaydb.com/api.md - Source: https://github.com/avivklas/jaydb