Reference

REST API

Plain HTTP over https://quiveros.ai/api/*. Authenticate every request with a qvr_ workspace key. Reads are GET; writes are POST/PATCH/DELETE and need a write-capable key.

auth
Authorization: Bearer qvr_xxxxxxxxxxxx

Files

Create & list

POST/api/files
write

Create a file of a configured type and populate its data in one call.

ParameterTypeNotes
typestring · requiredA file type from the workspace config (e.g. "score").
titlestringDefaults to an auto title if omitted.
dataobjectField id → value. Use an array for multi-value fields.
parent{ id, field }Append the new file to a parent file’s list field (a sub-item).
statusstringCreate directly in this status of the type’s workflow (recorded like a status move). An unknown id returns 422 listing the valid ones.
forcebooleanSkip dedupe when the type de-duplicates on create.
idempotency_keystringOr the Idempotency-Key header (1-200 printable characters). A repeat with the same key in the same workspace returns the ORIGINAL file with replayed: true instead of creating another — so a create whose response was lost can be retried safely.
request → response
curl -X POST https://quiveros.ai/api/files \
  -H "Authorization: Bearer $QUIVER_KEY" -H "content-type: application/json" \
  -d '{"type":"score","title":"Alice · 250","data":{"player":"Alice","value":250}}'

{ "ok": true, "file": { "id": "cmq…", "type": "score", "title": "Alice · 250" } }

Types that de-duplicate on create won’t spawn a near-duplicate: a confident match returns the existing file with reused: true (your fields merged in — empty fields filled, lists unioned, conflicts reported); several plausible matches return 409 with candidates. Pass force: true to create anyway.

A create is atomic: the file, its fields, its status and the parent link land together or not at all. If a step fails, what was written is rolled back and the response (500) says which step failed and that nothing was saved, with rolled_back: true and retryable: true.

POST/api/files/batch
write

Create many files in one request: up to 200 items, each exactly like a POST /api/files body, applied in order.

ParameterTypeNotes
itemsarray · requiredCreate bodies (type, title, data, parent, status, force, idempotency_key). At most 200 (413 above).
atomicbooleanAll or nothing: the first failure rolls back every file this request created and skips the rest. Default: every item is attempted and reported.
request → response
curl -X POST https://quiveros.ai/api/files/batch \
  -H "Authorization: Bearer $QUIVER_KEY" -H "content-type: application/json" \
  -d '{"items":[{"type":"task","title":"A","parent":{"id":"$P","field":"tasks"},"idempotency_key":"run1:0"},
               {"type":"task","title":"B","status":"nope"}]}'

{ "ok": false, "atomic": false, "created": 1, "failed": 1, "results": [
  { "index": 0, "ok": true, "status": 200, "file": { "id": "cmq…", "type": "task", "title": "A" } },
  { "index": 1, "ok": false, "status": 422, "error": "Unknown status 'nope' for type 'task'. Valid statuses: …" } ] }
GET/api/files
read

List files, optionally filtered. Rows carry each type's summary fields by default; ?fields= overrides the projection.

ParameterTypeNotes
typestringFilter to one file type. Required when any filter/sort param below is used.
statusstring · repeatableFilter by status id(s): ?status=playing&status=ended
qstringTitle substring search.
limitnumberMax rows. Default 100, capped at 1000.
parentfile idOnly the files linked under this parent through its list link fields, in link order (response gains total and parent). Must be visible to you; children you can’t see are omitted. Composes with type, status, q, limit, offset, fields.
parent_fieldfield idWith parent: only this link field.
fieldscsvData fields to include as KPIs: ?fields=value,category. OMITTED: each row carries its type’s summary_fields (what its list views show; a type without summary_fields falls back to its first three data fields). EMPTY (?fields=): status-only rows. Rows never include non-requested fields — fetch a file’s /kpis for everything.
response
curl "https://quiveros.ai/api/files?type=score&fields=player,value&limit=50" \
  -H "Authorization: Bearer $QUIVER_KEY"

{ "files": [
  { "id": "cmq…", "title": "Alice · 250", "type": "score", "status": "ended",
    "kpis": [
      { "pathKey": "status", "stringValue": "ended" },
      { "pathKey": "dataFields.player", "stringValue": "Alice" },
      { "pathKey": "dataFields.value", "numericValue": 250 } ] } ] }
