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

# Saved Payment Methods

> Store a shopper's card during checkout, then charge it later from your own system.

Use this when your own system decides when to charge and how much: prescription refills, renewals on a schedule you run, or any later order the shopper has agreed to. The shopper pays once on Gale's hosted checkout and agrees to later charges. Gale gives you a payment method id, and you charge it by API with the shopper absent.

Gale keeps no schedule for these charges. If you want Gale to run the plan and the renewals, use [Subscriptions](https://docs.withgale.com/developer-manual/subscriptions).

> [!NOTE]
>
> Saved payment methods are switched on per merchant account. Ask your Gale contact to enable them for your test account before you start.

## How it works

1. Your server creates a checkout with `setup_future_usage: "off_session"`.
2. The shopper ticks a consent box on the hosted page and pays.
3. Gale stores the card and returns a `payment_method` with an id that starts with `pm_`.
4. Later, your server calls `POST /api/v2/payment-methods/{id}/charges` with the items and amounts for that order.
5. Gale charges the card, creates an order, and sends `order.completed`.

## Step 1: Ask for storage at checkout

Create the checkout as usual and add one field.

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/checkout \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "order-1001",
    "customer": { "email": "jane@example.com", "first_name": "Jane", "last_name": "Doe" },
    "line_items": [
      { "product_id": "RX-100", "name": "Monthly prescription", "price": 4500, "quantity": 1, "currency": "USD" }
    ],
    "shipping_info": {
      "address_line_1": "1 Main St", "city": "Austin", "state": "TX", "postal_code": "78701", "country": "US"
    },
    "success_url": "https://example.com/success",
    "failure_url": "https://example.com/failure",
    "setup_future_usage": "off_session"
  }'
```

The response includes `setup_future_usage: "off_session"` and the `checkout_url` to send the shopper to.

| Answer | Meaning |
| - | - |
| `201` | Checkout created. The hosted page asks the shopper for consent. |
| `422` `CHECKOUT_002` | Saved payment methods are not enabled for this account. |
| `422` `CHECKOUT_003` | The order mixes HSA/FSA eligible and non-eligible items. One stored card cannot pay both parts. |

## Step 2: The shopper consents and pays

The hosted page shows a consent box for later charges. The shopper cannot pay until it is ticked. Gale records the consent with the payment.

## Step 3: Receive the payment method

Once the card is stored, the same `payment_method` object appears in three places:

* `GET /api/v2/checkout/{id}`
* the `order.completed` webhook for that order
* the `payment_method.saved` webhook

```json theme={null}
{
  "id": "pm_fc61f9c445dd477287c47052087dc91c",
  "type": "card",
  "brand": "visa",
  "last4": "1111",
  "exp_month": "03",
  "exp_year": "2030",
  "usage": "off_session",
  "status": "active",
  "checkout_id": "cs_abc123",
  "customer_email": "jane@example.com",
  "last_used_at": null,
  "created_at": "2026-11-10T21:04:11Z"
}
```

Store the `id` against your customer. Gale never returns the card number.

## Step 4: Charge the card later

Send the items for this order. Amounts are integers in cents. An `Idempotency-Key` header of 22 to 255 characters is required. Use one key per order: the same key sent again returns the first result and never charges twice.

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/payment-methods/pm_fc61f9c445dd477287c47052087dc91c/charges \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Idempotency-Key: refill-2026-12-order-0042" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "refill-2026-12-0042",
    "line_items": [
      { "product_id": "RX-100", "name": "Monthly prescription", "price": 4500, "quantity": 1, "currency": "USD" }
    ],
    "shipping": 500,
    "tax": 0,
    "discount": 0
  }'
```

| Field | Required | Notes |
| - | - | - |
| `reference_id` | Yes | Your id for this order. |
| `line_items` | Yes | Same shape as a checkout. Eligibility is checked again for these items on every charge. |
| `shipping`, `tax`, `discount` | No | Cents. Default `0`. |
| `metadata` | No | Returned on the order. |
| `customer`, `shipping_info`, `billing_info` | No | Default to the checkout that stored the card. |

