Skip to main content

Quickstart: Voice Calls

Give your AI agent a real phone number, send yourself an SMS, then place the first voice call to a number you control.

Prerequisites

  • An Anima API key from console.useanima.sh
  • Python 3.10+ or Node.js 18+
  • An existing agent_id
  • Phone access for SMS
  • Voice access for outbound calls
  • Consent to contact the destination number
If you are testing for the first time, use your own phone number as the destination.

Python

pip install anima-labs
from anima import Anima

anima = Anima(api_key="ak_...")

agent_id = "AGENT_ID"
your_phone = "+15551234567"

# 1. Provision a phone number for SMS and voice.
phone = anima.phones.provision(
    agent_id=agent_id,
    country_code="US",
    capabilities=["voice", "sms"],
)
print(f"Phone: {phone.phone_number}")

# 2. Text yourself first. This proves the number is real and reachable.
sms = anima.messages.send_sms(
    agent_id=agent_id,
    to=your_phone,
    body="Hi - this is my Anima agent texting before it calls.",
)
print(f"SMS sent: {sms.id} ({sms.status})")

# 3. Confirm the voice catalog is available for your tier.
voices = anima.voices.list(tier="basic")
print(f"Available basic voices: {len(voices['voices'])}")

# 4. Place the first outbound call.
call = anima.calls.create(
    agent_id=agent_id,
    to=your_phone,
    tier="basic",
    greeting="Hi, this is my Anima agent. I am calling from my own phone number.",
)
print(f"Call started: {call.call_id}, state: {call.state}")

# 5. After the call ends, fetch the transcript.
transcript = anima.calls.get_transcript(call.call_id)
for segment in transcript.segments:
    print(f"{segment.speaker}: {segment.text}")

Node.js / TypeScript

npm install @anima-labs/sdk
import { Anima } from "@anima-labs/sdk";

const anima = new Anima({ apiKey: "ak_..." });

const agentId = "AGENT_ID";
const yourPhone = "+15551234567";

// 1. Provision a phone number for SMS and voice.
const phone = await anima.phones.provision({
  agentId,
  countryCode: "US",
  capabilities: ["voice", "sms"],
});
console.log(`Phone: ${phone.phoneNumber}`);

// 2. Text yourself first. This proves the number is real and reachable.
const sms = await anima.messages.sendSms({
  agentId,
  to: yourPhone,
  body: "Hi - this is my Anima agent texting before it calls.",
});
console.log(`SMS sent: ${sms.id} (${sms.status})`);

// 3. Confirm the voice catalog is available for your tier.
const voices = await anima.voices.list({ tier: "basic" });
console.log(`Available basic voices: ${voices.voices.length}`);

// 4. Place the first outbound call.
const call = await anima.calls.create({
  agentId,
  to: yourPhone,
  tier: "basic",
  greeting: "Hi, this is my Anima agent. I am calling from my own phone number.",
});
console.log(`Call started: ${call.callId}, state: ${call.state}`);

// 5. After the call ends, fetch the transcript.
const transcript = await anima.calls.getTranscript(call.callId);
for (const segment of transcript.segments) {
  console.log(`${segment.speaker}: ${segment.text}`);
}

Environment Variables

You can also configure via environment variables instead of passing options directly:
export ANIMA_API_KEY="ak_..."
export ANIMA_API_URL="https://api.useanima.sh"  # optional, defaults to production
export ANIMA_LOG="debug"  # optional, enables debug logging
# No need to pass api_key when ANIMA_API_KEY is set
from anima import Anima
anima = Anima()
// No need to pass apiKey when ANIMA_API_KEY is set
const anima = new Anima();

Handle Inbound Calls

To react after calls complete, set up a webhook endpoint and subscribe to call.ended. Inbound real-time call control happens over the voice WebSocket.
from anima import Anima, fastapi_webhook_dependency
from fastapi import FastAPI, Depends

app = FastAPI()
webhook_dep = fastapi_webhook_dependency("whsec_...")

@app.post("/webhooks")
async def handle(event=Depends(webhook_dep)):
    if event.type == "call.ended":
        print(f"Call ended: {event.data['callId']}")
import express from "express";
import { Anima, webhookMiddleware } from "@anima-labs/sdk";

const app = express();
app.use(express.json());

app.post("/webhooks", webhookMiddleware("whsec_..."), (req, res) => {
  const event = req.webhookEvent;
  if (event.type === "call.ended") {
    console.log(`Call ended: ${event.data.callId}`);
  }
  res.sendStatus(200);
});

Real-Time Call Events (WebSocket)

Monitor and control calls in real time over the voice WebSocket:
const anima = new Anima({ apiKey: "ak_..." });
const conn = anima.calls.connect({ agentId });

conn.on("message", (message) => {
  switch (message.type) {
    case "call.started":
      console.log("Call started:", message.data?.callId);
      break;
    case "call.transcription":
      console.log(`[${message.data?.speaker}]: ${message.data?.text}`);
      break;
    case "call.ended":
      console.log("Call ended:", message.data?.callId);
      break;
  }
});

conn.createCall(yourPhone);

What’s Next?