Open in
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
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /v1/agents/{agent_id}/talk-links | API key | Create a talk link |
GET | /v1/talk-links/{token} | none | Check a link before connecting |
POST | /v1/talk-links/{token}/session | none | Start 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.
Create a talk link
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"}'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"])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
| Field | Type | Required | Description |
|---|---|---|---|
variant_id | integer | no | Talk to one A/B variant of the draft instead of the plain draft |
language | string | no | Language code for the conversation, such as es. Defaults to the agent's primary language |
expires_in_minutes | integer | no | Minutes until an unused link stops working. Default 30, between 1 and 120 |
note | string | no | Your 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"
}| Field | Type | Description |
|---|---|---|
url | string | The page to send. It contains the link's token; treat it like a password until it is used |
expires_at | string | When 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
| Status | Condition |
|---|---|
400 | expires_in_minutes outside 1–120, an unknown language, or a variant_id that is not one of this agent's variants |
403 | feature_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 |
404 | Agent not found in this organization |
Check a link
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
| Status | Condition |
|---|---|
400 | The link's language can no longer be used with the agent's current voice. The link stays unused |
402 | The organization's balance or test-call budget cannot cover a call. The link stays unused |
404 | talk_link_not_found: unknown token, or the link's agent has moved to another organization |
410 | talk_link_used: the link was already used. talk_link_expired: it expired before use, or its agent was moved to another organization and back |
422 | The agent's voice cannot be used, for example a custom voice that was deleted. The link stays unused |
429 | Too many requests for this link or from this address, or the organization is at its concurrent-call limit. The link stays unused |
503 | Voice 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.