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

# Stripe Billing Subscriptions

> Keep the subscription in Stripe Billing and collect each invoice with the shopper's HSA/FSA card through Gale.

Use this when the subscription lives in your Stripe account: Stripe creates an invoice for each cycle, and tools that follow Stripe Billing act on `invoice.paid`. Gale charges the shopper's HSA/FSA card for each invoice and tells Stripe, so Stripe marks the invoice paid and keeps the subscription active.

Your system starts every charge. Gale keeps no schedule.

> [!NOTE]
>
> This flow is switched on per merchant account. Ask your Gale contact to enable it for your test account before you start.

## Who does what

| | Stripe | Gale | You |
| - | - | - | - |
| Subscription, plan, billing dates | Owns them | | Create and cancel them in Stripe |
| Card details | Never sees them | Collects them on its hosted page and stores the card | |
| Charging the card | | Charges it, first payment and renewals | Start each charge by API |
| Invoice status | Marks it paid when Gale attaches the payment | Attaches the payment | |
| Access to your product | Sends `invoice.paid` | Sends `order.completed` | Grant access from either |

## Before you start

* Create a custom payment method type in Stripe for Pay with FSA/HSA, as in Step 1 of the [Stripe Payment Element](https://docs.withgale.com/custom-payment-methods/elements-payment-intent.md#step-1-create-your-custom-payment-method) page. You need its `cpmt_...` id.
* Save a restricted key on [Gale on Stripe](https://docs.withgale.com/custom-payment-methods/gale-on-stripe.md). Set **Payment Records** to Write and **Invoices** to Write. Gale needs nothing on charges, balance or payouts.
* [Saved payment methods](https://docs.withgale.com/integration/saved-payment-methods.md) are enabled for your account.
* The product you sell is registered in your Gale catalog. Gale reviews each product for HSA/FSA eligibility. A digital product needs no UPC.

## How it works

1. You create the Stripe customer and the subscription, with your custom payment method as its default.
2. For the first invoice, you create a Gale checkout that stores the card and names the Stripe customer and invoice.
3. The shopper pays on Gale's page. Gale writes a payment record to your Stripe account and attaches it to the invoice.
4. Stripe marks the invoice paid and the subscription active, and sends `invoice.paid`.
5. For each renewal, Stripe sends you `invoice.payment_attempt_required`. You charge the stored card through Gale and name the new invoice.

## Step 1: Create the subscription in Stripe

Create a payment method of your custom type, attach it to the customer, and create the subscription with `payment_behavior: "default_incomplete"`.

```js theme={null}
const paymentMethod = await stripe.paymentMethods.create({
  type: 'custom',
  custom: { type: 'cpmt_...' },   // your Pay with FSA/HSA type id
});
await stripe.paymentMethods.attach(paymentMethod.id, { customer: customer.id });

const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [{ price: 'price_...' }],
  payment_behavior: 'default_incomplete',
  default_payment_method: paymentMethod.id,
});
// subscription.latest_invoice is the first invoice, status "open"
```

> [!WARNING]
>
> Stripe expires an incomplete subscription 23 hours after it is created. Send the shopper to the Gale checkout right away.

## Step 2: Collect the first invoice

Create a Gale checkout for the invoice amount. Three keys in `metadata` tie it to Stripe.

```json theme={null}
{
  "reference_id": "in_1Abc...",
  "customer": { "email": "jane@example.com", "first_name": "Jane", "last_name": "Doe" },
  "line_items": [
    { "product_id": "MEMBERSHIP", "name": "Monthly membership", "price": 2500, "quantity": 1, "currency": "USD" }
  ],
  "shipping_info": {
    "address_line_1": "1 Main St", "city": "Austin", "state": "TX", "postal_code": "78701", "country": "US"
  },
  "success_url": "https://yoursite.com/welcome",
  "failure_url": "https://yoursite.com/pricing",
  "setup_future_usage": "off_session",
  "metadata": {
    "payment_source": "stripe_elements_cpm",
    "stripe_customer_id": "cus_...",
    "stripe_invoice_id": "in_1Abc..."
  }
}
```

| Key | Value |
| - | - |
| `payment_source` | `stripe_elements_cpm`. Gale writes the payment to your Stripe account |
| `stripe_customer_id` | The customer on the invoice |
| `stripe_invoice_id` | The open invoice this payment settles. Needs `stripe_customer_id` |

The checkout total has to equal the invoice total. Stripe refuses a payment of a different amount.

`customer.email`, `customer.first_name` and `customer.last_name` are required. `customer.phone` is optional. `shipping_info` is required even for a digital product, so send the customer's billing address there. Card details are entered on Gale's page.

When the shopper pays, you receive `payment_method.id` on the `order.completed` webhook. Store it against the Stripe customer.

## Step 3: Collect each renewal

Listen for `invoice.payment_attempt_required` on your Stripe webhook. Charge the stored card for that invoice.

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/payment-methods/pm_.../charges \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Idempotency-Key: in_1Def...-attempt-1" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_id": "in_1Def...",
    "line_items": [
      { "product_id": "MEMBERSHIP", "name": "Monthly membership", "price": 2500, "quantity": 1, "currency": "USD" }
    ],
    "metadata": {
      "payment_source": "stripe_elements_cpm",
      "stripe_customer_id": "cus_...",
      "stripe_invoice_id": "in_1Def..."
    }
  }'
```

Gale charges the card, writes the payment record, and attaches it to the invoice. Stripe sends `invoice.paid` once the payment is captured.

## What you see where

| Event | Where it arrives |
| - | - |
| A cycle is due | Stripe: `invoice.payment_attempt_required` |
| The payment succeeded | Gale: `order.completed`. Stripe: `invoice.paid` |
| The card was declined | Gale: `422` on the charge, with a `checkout_url` for the shopper. The Stripe invoice stays open |
| A refund | Gale: `refund.created`, `refund.succeeded`, `refund.failed` |

## Declines

A declined renewal returns `422` with `PAYMENT_METHOD_010` and a `checkout_url`. Send that link to the shopper so they can pay with another card. Gale does not retry a declined charge. If you use Stripe's retry schedule, each retry sends `invoice.payment_attempt_required` again, and you call the charge again with a new `Idempotency-Key`.

## Refunds and disputes

Refund the Gale order with [`POST /api/v2/refunds`](https://docs.withgale.com/api-reference/endpoint/create-refund). Gale reports the refund to the payment record in Stripe. Stripe does not send `charge.refunded`, and Gale does not create a credit note. Create one in Stripe if your books need it.

Stripe does not hold disputes for payments processed outside Stripe, so a dispute on one of these payments does not appear in your Stripe account. Stripe lists this in its [limitations](https://docs.stripe.com/billing/subscriptions/third-party-payment-processing).

## Cancelling

Cancel the subscription in Stripe, the way you do today. There is nothing to cancel on Gale, because Gale only charges when you ask. If the customer wants their card removed, call [`DELETE /api/v2/payment-methods/{id}`](https://docs.withgale.com/api-reference/endpoint/delete-payment-method).

## Webhooks

Gale signs every webhook with `X-Gale-Signature` and retries a failed delivery. Add your endpoint in the Gale dashboard under **Developer Tools** > **Webhooks**. See [Webhooks](https://docs.withgale.com/developer-manual/webhooks.md) for the signature check and every event.

## Testing

Use a `glm_test_` key and a restricted key from your Stripe sandbox. Put the Stripe customer on a [test clock](https://docs.stripe.com/billing/testing/test-clocks) and advance it one cycle to make Stripe send `invoice.payment_attempt_required`. Pay with Gale's [test cards](https://docs.withgale.com/resources/test-cards).

## Limits

* One invoice per charge, and the amounts have to match.
* A renewal cannot mix eligible and non-eligible items, and cannot include an item that needs a Letter of Medical Necessity.
* To change the shopper's card, send them a new checkout with `setup_future_usage` and remove the old payment method.

## Related

* [Create Checkout Session](https://docs.withgale.com/api-reference/endpoint/create-checkout-v2.md)
* [Checkout Session Object](https://docs.withgale.com/api-reference/objects/checkout-session.md)
* [Payment Method Object](https://docs.withgale.com/api-reference/objects/payment-method.md)
* [Order Object](https://docs.withgale.com/api-reference/objects/order.md)
* [Create a refund](https://docs.withgale.com/api-reference/endpoint/create-refund.md)
* [Saved Payment Methods](https://docs.withgale.com/integration/saved-payment-methods.md)
* [Charge a Payment Method](https://docs.withgale.com/api-reference/endpoint/charge-payment-method.md)
* [Gale on Stripe](https://docs.withgale.com/custom-payment-methods/gale-on-stripe.md)
* [Webhooks](https://docs.withgale.com/developer-manual/webhooks.md)


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