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
Name the workload, not the person
Use a name such as
support-distill-stagingso an operator can identify the owner and deployment without seeing the secret. - 2
Choose test mode
Token environment is immutable. Create a separate live token later instead of trying to promote the test credential.
- 3
Grant only the required scopes
The first integration normally needs
distill:readanddistill:write. The proxy also requiresdistill:writebecause it can capture calls. - 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.
{
"name": "support-distill-staging",
"environment": "test",
"scopes": ["distill:read", "distill:write"],
"expires_at": "2026-11-15T00:00:00Z"
}
{
"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.
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.
curl --fail-with-body --silent --show-error \
"$LIZZY_API_BASE/whoami" \
-H "Authorization: Bearer $LIZZY_API_TOKEN"
/v1/whoamiA 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.
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
- 1Create replacement
Use the same environment and least-privilege scopes. Give it a new workload version in the name.
- 2Store and verify
Save the one-time secret, then call whoami and one read endpoint with the new token.
- 3Deploy
Update the secret reference, roll out gradually, and monitor invalid_token and insufficient_scope errors.
- 4Disable old token
Disable first for a reversible observation window.
- 5Revoke old token
After every instance uses the replacement, revoke from another credential or the dashboard.
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.
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.