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

Overview

Python and TypeScript SDKs

Typed ThunderPhone clients for agents, calls, and the public API.

The ThunderPhone SDKs use the OpenAPI specification for request and response types. They read THUNDERPHONE_API_KEY from your server's environment. Create a key in the dashboard under Organization → Keys, and keep it in your secret manager. Never include it in browser code.

TypeScript

Requires Node.js 18 or later. Both ESM and CommonJS are supported.

npm install @thunderphone/sdk
import { ThunderPhone } from "@thunderphone/sdk";
 
const api = new ThunderPhone();
const agent = await api.agents.create({
  name: "Reception",
  prompt: "Help callers with scheduling and business information.",
  voice: process.env.THUNDERPHONE_VOICE!,
});
const call = await api.calls.place({
  agent_id: agent.id,
  from_number: process.env.FROM_NUMBER!,
  to_number: process.env.TO_NUMBER!,
  idempotency_key: "appointment-123",
});
const done = await api.calls.waitForCompletion(call.call_id, { timeoutMs: 300_000 });
if (done.status === "failed") throw new Error(done.end_reason ?? "Call failed");
console.log((await api.calls.transcript(call.call_id)).transcripts);

Pass { apiKey, baseUrl } to configure the client explicitly. baseUrl defaults to https://api.thunderphone.com, without /v1. All operations are available via api.client.GET, .POST, .PUT, .PATCH, and .DELETE with typed paths and bodies. waitForCompletion accepts an AbortSignal, timeoutMs, and pollIntervalMs.

Python

Requires Python 3.10 or later.

pip install thunderphone
import os
from thunderphone import ThunderPhone, AgentRequest, PlaceCallRequest
 
with ThunderPhone() as api:
    agent = api.agents.create(AgentRequest(
        name="Reception",
        prompt="Help callers with scheduling and business information.",
        voice=os.environ["THUNDERPHONE_VOICE"],
    ))
    call = api.calls.place(PlaceCallRequest(
        agent_id=agent.id,
        from_number=os.environ["FROM_NUMBER"],
        to_number=os.environ["TO_NUMBER"],
        idempotency_key="appointment-123",
    ))
    done = api.calls.wait_for_completion(call.call_id, timeout=300)
    if done.status == "failed":
        raise RuntimeError(done.end_reason)
    print(api.calls.transcript(call.call_id).transcripts)

Pass api_key= and base_url= to configure the client explicitly. Every operation also has typed sync and async functions under thunderphone.generated.api, with models under thunderphone.generated.models. Pass client=api.client to use the same authentication and client-identification header.

Calls and errors

Choose THUNDERPHONE_VOICE from GET /v1/voices. Set FROM_NUMBER to an outbound-capable number connected to your carrier, and TO_NUMBER to your test destination. Outbound calling requires sufficient balance and the organization's outbound confirmation. ThunderPhone-provisioned demo numbers are inbound only.

Polling returns completed or failed calls; inspect the status before consuming the transcript. Helpers raise ThunderPhoneError for unsuccessful HTTP responses and expose status and body. Transport errors propagate. Requests that mutate state are not retried automatically. Reuse an idempotency key only for the same outbound-call request.

For direct tool use from a coding agent, connect to the MCP server. See the coding-agent guide for setup and the OpenAPI specification for every operation.