Skip to main content
Add card-on-file payments to a Retell 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 it, the caller pays on the Ringup line, 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 first. This page is end to end: first-time setup, the call, the return, and what happens after payment.

How the pieces map to Retell

Ringup pieceOn Retell
create_checkoutA custom function on your agent that creates a Checkout Session and returns where to transfer
The transfer targetThe transfer_to SIP URI the Checkout Session returns
The transferRetell’s transfer_call tool (or Transfer Call node) with custom_sip_headers
The resultA checkout.completed webhook to your server

Prerequisites

  • A Retell agent you already run, with a phone number.
  • Your Retell 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.

Step 1: Add the Ringup checkout function to your agent

This is the one-time setup. Register a custom function on your Retell agent that creates a Ringup Checkout Session, authenticated with your Ringup API key. Add it in the Retell dashboard (Agent, then Functions, then Add custom function) or through the Retell API:
{
  "type": "custom",
  "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",
  "headers": { "Authorization": "Bearer <YOUR_RINGUP_KEY>" },
  "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 so it knows when to call it:
When the caller has confirmed their order, call create_checkout with the order total.
That is the whole setup. Nothing else is provisioned in Retell, and your agent is otherwise unchanged.
A CLI to register this for you is on the way. Until then, the function above is the only setup step, and it is a copy and paste.

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

Your agent calls the function 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:
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-retell-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)
  "failure_message": "That card was declined. Please call back with another card."  // optional
})

// 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
}
  • payment_required: "none": the merchant does not take payment for this order. There is no transfer_to; carry on and end the call normally.
  • required or optional: transfer the call to transfer_to.
The id and transfer_to are what Step 3 uses. order_id and line_items mirror a checkout session. return_to, success_message, and failure_message control how the call ends (Step 5).

Step 3: Transfer to the returned target

Transfer to the transfer_to from Step 2, and attach the Checkout Session id as a custom SIP header so Ringup can match the call to the session. Inject both through Retell dynamic variables, never as values the model types:
{
  "type": "transfer_call",
  "transfer_destination": "{{transfer_to}}",          // from Step 2
  "custom_sip_headers": { "X-Session-Id": "{{id}}" }  // the Checkout Session id, from Step 2
}
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.
Transfer to the SIP URI, not to a PSTN number. Custom SIP headers survive to a SIP endpoint but may be stripped on the way to a PSTN number, which would drop the header match.

Step 4: Keep the caller comfortable during the handoff

A cold transfer drops your agent as the payment line connects. Two easy, configurable moves remove the rough edge:
  • Have your agent speak one short bridge line just before the transfer fires (“One moment, connecting you to secure payment”), so the caller is never on silence.
  • On the warm transfer path, set on-hold music instead of the default ringtone for the brief connect gap.
The payment line’s voice and model are set in your Ringup dashboard, so you can match them to your agent.

Step 5: The return, and the result (the webhook)

Ringup answers the transferred call, recognizes the Caller, charges the saved Card on the merchant’s own payment processor, and texts the caller 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, depending on what you passed in Step 2:
  • return_to set: Ringup transfers the caller back to your agent and attaches the outcome as SIP headers (X-Payment-Status: completed, X-Confirmation), so your agent resumes already knowing payment succeeded and can confirm the order, upsell, or say goodbye in its own voice.
  • success_message / failure_message set (no return_to): Ringup reads your line for the outcome and ends the call on its line. Use this when you want the closing words in your own wording but do not need the caller back on your agent.
  • Neither: Ringup reads a short default confirmation and ends. The receipt is the proof.
A return_to that cannot connect falls back to reading your success_message (or the default) and ending, so a failed return never strands the caller. Either way, your server learns the outcome from a webhook. This is how you mark the order paid:
{
  "id": "evt_9f2",
  "type": "checkout.completed",         // or "checkout.failed"
  "created": "2026-07-07T18:05:12Z",
  "data": {
    "checkout_id": "cs_x9f2",
    "payment_id": "pay_abc",            // the Payment
    "amount_cents": 2500,
    "order_id": "sq_abc",               // the id you passed in Step 2, 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 for the full event catalog, the statuses, signature verification, and idempotency.

Validation status

Retell’s transfer_call and its custom_sip_headers support are documented by Retell. Ringup confirms each new platform by capturing the first real transfer and checking the Checkout Session id arrives as expected; until that check runs for your account, treat the transfer wiring as documented, not yet validated on your specific Retell and telephony setup. The recognition, charge, receipt, and webhook behavior is the same payment path Ringup runs everywhere.