LizzyDocs
Docs navigation Authentication

Setup · Security

Authenticate server-side requests

Create a test token, store it on the server, verify its identity and scopes, and rotate it without interrupting the integration.

Create a test token

Start in the Lizzy token dashboard at https://lizzy.albinilabs.com/tokens. An owner or admin chooses the environment and scopes, creates the token, and copies the secret once. The later token detail and list responses expose only a masked key.

  1. 1

    Name the workload, not the person

    Use a name such as support-distill-staging so an operator can identify the owner and deployment without seeing the secret.

  2. 2

    Choose test mode

    Token environment is immutable. Create a separate live token later instead of trying to promote the test credential.

  3. 3

    Grant only the required scopes

    The first integration normally needs distill:read anddistill:write. The proxy also requires distill:write because it can capture calls.

  4. 4

    Copy and store the secret immediately

    Put it in your local environment for development and in a managed secret for deployment. If a programmatic create response is lost, first retry the exact body with its original idempotency key. If that replay is unavailable, create a replacement; ordinary token reads cannot reveal the old secret.

jsonprogrammatic token body
{
  "name": "support-distill-staging",
  "environment": "test",
  "scopes": ["distill:read", "distill:write"],
  "expires_at": "2026-11-15T00:00:00Z"
}
jsonexample 201 response; secret appears once
{
  "id": "tok_01K2ZXQ8M4Y7V6R5T3S9N2P1B1",
  "object": "api_token",
  "secret": "<one-time token returned here>",
  "name": "support-distill-staging",
  "environment": "test",
  "masked_key": "lz_test_abcd••••••••",
  "scopes": ["distill:read", "distill:write"],
  "status": "active",
  "disabled": false,
  "expires_at": "2026-11-15T00:00:00Z",
  "credit_limit": null,
  "allowed_ips": null,
  "last_used_at": null,
  "created_by": { "type": "user", "id": "usr_01K2ZXQ8M4Y7V6R5T3S9N2P1C2" },
  "created_at": "2026-08-15T10:00:00Z",
  "updated_at": "2026-08-15T10:00:00Z"
}

Store the token outside source code

Use two environment variables: one for the versioned base URL and one for the secret. Keeping the base configurable makes local and deployed diagnostics use the same code. Keeping the token separate prevents an innocuous URL log from exposing credentials.

bashdevelopment shell
export LIZZY_API_BASE="https://lizzy.albinilabs.com/v1"
export LIZZY_API_TOKEN="<lizzy-test-token>"


# Confirm variables exist without printing the secret.
test -n "$LIZZY_API_TOKEN" || { echo "LIZZY_API_TOKEN is missing" >&2; exit 1; }
case "$LIZZY_API_TOKEN" in
  lz_test_*) echo "Lizzy test credential configured" ;;
  *) echo "Expected a test credential" >&2; exit 1 ;;
esac

Redact Authorization, environment variables, request configuration, and exception objects in logs. You can log the token ID, masked key, workspace ID, environment, scopes, resource ID, status, and request ID.

Verify identity at startup

Token prefixes are a useful local guard, but GET /v1/whoami is authoritative. Make a startup check in deployment validation. Confirm the exact workspace, test/live environment, and required scopes before permitting writes.

cURLexample
curl --fail-with-body --silent --show-error \
  "$LIZZY_API_BASE/whoami" \
  -H "Authorization: Bearer $LIZZY_API_TOKEN"
GET/v1/whoami

A token response includes credential.type: "api_token", token ID, name, environment, scopes, livemode, workspace, and dated API version. A dashboard session instead reports a user ID and role.

Use separate tokens for separate jobs

full_access satisfies API scope checks, but it is a poor default for long-lived application workers. Separate experiment execution, webhook management, event reading, and token administration so a compromise has a smaller blast radius.

textcommon workload-to-scope mapping
Run a Distill workflow     distill:read, distill:write
Proxy and capture traffic    distill:write
Read event records           events:read
Inspect webhook delivery     webhooks:read
Manage webhook endpoints     webhooks:read, webhooks:write
Provision or rotate tokens   tokens:read, tokens:write
Broad API administration     full_access (avoid for routine workers)

Token creation accepts an optional allowed_ips CIDR list, and token responses include last_used_at. In the current authentication implementation the CIDR list is stored but not enforced, and last-used time is not an authoritative usage audit. Use network controls and audit logs you control until those fields become enforcement guarantees.

Rotate tokens with an overlap window

  1. 1
    Create replacement

    Use the same environment and least-privilege scopes. Give it a new workload version in the name.

  2. 2
    Store and verify

    Save the one-time secret, then call whoami and one read endpoint with the new token.

  3. 3
    Deploy

    Update the secret reference, roll out gradually, and monitor invalid_token and insufficient_scope errors.

  4. 4
    Disable old token

    Disable first for a reversible observation window.

  5. 5
    Revoke old token

    After every instance uses the replacement, revoke from another credential or the dashboard.

bashcreate a replacement with an admin token
curl --fail-with-body -X POST "$LIZZY_API_BASE/tokens" \
  -H "Authorization: Bearer $LIZZY_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: token:rotate:support-distill:2026-08" \
  -d '{
    "name":"support-distill-staging-v2",
    "environment":"test",
    "scopes":["distill:read","distill:write"],
    "expires_at":"2026-11-15T00:00:00Z"
  }'


# After the new token is deployed, disable the old token during the rollback window.
curl --fail-with-body -X POST \
  "$LIZZY_API_BASE/tokens/tok_OLD_TOKEN_ID/disable" \
  -H "Authorization: Bearer $LIZZY_API_TOKEN"

Resolve authentication failures first

Authentication failures happen before Lizzy creates a Distill resource. Keep the HTTP status, structured error code, and X-Request-Id. Do not print the bearer token while debugging.

textauthentication recovery map
401 invalid_token
  The secret is unknown or malformed. Check secret injection and whitespace; replace if lost.


401 token_disabled
  The token was disabled or revoked. Confirm its status with a separate admin credential.


401 token_expired
  The expiry passed. Create or activate an appropriate replacement; do not extend blindly.


403 insufficient_scope
  Authentication worked, but the token lacks the endpoint scope. Add only the named scope or
  use the correctly scoped workload credential.


403 insufficient_role
  The route requires an owner/admin dashboard session. An API token, including full_access,
  cannot cross a dashboard-only Pilot boundary.


404 resource_not_found-style code
  Verify workspace and test/live mode with whoami. Cross-workspace and cross-mode resources are
  intentionally not revealed.

Once authentication is fixed, retry a read normally. For a mutation that may have reached the server, reuse the original Idempotency-Key and identical body. Changing credentials does not change the logical operation you were attempting.