The first three load once per visit. The deliveries panel requests the
25 most recent rows and refreshes every 30 seconds while the screen is
open.
API keys and scopes
A stream API key is a bearer token that your server presents to the control plane. Each key row carries:scopes is a list, not a single value, and the console renders one tag
per entry. Scope is enforced per procedure: the control plane rejects a
call when the presented key does not carry the scope that the called
procedure requires. Mint one key per job and give it only the scopes that
job needs — a key scoped to what it actually does limits the blast radius
when it leaks.
Scopes are fixed at creation time. There is no edit control on this
screen: to change what a key can do, create a replacement key with the
scopes you want, move your callers onto it, then revoke the old one.
Live and test environments
Every key belongs to exactly one environment, and theenv tag on the
row tells you which. The console colours live green and the test
environment amber, because the two are the mistake that costs the most:
a test key in production stops working, and a live key in a test harness
touches real inputs, real assets and real billable delivery.
The environments are separate credential namespaces. A key is not
promoted from test to live — you mint a second key in the environment you
want. The rest of the screen (signing keys, webhook endpoints,
deliveries) is listed for the environment that the Stream shell is
currently showing.
Key creation, preview-only storage, and rotation
Create API key mints a key and returns the full token string exactly once, at creation. After that the control plane stores only a hash of the token plus a short leading fragment (a dozen or so characters) intoken_preview.
That is why the key table shows the preview followed by mask characters
and offers neither a reveal nor a copy control:
- There is nothing to reveal. The cleartext is not retained anywhere, so no control could produce it.
- There is nothing useful to copy. The preview is a fragment that can never authenticate, and putting it on the clipboard only invites pasting it somewhere as though it were a token.
last_used_at is
moving, then use Revoke on the old row. Revoking is the only
destructive action on a key; the row stays in the list afterwards and
renders as revoked instead of offering a revoke control, so the history
of which key was retired and when is preserved.
Signing keys and their two uses
Signing keys are asymmetric keys held by the control plane. They are not bearer credentials and are never presented as one. Each key exists for exactly one use, and the console labels the row accordingly:
Each row shows the key id and its algorithm (
alg) in mono type, plus
the creation date. You reference the key id when minting a playback token
(see below), and you use the matching public key when verifying a webhook
delivery.
Keep the two uses on separate keys. They have different exposure: a
playback key signs tokens that go out to browsers many times a second,
while a webhook key signs traffic that only ever goes to endpoints you
control. Retiring one should not invalidate the other.
Signing key lifecycle states
status drives the status indicator on each row:
The Retire control appears only on rows whose status is
active —
a rotating or retired key has nothing left to retire. Because retiring is
offered only from active, the safe order is: generate the successor with
Generate signing key, point your minting code at the new key id, and
retire the old key once nothing still references it.
For playback keys, “nothing still references it” means every token that
the old key signed has passed its expiresIn. For webhook keys, it means
your verifier has been taught the new public key.
Minting a signed playback token
Signed playback tokens are minted on your server, with the SDK, against a signing key whose use isplayback:
signPlayback returns the token string. Append it to the playback URL as
?token=…; the player reads it from the URL and presents it on playback
without further wiring.
Never run this in the browser. The signing key is what makes a token
valid, and minting is a server-side operation for the same reason the API
key is: whatever can mint tokens can mint them for any viewer and any
lifetime.
Webhook endpoints and event types
Add endpoint registers a URL that ClutchCall POSTs events to. Each endpoint row shows:
An endpoint receives only the event types it is subscribed to, so the
count column is the quickest check when an event you expected never
arrived: a healthy endpoint subscribed to the wrong set looks perfectly
fine.
Every delivery is signed with the signing key whose use is webhook
signature. Verify that signature on your endpoint before you act on the
payload, using the algorithm shown on the signing key row — an unsigned
or unverified POST to a public URL is an open write endpoint. While a
webhook key is
rotating, accept signatures from both the rotating key
and its active successor, then drop the old one once you retire it.
Delete removes an endpoint. Deleting stops future deliveries to that
URL; it does not remove the delivery rows already logged for it.
Webhook endpoint health states
The console collapsesstatus and consecutive_failures into one
indicator:
An
active endpoint with a non-zero failure count shows as failing, not
as healthy — a key detail, because the endpoint is still enabled and
still accruing attempts. Read last_status_code next: a 4xx usually
means the payload or the signature check is being rejected, while a 5xx
or a missing code points at the endpoint itself being down. A successful
delivery resets the counter and the row returns to Healthy.
Delivery states, retries, and resending
The Recent event deliveries table is the delivery log — the 25 most recent attempts, refreshed every 30 seconds. There is no separate log explorer, so this panel is where a delivery question gets answered. Each row carries theevent_type, the obj_id of the object the event is
about (a live input, an asset, and so on), the response, and the
timestamp.
The response column has three renderings, and the distinction matters:
Queued is not failed. A delivery that has been accepted for delivery
but has no response yet renders neutral rather than red, so a burst of
in-flight events does not read as an outage. Only a delivery that has
actually come back non-2xx, or that is marked
failed, is an error.
Deliveries that fail are retried automatically with backoff — successive
attempts are spaced further apart rather than hammering a dead endpoint —
and each failed attempt increments the endpoint’s
consecutive_failures, which is what eventually moves the endpoint row
out of Healthy.
Resend on a delivery row asks for that event to be delivered again. It
queues a fresh attempt; it does not cancel, replace, or reprioritise an
attempt that is already queued or in flight. Resending a delivery that is
still showing — Queued therefore leaves you with two attempts for the
same event, so wait for a response before resending. Because a resend is
an additional delivery of the same event, your endpoint handlers should be
idempotent on the event id.
Related
- Authentication — API keys, relay tokens, and signing-key rotation across the platform
- Telemetry — operational data streams and where to scrape them

