> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useanima.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Give Your AI Agent a Phone Number in 5 Minutes

> Step-by-step tutorial: provision a US phone number for your AI agent, send SMS, place a first voice call, and handle inbound events.

# Give Your AI Agent a Phone Number in 5 Minutes

Your AI agent can send email, but some workflows need a phone path too: urgent updates, appointment reminders, SMS replies, voice confirmation, and verification flows. This tutorial provisions a number, sends a real SMS, places a first voice call, and wires inbound events to a webhook.

## Prerequisites

* An Anima API key from [console.useanima.sh](https://console.useanima.sh)
* Python 3.10+ or Node.js 18+
* An existing `agent_id`
* Phone access for SMS
* Voice access if you want to place the call step
* Consent to contact the destination number

Use your own phone number for the first run.

## 1. Install the SDK

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```bash theme={null}
    npm install @anima-labs/sdk
    ```
  </Tab>

  <Tab value="Python">
    ```bash theme={null}
    pip install anima-labs
    ```
  </Tab>
</Tabs>

## 2. Search for available numbers

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    import { Anima } from "@anima-labs/sdk";

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

    const numbers = await anima.phones.search({
      countryCode: "US",
      areaCode: "415",
      capabilities: ["sms", "voice"],
      limit: 3,
    });

    for (const number of numbers.items) {
      console.log(number.phoneNumber, number.region);
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    from anima import Anima

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

    numbers = anima.phones.search(
        country_code="US",
        area_code="415",
        capabilities=["sms", "voice"],
        limit=3,
    )

    for number in numbers["items"]:
        print(number["phoneNumber"], number.get("region"))
    ```
  </Tab>
</Tabs>

## 3. Provision the number

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const phone = await anima.phones.provision({
      agentId,
      countryCode: "US",
      areaCode: "415",
      capabilities: ["sms", "voice"],
    });

    console.log(`Provisioned: ${phone.phoneNumber}`);
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    phone = anima.phones.provision(
        agent_id=agent_id,
        country_code="US",
        area_code="415",
        capabilities=["sms", "voice"],
    )

    print(f"Provisioned: {phone.phone_number}")
    ```
  </Tab>
</Tabs>

The number is linked to the agent's unified identity: the same `agent_id` used for email, vault, DID, audit logs, and webhooks.

## 4. Text yourself

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const sms = await anima.messages.sendSms({
      agentId,
      to: "+15551234567",
      body: "Hi - this is my Anima agent texting from its own number.",
    });

    console.log(`SMS sent: ${sms.id} (${sms.status})`);
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    sms = anima.messages.send_sms(
        agent_id=agent_id,
        to="+15551234567",
        body="Hi - this is my Anima agent texting from its own number.",
    )

    print(f"SMS sent: {sms.id} ({sms.status})")
    ```
  </Tab>
</Tabs>

## 5. Call yourself

Outbound voice calls run through the voice gate before dialing. Only call recipients where you have the required consent.

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const call = await anima.calls.create({
      agentId,
      to: "+15551234567",
      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}`);
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    call = anima.calls.create(
        agent_id=agent_id,
        to="+15551234567",
        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}")
    ```
  </Tab>
</Tabs>

After the call ends, fetch the transcript:

<Tabs items={["Node.js", "Python"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const transcript = await anima.calls.getTranscript(call.callId);
    for (const segment of transcript.segments) {
      console.log(`${segment.speaker}: ${segment.text}`);
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    transcript = anima.calls.get_transcript(call.call_id)
    for segment in transcript.segments:
        print(f"{segment.speaker}: {segment.text}")
    ```
  </Tab>
</Tabs>

## 6. Handle inbound events

Inbound SMS arrives as `message.received`; inspect the message channel/payload to distinguish SMS from email. Call lifecycle events use the `call.*` namespace.

```bash theme={null}
curl -X POST https://api.useanima.sh/v1/webhooks \
  -H "Authorization: Bearer ak_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/anima",
    "events": ["message.received", "phone.provisioned", "call.ended"]
  }'
```

Example handler:

```ts theme={null}
app.post("/webhooks/anima", (req, res) => {
  const event = req.body;

  if (event.type === "message.received") {
    console.log("Inbound message:", event.data);
  }

  if (event.type === "call.ended") {
    console.log("Call ended:", event.data.callId);
  }

  res.status(200).send("ok");
});
```

## 10DLC and voice compliance

For US SMS, 10DLC registration may be required depending on your use case and volume. Anima tracks phone identity status and carrier capability flags with the provisioned number.

For US outbound voice calls, Anima enforces plan eligibility, TCPA consent posture, Reassigned Numbers Database checks, time-of-day windows, and per-tier call caps server-side. If a gate fails, the call is rejected before the provider dials.

## What makes this different

The phone number is not a disconnected CPaaS resource. It is part of the agent identity:

* Same `agent_id` across email, SMS, voice, vault, and DID
* Same policy and audit surface across channels
* Same webhook system for inbound and lifecycle events
* Same vault-backed credential boundary when the agent needs to act after the conversation

[Read the Phone docs](/phone) | [Set up webhooks](/webhooks) | [Get started](/getting-started)