GET/api/files (filtered query)
read

Adding any of the params below switches the list into a real query: filter by data-field value, by last-update time, sort, and page. Requires type; the response gains a total count for paging. The other list params (status, q, fields, limit) still apply.

ParameterTypeNotes
data.<field>string · repeatableEquality match on a data-field value: ?data.player=Alice. Repeat for AND: &data.daily_date=2026-07-01. Field ids are validated against the type’s config.
updatedAt_gteISO or epoch-msOnly files updated at/after this instant: ?updatedAt_gte=2026-07-01T00:00:00Z (or 1782172800000).
updatedAt_lteISO or epoch-msOnly files updated at/before this instant.
sortkey:dirupdatedAt | createdAt | title, each :asc or :desc. Default updatedAt:desc. File columns only (no data-field sort).
offsetnumberSkip N rows (with limit = paging). Default 0.
request → response
curl "https://quiveros.ai/api/files?type=score&data.player=Alice&sort=updatedAt:desc&limit=20&offset=0" \
  -H "Authorization: Bearer $QUIVER_KEY"

{ "files": [ { "id": "cmq…", "title": "Alice · 250", … } ], "total": 34 }

Files

Read, update & delete a file

GET/api/files/:id
read

Fetch one file with its full data and KPIs.

response
{ "ok": true, "file": {
  "id": "cmq…", "title": "Alice · 250", "type": "score", "status": "ended",
  "data": "{\"player\":\"Alice\",\"value\":250}",
  "kpis": [ … ] } }
POST/api/files/:id/data
write

Set one or more data fields (and optionally the title). Writes through the real KPI path, so metrics update immediately.

ParameterTypeNotes
fieldsobjectField id → new value. Batch-applied in one mutation.
fieldId + valuestring + anySingle-field alternative to fields: {"fieldId":"value","value":600}.
titlestringOptionally rename the file.
add / remove{ field: value | [values] }Add or remove single elements of multi-valued fields (incl. file links), against the current list — concurrent adds all land. Link targets must be files you can see. Removing a link never deletes the linked file, even from a field that owns its children (the response notes it). One of fields, title, add, remove is required.
request → response
curl -X POST https://quiveros.ai/api/files/$ID/data \
  -H "Authorization: Bearer $QUIVER_KEY" -H "content-type: application/json" \
  -d '{"fields":{"value":600,"category":"hard"},"title":"Alice · 600"}'

{ "ok": true, "fields": { "value": 600, "category": "hard" }, "title": "Alice · 600",
  "sideEffects": [ { "fieldId": "score_delta", "name": "Score Δ", "value": 350 } ] }

Writes are CRDT-safe: they merge with concurrent live edits instead of clobbering them, and metrics update immediately. Unknown/uneditable fields come back in skipped; computed fields the write rippled into come back in sideEffects. If nothing changes, the call is a no-op and returns 400 “No fields applied”.

POST/api/files/:id/status
write

Move a file to a status in its workflow (e.g. playing → ended). PATCH works too; body can be JSON ({status}) or form-encoded (status=…). An id that isn’t in the type’s workflow returns 422.

request
curl -X POST https://quiveros.ai/api/files/$ID/status \
  -H "Authorization: Bearer $QUIVER_KEY" -H "content-type: application/json" \
  -d '{"status":"ended"}'

{ "ok": true, "fileId": "cmq…", "status": "ended", "sideEffects": [] }
DELETE/api/files/:id
write

Permanently delete a file.

request
curl -X DELETE https://quiveros.ai/api/files/$ID \
  -H "Authorization: Bearer $QUIVER_KEY"
# → { "ok": true }

Metrics

Read computed values

You declare metrics in config (count, sum, max, grouped breakdowns, derived). The engine computes them — you just read the value.
GET/api/metrics
read

With ?id= returns one metric (including its grouped breakdown); without, returns a snapshot of all metrics + a catalog. Key-only: this endpoint authenticates by qvr_ bearer key, never a session cookie.

