Docs/API keys

API keys

Manage team-scoped API keys programmatically or from the dashboard. Keys authenticate with the Authorization: Bearer header.

Create a key

POST/keys

Generates a new key for a team and environment. The response includes the plaintext secret — store it immediately, since it can't be retrieved again.

FieldDescription
teamIdThe UUID of the team this key belongs to.
nameA human-readable label for the key, shown in the dashboard.
envThe environment the key is scoped to: live or test.
embedOriginsOptional. CSP origins allowed to embed this key's agent viewer in an iframe, one per array entry (e.g. https://acme.odoo.com). Empty or omitted means no third-party origin may embed it — only the SeeItLive dashboard can.
expiresAtOptional. ISO 8601 date-time after which the key stops working. Omit for a key that never expires.
curl -X POST https://api.seeitlive.io/v1/keys \
  -H "Authorization: Bearer <dashboard-jwt>" \
  -H "Content-Type: application/json" \
  -d '{ "teamId": "<uuid>", "name": "Server key", "env": "live", "embedOrigins": ["https://acme.odoo.com"] }'
json
{
  "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "name": "Server key",
  "env": "live",
  "prefix": "sil_live_ab12cd",
  "secret": "sil_live_ab12cdxxxxxxxxxxxxxxxxxxxxxxxx"
}
Shown once
The secret field is returned only on creation and never again.
Creating and revoking keys requires the manage_keys permission on the team; listing keys only requires view_team.

List keys

GET/keys?teamId=<uuid>

Returns the active (non-revoked) keys for a team. The secret is never included — only the prefix, which is enough to identify a key in the dashboard or logs.

json
[
  {
    "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
    "name": "Server key",
    "env": "live",
    "prefix": "sil_live_ab12cd",
    "embedOrigins": ["https://acme.odoo.com"],
    "lastUsedAt": "2026-07-01T12:03:44.000Z",
    "createdAt": "2026-06-15T09:12:00.000Z"
  }
]

Update a key

PATCH/keys/:id

Partially updates a key. Only the fields you include are changed; omitted fields are left as-is.

FieldDescription
nameA new label for the key.
allowedIpsThe unified allowed-sources list: IPs, CIDR ranges, or hostnames, one per array entry. Replaces the existing list.
embedOriginsThe origins allowed to embed this key's agent viewer, same shape as on create. Replaces the existing list; an empty array removes all third-party embedding.
expiresAtISO 8601 date-time, or null to clear an existing expiry.
curl -X PATCH https://api.seeitlive.io/v1/keys/d290f1ee-6c54-4b01-90e6-d701748f0851 \
  -H "Authorization: Bearer <dashboard-jwt>" \
  -H "Content-Type: application/json" \
  -d '{ "allowedIps": ["10.0.0.0/8 # office VPN"], "embedOrigins": ["https://acme.odoo.com # crm"], "expiresAt": "2026-12-31T00:00:00.000Z" }'
json
{
  "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "name": "Server key",
  "env": "live",
  "prefix": "sil_live_ab12cd",
  "allowedIps": ["10.0.0.0/8 # office VPN"],
  "embedOrigins": ["https://acme.odoo.com # crm"],
  "expiresAt": "2026-12-31T00:00:00.000Z",
  "lastUsedAt": "2026-07-01T12:03:44.000Z",
  "createdAt": "2026-06-15T09:12:00.000Z"
}

Rotate a key

POST/keys/:id/rotate

Issues a new secret for an existing key and invalidates the old one immediately. The key keeps its id, name, environment and settings, so allowlists, signing and TOTP survive the rotation. The plaintext secret is shown once, exactly like creation.

json
{
  "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "name": "Server key",
  "env": "live",
  "prefix": "sil_live_ef34gh",
  "secret": "sil_live_ef34ghxxxxxxxxxxxxxxxxxxxxxxxx"
}

Set the default key

POST/keys/:id/default

Marks one key as the team's default. The dashboard uses it when a session is created from the UI, so those sessions land in the default key's environment and are attributed to it. Setting a new default clears the previous one; a revoked key cannot be made default.

json
{ "ok": true }

Revoke a key

DELETE/keys/:id

Immediately disables a key. In-flight requests using it start failing right away, and it stops appearing in the list response.

json
{ "ok": true }

Request signing

Signing adds HMAC verification on top of the bearer key. See the signing contract in the authentication guide for exactly how to compute and send the signature.

Enable signing

POST/keys/:id/signing/enable

Turns on signing for a key and returns the signing secret. The secret is shown once — store it immediately.

json
{ "signingSecret": "3fa1e2d0c9b84a5b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081920a3b4c5" }

Rotate the signing secret

POST/keys/:id/signing/rotate

Issues a new signing secret for a key, invalidating the previous one. Also shown once.

json
{ "signingSecret": "8c9d0e1f2a3b4c5d6e7f8091a2b3c4d53fa1e2d0c9b84a5b6e7f8091920a3b4c" }

Disable signing

POST/keys/:id/signing/disable

Turns off signing for a key. Requests to it no longer need a signature.

json
{ "ok": true }

Per-key TOTP

An opt-in second factor for a key: once enabled, every request made with it must also carry a valid rotating code in an X-SeeItLive-Totp header. Useful for keys held by a human operator rather than a server.

