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

Calls

Talk Links

Create a single-use link that opens a browser page where a person talks to an agent

A talk link is a URL you can hand to a person: they open it, click Start talking, and talk to the agent's current draft from their browser. They need no ThunderPhone account. It is the same conversation as the dashboard's Talk button and the mic session endpoint: the draft configuration, recorded and billed like any test call.

Coding agents use it to ask someone to try a change: edit the draft, create a link, and send it with a note about what to listen for.

Each link works once and expires after 30 minutes unless you set another expiry (at most 120 minutes). The page shows only the agent's name.

Creating a link is part of the agent iteration toolkit, which is enabled per organization while it is in beta. A link already created keeps working either way.

Endpoints

MethodPathAuthDescription
POST/v1/agents/{agent_id}/talk-linksAPI keyCreate a talk link
GET/v1/talk-links/{token}noneCheck a link before connecting
POST/v1/talk-links/{token}/sessionnoneStart the conversation (works once)

The two {token} endpoints are what the talk page calls. You only need them to build your own page; the token in the URL is their credential.

cURL
curl -X POST https://api.thunderphone.com/v1/agents/12/talk-links \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"expires_in_minutes": 30, "note": "shorter greeting"}'
Python
link = requests.post(
    "https://api.thunderphone.com/v1/agents/12/talk-links",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={"expires_in_minutes": 30, "note": "shorter greeting"},
).json()
print(link["url"])
Node.js
const link = await fetch("https://api.thunderphone.com/v1/agents/12/talk-links", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.THUNDERPHONE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ expires_in_minutes: 30, note: "shorter greeting" }),
}).then((r) => r.json());

Request fields

FieldTypeRequiredDescription
variant_idintegernoTalk to one A/B variant of the draft instead of the plain draft
languagestringnoLanguage code for the conversation, such as es. Defaults to the agent's primary language
expires_in_minutesintegernoMinutes until an unused link stops working. Default 30, between 1 and 120
notestringnoYour own label for the link, up to 500 characters. Never shown on the talk page

Response

201 Created

{
  "url": "https://app.thunderphone.com/talk/Vh3k…",
  "expires_at": "2026-10-19T18:30:00Z"
}
FieldTypeDescription
urlstringThe page to send. It contains the link's token; treat it like a password until it is used
expires_atstringWhen an unused link stops working (ISO 8601)

ThunderPhone stores only a hash of the token, so a lost URL cannot be shown again. Create another link instead.

Errors

StatusCondition
400expires_in_minutes outside 1–120, an unknown language, or a variant_id that is not one of this agent's variants
403feature_not_enabled: the organization does not have the agent iteration toolkit, which is enabled per organization while it is in beta. The body's next_step says what to do
404Agent not found in this organization

GET /v1/talk-links/{token} needs no authentication. It returns what the talk page shows before the person connects, and nothing else about your organization.

{
  "agent_name": "Front Desk",
  "expires_at": "2026-10-19T18:30:00Z",
  "used": false,
  "recorded": true
}

recorded says whether the conversation will be recorded, from the agent draft's recording setting (the session runs the draft).

404 with code: "talk_link_not_found" means the token is unknown or the link's agent has moved to another organization.

Start the conversation

POST /v1/talk-links/{token}/session needs no authentication and no body. The first successful request uses the link and starts a browser session with the agent's draft at that moment, exactly like POST /v1/mic-session:

{
  "call_id": 987654321,
  "token": "<livekit-jwt>",
  "room_name": "mic-987654321",
  "server_url": "wss://livekit.thunderphone.com",
  "agent_name": "Front Desk"
}

Join the room with the LiveKit Web SDK as described under Connecting from the browser. The conversation appears in call history with direction="test".

Errors

StatusCondition
400The link's language can no longer be used with the agent's current voice. The link stays unused
402The organization's balance or test-call budget cannot cover a call. The link stays unused
404talk_link_not_found: unknown token, or the link's agent has moved to another organization
410talk_link_used: the link was already used. talk_link_expired: it expired before use, or its agent was moved to another organization and back
422The agent's voice cannot be used, for example a custom voice that was deleted. The link stays unused
429Too many requests for this link or from this address, or the organization is at its concurrent-call limit. The link stays unused
503Voice infrastructure unavailable. The link stays unused

MCP

The ThunderPhone MCP server exposes this as create_talk_link, so a coding agent can create the link and hand you the URL.