ParameterTypeNotes
idstringA metric id from config. Omit for the full snapshot. The window/filter params below apply to single-metric reads.
periodstringRequest-time window: lifetime · 2026 · q1-2026 · w22-2026 · d2026-07-02. Omit to keep the metric’s own default window.
from / toYYYY-MM-DDCustom date range (inclusive), instead of period.
dateYYYY-MM-DDOne-day convenience — expands to from=to=date. Handy for daily boards.
tzIANA zoneMakes day windows follow local midnight: ?tz=America/Los_Angeles.
limitnumberTop-N rows of a grouped metric (leaderboards). Capped at 1000; omit to use the metric’s configured limit.
data.<field>string · repeatableEquality filter on a data-field value, applied at request time: ?data.daily_date=2026-07-01. Repeat for AND. Field ids validated against config.
daily leaderboard — one metric, any day
curl "https://quiveros.ai/api/metrics?id=top_players_daily&period=lifetime&data.daily_date=2026-07-01" \
  -H "Authorization: Bearer $QUIVER_KEY"

{ "metric": {
  "id": "top_players_daily", "metric": 250,
  "breakdown": [
    { "key": "Alice", "value": 250 },
    { "key": "Bob",   "value": 175 } ] } }

One configured metric serves every slice: the window params re-scope it per request (no per-day or per-week metric definitions), and data.<field> filters do a plain value match — so a daily board keyed by a date field avoids time-zone drift entirely.

Recipes

Common queries

Everything below is one GET — no fetch-everything-and-reduce client side.
GETDaily leaderboard by date
read

A grouped metric filtered to one day’s files by a date field.

request
curl "https://quiveros.ai/api/metrics?id=top_players_daily&period=lifetime&data.daily_date=2026-07-01&limit=10" \
  -H "Authorization: Bearer $QUIVER_KEY"
GETMy records
read

All of one player’s files, newest first, with the values inlined.

request
curl "https://quiveros.ai/api/files?type=score&data.player=Alice&sort=createdAt:desc&fields=value,daily_date&limit=25" \
  -H "Authorization: Bearer $QUIVER_KEY"
GETPresence — who’s on right now
read

Files in a live status that were touched in the last two minutes (epoch-ms works too).

request
NOW=$(($(date +%s) * 1000)); SINCE=$((NOW - 120000))
curl "https://quiveros.ai/api/files?type=score&status=playing&updatedAt_gte=$SINCE" \
  -H "Authorization: Bearer $QUIVER_KEY"
GETPoint lookup by several fields
read

Repeat data.<field> to AND conditions — e.g. one player’s entry for one day.

request
curl "https://quiveros.ai/api/files?type=score&data.player=Alice&data.daily_date=2026-07-01&fields=value" \
  -H "Authorization: Bearer $QUIVER_KEY"

Discovery

Search, activity & orientation

GET/api/files/search
read

Free-text recall over titles and data-field values.

response
curl "https://quiveros.ai/api/files/search?q=Alice&type=score&limit=5" \
  -H "Authorization: Bearer $QUIVER_KEY"
# → { "results": [ { "id": "…", "title": "Alice · 250", "type": "score", "status": "ended" } ] }
GET/api/activity
read

Recent changes across the workspace (field, value, actor, time).

request
curl "https://quiveros.ai/api/activity?limit=20" -H "Authorization: Bearer $QUIVER_KEY"
GET/api/orient
read

A one-call bootstrap bundle — purpose, singletons, active files (children rolled up under their active parent: status counts plus the open ones with their summary fields; a file linked from an active parent is listed there instead of again at the top level — active_linked says which), per-type counts, recent activity. Built for agents starting cold.

request
curl "https://quiveros.ai/api/orient" -H "Authorization: Bearer $QUIVER_KEY"

Workspace

Inspect the workspace & its config

GET/api/workspace
read

Workspace metadata; ?include=config returns the full schema (types, fields, statuses, metrics, views).

ParameterTypeNotes
includestringconfig · apikeys · secrets · variables
response
curl "https://quiveros.ai/api/workspace" -H "Authorization: Bearer $QUIVER_KEY"
# → { "workspace": { "id": "…", "name": "Quiver Archer", "configId": "personal.leaderboard", "userCount": 1 } }