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

# Charge

> Charge a recognized caller's saved card off-session, settling on the merchant's own processor. Idempotent, and only true when the result says succeeded.

`charge` runs a recognized caller's saved card. The caller is already known by phone number, so
there is no Checkout Session to create and no link to text: you pass the amount, and Ringup charges
the card <Tooltip tip="A charge run against a card the caller saved earlier, with their consent, while they are not actively entering card details.">off-session</Tooltip>
and settles the money on the merchant's own processor.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://ringup.dev/api/tools/charge \
    -H "Content-Type: application/json" \
    -H "X-Caller-Number: +14155550142" \
    -H "X-Ringup-Merchant: tonys-pizza" \
    -H "X-Call-Id: call_abc123" \
    -d '{ "amount_cents": 8500, "description": "Front brake pads, 2022 Toyota Highlander" }'
  ```

  ```javascript Node theme={null}
  const res = await fetch("https://ringup.dev/api/tools/charge", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Caller-Number": "+14155550142",
      "X-Ringup-Merchant": "tonys-pizza",
      "X-Call-Id": "call_abc123",
    },
    body: JSON.stringify({
      amount_cents: 8500,
      description: "Front brake pads, 2022 Toyota Highlander",
    }),
  });
  const payment = await res.json();
  ```

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

  payment = requests.post(
      "https://ringup.dev/api/tools/charge",
      headers={
          "X-Caller-Number": "+14155550142",
          "X-Ringup-Merchant": "tonys-pizza",
          "X-Call-Id": "call_abc123",
      },
      json={"amount_cents": 8500, "description": "Front brake pads, 2022 Toyota Highlander"},
  ).json()
  ```
</CodeGroup>

```json Response theme={null}
{
  "ok": true,
  "status": "succeeded",
  "payment_id": "pay_x",
  "order_id": "ord_x",
  "confirmation": "2PJJZY",
  "charged": { "brand": "VISA", "last_4": "5858", "amount_cents": 8500 }
}
```

`amount_cents` is the only required field. `description` and `order_id` are optional, and
`X-Call-Id` keys [idempotency](#idempotent-under-retries) so a retry within a call never
double-charges. `status` is `succeeded`, `failed`, or `pending`; only `succeeded` moved money.

## Only after the caller agrees, and only `succeeded` is true

Charge the card only after the caller verbally agrees to the amount. The result is ground truth:
never tell the caller payment happened without a `succeeded` status and a `payment_id`. A `failed`
status means nothing was charged, and `pending` means the money has not moved yet. Speak the
`confirmation` code back only on `succeeded`.

## Idempotent under retries

The charge is idempotent, keyed on the call and amount, so if the platform retries the tool call,
the caller is charged once and the retry returns the original Payment. This is what makes it safe
on platforms that auto-retry a function that does not answer fast enough.

## With or without an order

* **With `order_id`,** the Payment attaches to that order, so your system reconciles the two
  directly.
* **Without it,** Ringup creates a minimal order to hang the Payment on, and echoes its id back so
  you still have something to match against.

Whether or not you pass one, your server gets the same `checkout.completed`
[webhook](/concepts/webhooks) as its out-of-band record. If the caller has no saved card yet, use
[`send_link`](/concepts/send-link) instead; if you want Ringup to run the whole payment step for
you, create a [Checkout Session](/concepts/checkout-session). Whether payment is required at all is
the merchant's [policy](/concepts/payment-policy).

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/concepts/webhooks">
    Your out-of-band source of truth for every charge.
  </Card>

  <Card title="Testing" icon="flask" href="/concepts/testing">
    The fixtures and cards to exercise a charge end to end.
  </Card>
</CardGroup>