A successful charge returns `201` with the order.

```json theme={null}
{
  "data": {
    "id": "ord_01ABC...",
    "status": "completed",
    "payment_status": "captured",
    "amount": 5000,
    "reference_id": "refill-2026-12-0042",
    "payment_method": { "id": "pm_fc61f9c445dd477287c47052087dc91c", "brand": "visa", "last4": "1111" }
  }
}
```

Gale also sends `order.completed` with the same `payment_method` block. Fulfil from the webhook, as you do for a checkout.

## When a charge does not go through

| Answer | Meaning | What to do |
| - | - | - |
| `422` `PAYMENT_METHOD_010` | The card was declined. | Send the shopper the `checkout_url` from `error.details` so they can pay this order with another card. |
| `503` `PAYMENT_METHOD_011` | Not completed. No money was taken. | Retry with the same `Idempotency-Key`, or a new one when `error.details.retry_with_new_key` is `true`. |
| `503` `PAYMENT_METHOD_012` | Not confirmed. | Retry with the same `Idempotency-Key` only. |
| `409` `PAYMENT_METHOD_015` | A request with this key is still being processed. | Retry shortly with the same key. |
| `422` `PAYMENT_METHOD_003` to `PAYMENT_METHOD_009` | Refused before any charge. | Fix the request. See below. |
| `404` `PAYMENT_METHOD_001` | Unknown id, or a card stored in the other mode (test or live). | Check the id and the key. |

A decline looks like this:

```json theme={null}
{
  "error": {
    "code": "PAYMENT_METHOD_010",
    "message": "The card was declined. No money was taken.",
    "details": {
      "decline_code": "6",
      "decline_reason": "shopper_correctable",
      "retryable": false,
      "order_id": "ord_01ABD...",
      "checkout_url": "<hosted checkout link for this order>"
    }
  }
}
```

Gale also sends `payment.failed` for a declined charge. Gale does not retry a declined charge for you.

A charge is refused before the card is touched when:

* the card was removed,
* the card was stored without consent to later charges,
* the order mixes eligible and non-eligible items,
* an item in the order needs a Letter of Medical Necessity. The shopper has to complete that on the hosted checkout.

## Manage stored cards

| Call | What it does |
| - | - |
| `GET /api/v2/payment-methods` | List stored cards. Filter with `checkout_id`, `customer_email`, `limit`. |
| `GET /api/v2/payment-methods/{id}` | Read one. |
| `DELETE /api/v2/payment-methods/{id}` | Remove a card. Safe to call twice. |

Remove a card when the shopper asks you to. A removed card cannot be charged again.

## Refunds

Refund an order from a stored card the same way as any other order, with [`POST /api/v2/refunds`](https://docs.withgale.com/api-reference/endpoint/create-refund).

## Test and live

A card stored with a `glm_test_` key can only be charged with a `glm_test_` key, and the same holds for live. Use Gale's test cards in test mode.

## Limits

* A card is stored only on a paid checkout.
* To change a shopper's card, create a new checkout with `setup_future_usage` and remove the old payment method.
* One checkout stores one card.
* A stored-card charge cannot mix eligible and non-eligible items, and cannot include an item that needs a Letter of Medical Necessity.

## Reference

* [Payment Method Object](https://docs.withgale.com/api-reference/objects/payment-method.md)
* [Charge a Payment Method](https://docs.withgale.com/api-reference/endpoint/charge-payment-method.md)
* [List](https://docs.withgale.com/api-reference/endpoint/list-payment-methods.md), [Get](https://docs.withgale.com/api-reference/endpoint/get-payment-method.md) and [Remove](https://docs.withgale.com/api-reference/endpoint/delete-payment-method.md) a payment method
* [Webhooks](https://docs.withgale.com/developer-manual/webhooks.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.