LizzyDocs
Docs navigation API reference

Reference

API conventions and contracts

Reference the versioned JSON API, authentication headers, cursor pagination, idempotency rules, asynchronous resources, and operation metadata.

Use the deployed origin, then choose a surface

The production API lives at https://lizzy.albinilabs.com/v1. The proxy is a base-URL swap for an OpenAI-compatible client; the rest of the API manages sources, datasets, rewards, runs, reports, deployments, events, and webhooks.

REST APIhttps://lizzy.albinilabs.com/v1
OpenAI proxyhttps://lizzy.albinilabs.com/v1/proxy
OpenAPIhttps://lizzy.albinilabs.com/v1/openapi.json
Healthhttps://lizzy.albinilabs.com/healthz
Local developmenthttp://localhost:8080/v1
POST/v1/proxy/chat/completions

Send an OpenAI-compatible request through a configured source, or serve a deployment by using model: "lz:<alias>".

Authenticate server-side, then ask who you are

Send a secret API token as Authorization: Bearer <token>. Live tokens begin with lz_live_; test tokens begin with lz_test_. Each token belongs to one workspace, one mode, and one set of scopes. The full secret appears only in the token-creation response, so store it in a secret manager immediately.

Start every integration with GET /v1/whoami. It verifies the credential and makes workspace, environment, scopes, and the dated API version visible before any write.

cURLexample
export LIZZY_ORIGIN="https://lizzy.albinilabs.com"
: "${LIZZY_API_TOKEN:?Inject an lz_test_ token from your secret manager}"


curl --fail-with-body --silent --show-error --max-time 15 \
  -H "Authorization: Bearer $LIZZY_API_TOKEN" \
  "$LIZZY_ORIGIN/v1/whoami"
jsonexample response
{
  "object": "whoami",
  "workspace": {
    "id": "ws_example",
    "name": "Example workspace",
    "plan": "pro"
  },
  "credential": {
    "type": "api_token",
    "id": "tok_example",
    "name": "Experiment runner",
    "environment": "test",
    "scopes": ["distill:read", "distill:write", "events:read"]
  },
  "livemode": false,
  "api_version": "2026-07-01"
}

A token’s mode is a data boundary

Token mode is fixed when the token is created. A test token reads and writes test-mode resources; a live token reads and writes live resources. Passing livemode=trueon a list request cannot make a test token cross that boundary, and the dashboard-onlyLizzy-Mode: test header does not change an API token.

Recommended first

Test token

Separate test data, no ledger charge, and every Distill run is forced to dry-run.

Prefix: lz_test_
Production

Live token

Sees live resources and can trigger billable work when its scopes allow it.

Prefix: lz_live_
Separate concept

Product sandbox

Dedicated sandbox routes and dashboard test conversations have their own semantics.

Do not infer mode from the word sandbox

Choose scopes by job

full_access passes every scope check, but a long-lived automation should carry only what it uses. Reads and writes are separate for Distill, events, webhooks, tokens, billing, agents, conversations, sources, channels, and workspace administration.

Experiment runnerdistill:read, distill:write
Event consumerevents:read, plus webhooks:read for delivery diagnosis
Webhook managerwebhooks:read, webhooks:write
Token bootstraptokens:read, tokens:write; keep this out of routine workers
All accessfull_access; reserve for tightly controlled administration

Preserve the headers that carry intent

AuthorizationRequired on private routes: Bearer lz_test_… or Bearer lz_live_….
Content-TypeUse application/json for JSON writes; uploads document their binary type separately.
X-Request-IdReturned on every control-plane response. Keep it for diagnostics; on an error it matches error.request_id.
Idempotency-KeyIdentifies one logical creating write. Required for uploads, runs, and deployments.
X-Lizzy-SourceSelects the configured upstream source for an OpenAI proxy request.
X-Lizzy-TagsAdds comma-separated capture labels; at most 16 tags.
X-Lizzy-External-IdCarries your stable join key for capture feedback and investigation.
X-Lizzy-Call-IdReturned by the proxy as Lizzy’s correlation ID for the captured call.
X-Lizzy-Served-ByReports whether the proxy used upstream, student, shadow, or upstream fallback.

