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

# ElevenLabs Agents

> Add card-on-file payments to an ElevenLabs agent by call transfer: create a Checkout Session, transfer with SIP REFER, and reconcile on the webhook.

Add card-on-file payments to an ElevenLabs agent by call transfer. This works like a hosted web
checkout, over the phone: when the order is confirmed, your agent creates a **Checkout Session**
and transfers the live call to a Ringup payment line, the caller pays there, and the call
optionally returns to your agent. Ringup recognizes the caller, charges their saved card,
settles it against the order, and texts a receipt. Your server reconciles from a webhook. If the
model is new to you, read [Call transfer](/concepts/call-transfer) first.

This page is end to end: first-time setup, the call, the return, and what happens after payment.

## How the pieces map to ElevenLabs

| Ringup piece        | On ElevenLabs                                                                              |
| ------------------- | ------------------------------------------------------------------------------------------ |
| `create_checkout`   | A server tool on your agent that creates a Checkout Session and returns where to transfer  |
| The transfer target | The `transfer_to` SIP URI the Checkout Session returns                                     |
| The transfer        | The `transfer_to_number` system tool with `transferType: sip_refer` and `customSipHeaders` |
| The result          | A `checkout.completed` webhook to your server                                              |

## Prerequisites

* An ElevenLabs agent you already run, with a phone number attached over a SIP trunk (custom
  SIP headers require a SIP trunk, not a native-Twilio number; see the warning below).
* Your ElevenLabs API key.
* A Ringup account and API key (from your Ringup dashboard). Test mode works out of the box on a
  shared sandbox, so there is nothing to connect. See [Testing](/concepts/testing).

## Step 1: Add the Ringup checkout tool to your agent

This is the one-time setup. On your ElevenLabs agent, add a **server tool** that calls Ringup's
`create_checkout` endpoint with your Ringup API key (Agent, then Tools, then Add tool, then
Webhook), and confirm the built-in `transfer_to_number` system tool is enabled.

```jsonc theme={null}
{
  "type": "webhook",
  "name": "create_checkout",
  "description": "Create a Ringup Checkout Session for the order and return where to transfer the call.",
  "url": "https://api.ringup.dev/v1/checkouts",
  "method": "POST",
  "request_headers": { "Authorization": "Bearer <YOUR_RINGUP_KEY>" },
  "body_parameters": {
    "amount_cents": { "type": "number", "description": "Order total in cents" },
    "order_id":     { "type": "string", "description": "Your processor order id, if you have one" }
  }
}
```

Then add one line to your agent's prompt:

> When the caller has confirmed their order, call `create_checkout` with the order total, then
> transfer to the returned target.

## Step 2: Create a Checkout Session when the order is confirmed

Your agent calls the tool from Step 1. It takes the same inputs a hosted checkout session takes
(amount, line items, order), plus how you want the call to end, and returns where to send the
call:

```jsonc theme={null}
create_checkout({
  "amount_cents": 2500,
  "line_items": [{ "name": "Large pepperoni", "quantity": 1, "amount_cents": 2500 }], // optional
  "order_id": "sq_abc",                              // optional: settle against an existing order
  "return_to": "sip:agent@your-eleven-number",       // optional: transfer the caller back after payment
  "success_message": "You are all set, your order will be ready shortly."  // optional (if no return_to)
})

// response (the Checkout Session)
{
  "id": "cs_x9f2",                                   // Checkout Session id; the correlation token
  "payment_required": "required",                    // "required" | "optional" | "none"
  "transfer_to": "sip:cs_x9f2@transfer.ringup.dev"   // where to transfer; embeds the id
}
```

If `payment_required` is `none`, do not transfer: carry on and end the call normally. Otherwise
transfer to `transfer_to`.

## Step 3: Transfer with SIP REFER

Call the `transfer_to_number` system tool with a SIP-URI destination and the Checkout Session
`id` as a custom SIP header. The `client_message` is spoken to the caller as the handoff line,
so write it naturally rather than as a terse "please hold":

```jsonc theme={null}
transfer_to_number({
  "transferType": "sip_refer",
  "transferDestination": { "type": "sip_uri", "sipUri": "{{transfer_to}}" },
  "customSipHeaders": { "X-Session-Id": "{{id}}" },
  "client_message": "One moment, connecting you to secure payment."
})
```

Ringup matches the call by the `X-Session-Id` header, with the id also embedded in the SIP URI
as a backstop, so correlation holds even if a middlebox strips the header.

<Warning>
  Use a SIP trunk number and `transferType: sip_refer`. Custom SIP headers survive to a SIP
  endpoint but are stripped on a native-Twilio ElevenLabs number, which would drop the header
  match.
</Warning>

## Step 4: The return, and the result (the webhook)

Ringup answers the transferred call, recognizes the Caller, charges the saved Card, and texts a
receipt. A first-time caller with no saved card is texted a secure pay link instead. Then the
call ends one of three ways, from what you passed in Step 2:

* **`return_to` set**: Ringup transfers the caller back to your agent with the outcome in SIP
  headers (`X-Payment-Status`, `X-Confirmation`), so your agent resumes and closes in its voice.
* **`success_message` / `failure_message` set (no `return_to`)**: Ringup reads your line and ends.
* **Neither**: Ringup reads a short default and ends. The receipt is the proof.

A `return_to` that cannot connect falls back to reading your `success_message` (or the default),
so a failed return never strands the caller. Either way, your server reconciles from a webhook:

```jsonc theme={null}
{
  "id": "evt_9f2",
  "type": "checkout.completed",         // or "checkout.failed"
  "data": {
    "checkout_id": "cs_x9f2",
    "payment_id": "pay_abc",
    "amount_cents": 2500,
    "order_id": "sq_abc",               // echoed back
    "confirmation": "2PJJZY",
    "caller": "+14155551234",
    "card": { "brand": "VISA", "last_4": "5858" }
  }
}
```

Match on the `order_id` you passed, store the `payment_id`, and flip your order to paid. See
[Webhooks](/concepts/webhooks) for the full catalog, statuses, signature verification, and
idempotency.

## Validation status

ElevenLabs' `transfer_to_number` with `sip_refer` and `customSipHeaders` is documented by
ElevenLabs. Ringup's hosted transfer endpoint is rolling out; confirm access in your Ringup
dashboard before relying on this in production. The recognition, charge, receipt, and webhook
behavior is the same payment path Ringup runs everywhere.
