> ## 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.

# Checkout Session

> The central object: created when an order is ready to pay, it carries Ringup's payment policy and, in transfer mode, where to send the call.

The **Checkout Session** is the object at the center of a Ringup payment. You create one the
moment an order is ready to pay, and it carries everything the payment step needs: the amount,
Ringup's [policy decision](/concepts/payment-policy) for this order, and, when payment runs by
transfer, the destination to send the live call.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://ringup.dev/api/tools/create_checkout \
    -H "Content-Type: application/json" \
    -H "X-Ringup-Merchant: tonys-pizza" \
    -d '{
      "amount_cents": 2500,
      "order_id": "sq_abc",
      "return_to": "sip:agent@your-number",
      "success_message": "You are all set, ready in fifteen minutes."
    }'
  ```

  ```javascript Node theme={null}
  const res = await fetch("https://ringup.dev/api/tools/create_checkout", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Ringup-Merchant": "tonys-pizza",
    },
    body: JSON.stringify({
      amount_cents: 2500,
      order_id: "sq_abc",
      return_to: "sip:agent@your-number",
      success_message: "You are all set, ready in fifteen minutes.",
    }),
  });
  const checkout = await res.json();
  ```

  ```python Python theme={null}
  import requests

  checkout = requests.post(
      "https://ringup.dev/api/tools/create_checkout",
      headers={"X-Ringup-Merchant": "tonys-pizza"},
      json={
          "amount_cents": 2500,
          "order_id": "sq_abc",
          "return_to": "sip:agent@your-number",
          "success_message": "You are all set, ready in fifteen minutes.",
      },
  ).json()
  ```
</CodeGroup>

```json Response theme={null}
{
  "id": "cs_x9f2",
  "payment_required": "required",
  "transfer_to": "sip:cs_x9f2@transfer.ringup.dev"
}
```

`amount_cents` is the only required field. `line_items`, `order_id`, `return_to`,
`success_message`, and `failure_message` are optional: `order_id` settles against an existing
order, `return_to` brings the caller back after payment, and `success_message` / `failure_message`
let Ringup speak the outcome and end the call. `transfer_to` comes back only in transfer mode and
embeds the session id. See the [API reference](/api-reference/introduction) for the full schema.

## Two ways it is delivered

A Checkout Session can reach the caller two ways, and the difference is invisible to your order
logic. Both start with the same `create_checkout`.

* **Native handoff.** On platforms that support it, payment runs inside the same call with no
  transfer. Your agent hands off to Ringup's payment step, which reads the session and takes
  payment in place.
* **Call transfer.** If you have ever used a hosted web checkout, you already know this shape. In
  a web checkout you create a session, redirect the browser to a hosted page, and pass a return
  URL; the customer pays and lands back on your site. A Ringup call transfer is the same over the
  phone: `transfer_to` is the checkout URL, transferring the call is the redirect, and `return_to`
  is the return URL. The caller pays on the Ringup line and the call comes back to your agent.

`transfer_to` (in the response) is where you send the call. `return_to` (in the request) is where
Ringup sends the caller back. They are the two ends of the same trip.

## Three ways a transfer ends

However the transfer ends, the payment itself is identical: Ringup charges the caller, texts them
an SMS receipt, and posts a [webhook](/concepts/webhooks) to your server. The three options below
change only what the caller hears and where the call goes next, never whether they get a receipt or
whether you get the webhook.

`return_to` and the spoken messages are complementary. Use whichever fits; you do not need both.

1. **Transfer back (`return_to`).** Ringup returns the caller to your agent and attaches the
   outcome as SIP headers, so your agent resumes already knowing payment succeeded and closes in
   its own voice. Best when you want to keep talking (upsell, fulfillment, goodbye).
2. **Ringup speaks the result (`success_message`).** No transfer back: Ringup reads your line and
   ends the call. Best when payment is the last thing on the call but you want the closing words in
   your words.
3. **Neither.** Ringup reads a short default confirmation and ends.

A `return_to` that cannot connect falls back to speaking `success_message` (or the default) and
ending, so a failed return never strands the caller.

## Reconcile from the webhook

However the call ends, your server learns the outcome from a `checkout.completed`
[webhook](/concepts/webhooks) carrying the **Payment**. That is your source of truth, independent
of what the caller heard.

If the caller has no saved card, Ringup instead [texts a pay link](/concepts/send-link); if you
already have a recognized caller and just want to run the card, [`charge`](/concepts/charge) skips
the session entirely.

## Next steps

<CardGroup cols={2}>
  <Card title="Payment Policy" icon="scale-balanced" href="/concepts/payment-policy">
    How Ringup decides payment\_required for the session.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/concepts/webhooks">
    Reconcile the outcome from the checkout.completed event.
  </Card>
</CardGroup>