One key means one logical write for 24 hours

Lizzy hashes the exact request-body bytes. The same key and byte-identical body replay the stored status and JSON body with Idempotent-Replayed: true. The same key with different bytes returns 409 idempotency_key_reused; a duplicate that overlaps an unfinished request returns 409 idempotency_key_in_flight. A failed operation releases its reservation so the original request can be retried.

cURLexample
request_body='{"name":"support-quality","description":"Preserve resolution quality"}'
: "${IDEMPOTENCY_KEY:=$(uuidgen)}"


curl --fail-with-body --silent --show-error --max-time 20 \
  -X POST "https://lizzy.albinilabs.com/v1/distill/loops" \
  -H "Authorization: Bearer $LIZZY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data-binary "$request_body"


# Unknown transport outcome? Run the same curl command with the same two variables.
Required nowPOST /distill/uploads, POST /distill/runs, and POST /distill/deployments.
Accepted elsewhereMany creating and sending POSTs honor a key but do not reject an omitted one.
RecommendedSend a fresh, stable key for every logical create or start operation.

Walk cursor pages until has_more is false

List responses use data, has_more, andnext_cursor. limit defaults to 20; values above 100 are clamped to 100, while values below 1 fail validation. Treat cursors as opaque and URL-encode them.

jsonlist envelope
{
  "data": [{ "id": "evt_example", "object": "event" }],
  "has_more": true,
  "next_cursor": "eyJ0IjoiMjAyNi0wOC0xNVQxNzozMDowMCswMDowMCIsImlkIjoiZXZ0X2V4YW1wbGUifQ"
}
cURLexample
first_page=$(curl --fail-with-body --silent --show-error --get \
  -H "Authorization: Bearer $LIZZY_API_TOKEN" \
  --data-urlencode "limit=20" \
  "https://lizzy.albinilabs.com/v1/events")


printf '%s' "$first_page" | jq '.data'
cursor=$(printf '%s' "$first_page" | jq -r '.next_cursor // empty')


if [ -n "$cursor" ]; then
  curl --fail-with-body --silent --show-error --get \
    -H "Authorization: Bearer $LIZZY_API_TOKEN" \
    --data-urlencode "limit=20" \
    --data-urlencode "cursor=$cursor" \
    "https://lizzy.albinilabs.com/v1/events" | jq .
fi

Persist asynchronous resource IDs before you poll

Uploads, connector pulls, dataset versions, runs, and deployments can outlive the request that created or discovered them. Store the returned ID, poll its GET endpoint with a capped delay and deadline, and stop only on that resource’s documented terminal state.

Client timeoutEnds the local watch, not the server-side operation.
Known resource IDResume its GET endpoint; do not submit a replacement create request.
Terminal stateStop on the endpoint’s closed status set, then return the final object to the operator.

Use the enriched Distill contract for agent discovery

The versioned OpenAPI 3.1 document inventories the public Distill surface and enriches it with operation IDs, request models, workflow stages, prerequisites, async terminal states, recovery notes, human-only boundaries, and transport guarantees. Internal control-plane routes are removed.

Open /v1/openapi.json
bashinspect without credentials
curl --fail --silent --show-error --max-time 20 \
  "https://lizzy.albinilabs.com/v1/openapi.json" \
  | jq '{openapi, info, servers, distill_run: .paths["/v1/distill/runs"].post}'
AuthenticationAuthenticated operations declare the BearerAuth HTTP security scheme. The shared-report capability URL explicitly declares no bearer requirement; possession of its revocable share token is the authority.
Idempotencyx-lizzy-idempotency-supported, x-lizzy-idempotency-required, and the header’s required flag distinguish optional from mandatory keys exactly.
Response headersSuccesses and errors document X-Request-Id; idempotent mutations also document Idempotent-Replayed.
Validation and errorsValidation uses the Lizzy HTTP 400 envelope without a stale 422. Proxy errors are described as either a Lizzy envelope or a pass-through upstream response.