Enable

POST/keys/:id/totp/enable

Returns the seed and an otpauth URL for an authenticator app. Both are shown once — the seed is never readable again.

json
{
  "secret": "JBSWY3DPEHPK3PXP",
  "otpauthUrl": "otpauth://totp/SeeItLive:key%3Asil_live_ab12cd?secret=JBSWY3DPEHPK3PXP&issuer=SeeItLive"
}

From then on, requests with that key must include the current 6-digit code; without it they fail with 401.

curl https://api.seeitlive.io/v1/sessions/<id>/status \
  -H "Authorization: Bearer sil_live_ab12cdxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "X-SeeItLive-Totp: 418205"

Disable

POST/keys/:id/totp/disable

Turns the second factor off and discards the seed. Requests with the key stop requiring a code.

json
{ "ok": true }

Client certificate pinning (mTLS)

Pins a key to one client certificate. Once pinned, a request is accepted only when your ingress forwards the caller's certificate as a URL-encoded PEM in an X-Ssl-Client-Cert header and its SHA-256 fingerprint matches the pinned one.

Pin a certificate

POST/keys/:id/cert/upload

Send the certificate as PEM in a pem field. The response returns the SHA-256 fingerprint that will be enforced.

curl -X POST https://api.seeitlive.io/v1/keys/d290f1ee-6c54-4b01-90e6-d701748f0851/cert/upload \
  -H "Authorization: Bearer <dashboard-jwt>" \
  -H "Content-Type: application/json" \
  -d "{ \"pem\": \"$(awk '{printf "%s\\n", $0}' client.crt)\" }"
json
{
  "fingerprint": "9f:86:d0:81:88:4c:7d:65:9a:2f:ea:a0:c5:5a:d0:15:a3:bf:4f:1b:2b:0b:82:2c:d1:5d:6c:15:b0:f0:0a:08"
}
Your ingress has to forward the certificate
The API never terminates TLS itself, so pinning is inert unless the proxy in front of it sets X-Ssl-Client-Cert. Enable this only once that header is in place, or requests with the key will start failing.

Unpin

DELETE/keys/:id/cert

Removes the pinned certificate and stops enforcing it.

json
{ "ok": true }

Feature restrictions

A team can narrow what each key may do, below what its plan includes. Three plan features are switchable per key: sms, annotations and snapshot_history. A key inherits the team default for each feature unless it overrides it. Naming a switchable feature the plan does not include returns 402; any field other than these three returns 400.

When a key has a feature switched off, requests made with it are refused with 403 and code feature_disabled_for_key: an SMS invitation, a switch to SMS, or SMS to a new recipient, on re-share, the snapshot list or a snapshot. Annotation is never refused; viewer links minted with the key simply cannot annotate. A 402 still means the plan itself lacks the feature. Dashboard requests are never restricted.

Team defaults

GET/teams/:id/api-key-features
PATCH/teams/:id/api-key-features

Each field is optional and takes true or false; a feature that was never set is on. Requires the manage-keys permission.

Per-key overrides

GET/keys/:id/features
PATCH/keys/:id/features

true or false overrides the team default; null removes the override so the key inherits it again. effective is what requests made with the key get. Requires the manage-keys permission, and the key must be active (not revoked).

json
{ "sms": false, "annotations": null }
json
{
  "features": [
    { "key": "sms", "planAllows": true, "teamDefault": true, "override": false, "effective": false },
    { "key": "annotations", "planAllows": true, "teamDefault": false, "override": null, "effective": false },
    { "key": "snapshot_history", "planAllows": false, "teamDefault": true, "override": null, "effective": false }
  ]
}

Access log

GET/keys/:id/access-log?limit=50&cursor=<opaque>

Every access attempt made with a key is recorded — successes and failures alike — newest first. Reading it requires the manage-keys permission. The log holds no secrets: neither the key, nor request bodies.

FieldDescription
limitRows per page, 1–100 (default 50).
cursorOpaque cursor from the previous response's nextCursor. Omit it for the first page; a null cursor means there are no more rows.
json
{
  "items": [
    {
      "id": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
      "outcome": "failure",
      "failureReason": "source_not_allowed",
      "ip": "203.0.113.7",
      "userAgent": "curl/8.5.0",
      "method": "POST",
      "path": "/api/v1/sessions",
      "createdAt": "2026-07-01T12:03:44.000Z"
    },
    {
      "id": "1f2a3b4c-5d6e-7f80-91a2-b3c4d5e6f708",
      "outcome": "success",
      "failureReason": null,
      "ip": "198.51.100.24",
      "userAgent": "@seeitlive/sdk 0.1.0",
      "method": "GET",
      "path": "/api/v1/sessions/abc/status",
      "createdAt": "2026-07-01T12:02:10.000Z"
    }
  ],
  "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA3LTAxVDEyOjAyOjEwLjAwMFoiLCJpZCI6IjFmMmEzYjRjIn0"
}

outcome is success or failure. On a failure, failureReason is one of invalid_key, revoked, expired, source_not_allowed, totp, client_cert, signature, env_mismatch or malformed.

Entries are kept for 30 days, then deleted automatically. Repeated tamper-shaped failures (a bad signature, a blocked source, a wrong certificate) also raise a notification to the team's owners.
API keys