ThunderPhone 2.0 is live.Self-serve, from 2¢/min.Read the announcement

Developer

Publishable Keys

Create, list, and revoke the pk_live_ publishable keys that let the embeddable web widget start browser voice sessions with your agents from your own site.

Publishable keys (pk_live_...) are public credentials that the embeddable web widget uses from the browser. Unlike secret API keys, they are scoped to a specific agent (or a webhook that will dynamically resolve one) and gated to a list of allowed origins — safe to ship in your front-end code. The origin list stops casual reuse on other sites; it is not authentication, since a non-browser client can send any Origin header. That is why the session settings a browser may send are off by default (see allowed_overrides).

Each key is associated with exactly one of:

  • mode = "agent": fixed binding to an agent id. Simplest setup.
  • mode = "webhook": the widget calls your call.incoming webhook to dynamically resolve an agent per visitor.

Endpoints

MethodPathDescription
GET/v1/publishable-keyList publishable keys
POST/v1/publishable-keyCreate a publishable key
GET/v1/publishable-key/{key_id}Retrieve a key
PATCH/v1/publishable-key/{key_id}Update name / allowed domains / mode / browser overrides
DELETE/v1/publishable-key/{key_id}Deactivate a key
POST/v1/publishable-key/{key_id}/transferCopy or move to another org

Publishable key object

{
  "id": 9,
  "name": "Marketing site (prod)",
  "key": "pk_live_abc123...",
  "key_prefix": "pk_live_abc",
  "allowed_domains": ["example.com", "*.example.com"],
  "is_active": true,
  "is_enabled": true,
  "mode": "agent",
  "agent_id": 12,
  "agent_name": "Customer Support Agent",
  "webhook_url": null,
  "allowed_overrides": ["context"],
  "max_call_duration_seconds": 1800,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
FieldTypeDescription
idintegerKey id
namestringDisplay name
keystringThe raw pk_live_... value. Publishable keys are public, so the full value is retrievable at any time
key_prefixstringFirst 12 chars for display (e.g. pk_live_abc)
allowed_domainsarray of stringOrigin allowlist — exact hostnames and *.subdomain wildcards. localhost is not allowed automatically in production; list it to test locally
is_activebooleanfalse after deactivation; a deactivated key stops working
is_enabledbooleanTemporary disable toggle (separate from is_active)
modestringagent or webhook
agent_idinteger | nullRequired for mode="agent"
agent_namestring | nullRead-only convenience — the linked agent's name
webhook_urlstring | nullRequired for mode="webhook" — overrides the org-level webhook
allowed_overridesarray of stringSession settings the browser may send to POST /v1/widget/session: any of context, variables, voice, language. A request carrying one that is not listed fails with 400 override_not_allowed. [] for new keys; keys created before the setting existed allow all four
max_call_duration_secondsinteger | nullLongest a widget session may run, in seconds: 60–21600, default 1800 (30 minutes). A session ends at this or at the agent's own max call duration, whichever is shorter. null uses the agent's (or webhook config's) own limit alone
created_at, updated_attimestamp

List publishable keys

cURL
curl https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

Returns an array of Publishable key objects.


Create a publishable key

Agent-bound key
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Marketing site (prod)",
    "mode": "agent",
    "agent_id": 12,
    "allowed_domains": ["example.com", "*.example.com"]
  }'
Webhook-mode key
curl -X POST https://api.thunderphone.com/v1/publishable-key \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Dynamic widget",
    "mode": "webhook",
    "webhook_url": "https://example.com/thunderphone-webhook",
    "allowed_domains": ["example.com"]
  }'
FieldTypeRequiredDescription
namestringnoDefaults to "Web Widget"
modestringnoagent (default) or webhook
agent_idintegeryes (if mode="agent")
webhook_urlstringyes (if mode="webhook")HTTPS URL
allowed_domainsarray of stringyesAt least one entry required. See rules below
is_enabledbooleannoDefaults to true
allowed_overridesarray of stringnoAny of context, variables, voice, language. Defaults to [] (the browser may set none)
max_call_duration_secondsinteger | nullno60–21600, default 1800 (30 minutes). null leaves only the agent's own limit

Allowed-domain rules

  • An exact match: example.com
  • A wildcard match: *.example.com (matches api.example.com but not bare example.com)
  • localhost and 127.0.0.1 are not allowed automatically in production. List them to test a local page against the production API
  • Bare wildcards (* or *.*) are rejected with 400
  • At least one entry is required — passing an empty array returns 400 allowed_domains: "At least one allowed domain is required."

Returns 201 Created with the new Publishable key object. The key field is included on creation and is retrievable later via GET — publishable keys are public by design.


Update / delete

PATCH accepts any subset of name, allowed_domains, mode, agent_id, webhook_url, is_enabled, embed_config, allowed_overrides, max_call_duration_seconds. Switching between modes requires providing the new required field (agent_id or webhook_url).

DELETE sets is_active=false — the key stops working but remains visible in list responses so you can audit prior deployments. There is no hard delete.


Transfer a publishable key

Copy or move a publishable key to another organization where you are an admin.

An sk_live_ API key is limited to its own organization: with a key, target_org_id must be the key's organization, and any other target returns 403. Copy or move between organizations from a signed-in session (Authorization: Token <session-token> plus X-ThunderPhone-Org for the source org), as below.

cURL
curl -X POST https://api.thunderphone.com/v1/publishable-key/9/transfer \
  -H "Authorization: Token YOUR_SESSION_TOKEN" \
  -H "X-ThunderPhone-Org: 42" \
  -H "Content-Type: application/json" \
  -d '{"target_org_id": 77, "mode": "copy"}'
FieldTypeRequiredDescription
target_org_idintegeryes
modestringyescopy or move
namestringnoOverride the copy's name