API keys
Manage team-scoped API keys programmatically or from the dashboard. Keys authenticate with the Authorization: Bearer header.
Create a key
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.
| Field | Description |
|---|---|
teamId | The UUID of the team this key belongs to. |
name | A human-readable label for the key, shown in the dashboard. |
env | The environment the key is scoped to: live or test. |
embedOrigins | Optional. 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. |
expiresAt | Optional. 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"] }'{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"name": "Server key",
"env": "live",
"prefix": "sil_live_ab12cd",
"secret": "sil_live_ab12cdxxxxxxxxxxxxxxxxxxxxxxxx"
}manage_keys permission on the team; listing keys only requires view_team.List keys
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.
[
{
"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
Partially updates a key. Only the fields you include are changed; omitted fields are left as-is.
| Field | Description |
|---|---|
name | A new label for the key. |
allowedIps | The unified allowed-sources list: IPs, CIDR ranges, or hostnames, one per array entry. Replaces the existing list. |
embedOrigins | The 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. |
expiresAt | ISO 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" }'{
"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
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.
{
"id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"name": "Server key",
"env": "live",
"prefix": "sil_live_ef34gh",
"secret": "sil_live_ef34ghxxxxxxxxxxxxxxxxxxxxxxxx"
}Set the default key
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.
{ "ok": true }Revoke a key
Immediately disables a key. In-flight requests using it start failing right away, and it stops appearing in the list response.
{ "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
Turns on signing for a key and returns the signing secret. The secret is shown once — store it immediately.
{ "signingSecret": "3fa1e2d0c9b84a5b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f7081920a3b4c5" }Rotate the signing secret
Issues a new signing secret for a key, invalidating the previous one. Also shown once.
{ "signingSecret": "8c9d0e1f2a3b4c5d6e7f8091a2b3c4d53fa1e2d0c9b84a5b6e7f8091920a3b4c" }Disable signing
Turns off signing for a key. Requests to it no longer need a signature.
{ "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
Returns the seed and an otpauth URL for an authenticator app. Both are shown once — the seed is never readable again.
{
"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
Turns the second factor off and discards the seed. Requests with the key stop requiring a code.
{ "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
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)\" }"{
"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"
}X-Ssl-Client-Cert. Enable this only once that header is in place, or requests with the key will start failing.Unpin
Removes the pinned certificate and stops enforcing it.
{ "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.
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
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
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).
{ "sms": false, "annotations": null }{
"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
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.
| Field | Description |
|---|---|
limit | Rows per page, 1–100 (default 50). |
cursor | Opaque cursor from the previous response's nextCursor. Omit it for the first page; a null cursor means there are no more rows. |
{
"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.