An app is the credential boundary for realtime traffic. Each app carries an app ID, a key, and a secret. Your servers sign HTTP API calls and channel auth responses with the secret. Clients connect with the key. Apps are scoped to an organization, so the Apps & keys screen requires a signed-in session with an org selected — until then it shows a sign-in prompt and does not call the app list procedure at all. The key/secret pair is Pusher-compatible. A stock pusher-js client pointed at an app’s key connects without a custom transport.

What an app is: app ID, key, secret

The app table lists one row per app with these columns: Rows whose status is not active render dimmed, with the status string shown in place of the active pill. The three identifiers do different jobs:
  • App ID identifies the app in HTTP API paths and in webhook payloads.
  • Key is the public half. It goes in client config.
  • Secret is the private half. It stays on your servers. ClutchCall seals it at rest and the API does not return it after it has been issued.

The one-time reveal and the masked tail

When an app is created or a secret is rotated, the screen renders a one-time reveal panel above the table. It is the only place the full secret ever appears.
  • On create, the panel shows three fields: App ID, Key, and Secret (shown once).
  • On rotate, the panel shows one field: New secret (shown once).
Dismissing the panel — via the close button or I’ve stored it — discards it from the UI. There is no way to reopen it. Reloading the screen will not bring it back, because the list procedure returns only the masked tail. If you lose a secret, the recovery path is rotation, not retrieval. Rotating issues a fresh secret and shows it once, under the same rules. Copy the secret into your secret manager before you dismiss the panel.

Creating an app

Press Create app to open the create card, then fill in App name and press Generate. The key and secret are generated server-side; you do not supply them. Naming rules enforced by the form:
  • The name is required. An empty or whitespace-only name blocks submission.
  • The name is capped at 80 characters.
Validation errors stay hidden until you first press Generate, then appear inline under the field. The name is trimmed before it is sent. If creation fails, the error message from the server is shown inline at the bottom of the create card and the card stays open with your input intact. When there are no apps yet, the screen shows an empty state with its own Create app button instead of the table; the header button appears once at least one app exists.

Rotating a secret without dropping traffic

Rotate secret lives in the row’s overflow menu (the ⋯ button). It asks for confirmation first, and the dialog states the consequence plainly: the new secret is shown once, and every server still signing with the current secret stops authenticating immediately. There is no overlap window. The old secret is invalid the moment the new one is issued. Plan the rollout accordingly:
  1. Make sure your servers read the secret from a source you can update without a code deploy — an environment variable backed by a secret manager, or a config store your processes re-read.
  2. Rotate in the console and copy the new secret from the reveal panel.
  3. Write it to that source and roll your signing servers.
Any request signed with the previous secret and still in flight during that window fails authentication rather than being honoured. Client connections authenticate with the key, not the secret, so they are not the thing at risk — the exposure is on your server-side signing path, including private and presence channel auth responses. Rotation does not change the app ID or the key. Clients do not need new config.

Renaming an app

The name is editable in place, from the same screen that displays it. Click the pencil next to the name, or choose Rename from the row menu.
  • Enter commits the change; Escape cancels.
  • The check button commits; the × cancels.
  • An empty name, or one longer than 80 characters, is not committed.
  • Committing the same name the app already has just closes the editor without a write.
A failed rename surfaces as an inline note above the table. The app’s key, secret, and app ID are untouched by a rename.

Deleting an app

Delete app is the destructive entry at the bottom of the row menu and requires confirmation. The dialog spells out the blast radius: all keys, channels, and webhooks belonging to the app are removed, and connected clients are dropped immediately. The app switcher only clears its selection after the server confirms the delete. If the delete is rejected, the selection stays as it was and the failure is reported inline.

Voice agent keys shown on this screen

Below the app table, the screen lists Voice agent keys — read-only credentials for externally-hosted voice agents. This block only renders when the org has at least one such credential. These are not interchangeable with an app key. They come from a different table and a different engine registry, and they authenticate the /media/ transport only — not channel connections and not the realtime HTTP API. Signing a realtime API request with a voice agent secret does not authenticate, and vice versa. They appear here because an operator auditing “which credentials does this org have in the wild” needs to see both sets. Nothing on this screen mutates them: create, rotate, and delete for voice agent credentials live in Voice AI → External agents.

Tagging and filtering apps

Each app row has a tag cell. Tags are org-scoped and stored against the resource kind realtime_app, keyed by the app’s internal id. Edit them in place from the cell. The tag filter in the page header narrows the table to apps matching the filter and reports how many of the total rows matched. Filtering is applied to the table only — it does not affect the voice agent keys block.
  • Authentication — how server credentials relate to short-lived client tokens
  • Telemetry — operational data emitted per tenant