API authentication

Qassandra exposes a small HTTP API. Programmatic requests authenticate using a per-app API key sent as a Bearer token.

API keys

Each app has at most one API key. Keys are scoped to a single app — a key for my-staging-app cannot trigger checks on my-prod-app.

Keys look like this and start with the qsk_ prefix:

qsk_a1b2c3d4e5f6...

Generating a key

  1. Open App settings → API key.
  2. Click Generate API key. The full key is shown once — copy it immediately into your secret manager.
  3. The settings page will keep showing the key while the page is open, but you should rely on your own secret store going forward.
!

Store the key securely

Treat the key like a password. Anyone with it can trigger checks against your app. Store it in your CI's secret store (GitHub Actions Secrets, Vercel env vars, etc.) — never commit it to a repository.

Rotating a key

Click Generate API key again. The new key replaces the old one immediately and the old key stops working. There's no overlap window, so plan to update your CI secrets in the same change window.

Removing a key

Click Remove API key. After removal, programmatic triggers will fail with a 401 until you generate a new one.

Sending the key

Pass the key in the Authorization header using the Bearer scheme:

curl -X POST https://qassandra.com/api/apps/APP_ID/trigger \
  -H "Authorization: Bearer qsk_..." \
  -H "Content-Type: application/json" \
  -d '{}'

Two authentication modes

Most API routes accept either of two authentication modes:

  • Bearer token — the qsk_… key in the Authorization header. Use this for CI, webhooks, and any other server-to-server call.
  • Session cookie — when you're logged into the dashboard, the same endpoints accept your Supabase session cookie. This is what the UI uses internally.

If neither is present, the API responds with 401 Unauthorized and an explanation of which header to add.

Where to find APP_ID

Open any app in the dashboard. The URL looks like /apps/abc12345-…. Either the long UUID or the short alias from the URL works in API calls.