> This page is for version v1 (default).
> For other versions, use one of these documentation indexes:
> - v1 (default): https://developers.truemed.com/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.truemed.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.truemed.com/_mcp/server.

# Recurring charges

> Charge a stored payment token on your own billing schedule, and keep tokens chargeable over time.

Once you have a `payment_token`, each billing period is a normal `create_payment_session` call with
the token attached. The customer isn't present and there's no redirect—Truemed charges the card on
file.

Your system decides when to charge. Truemed decides whether the charge is allowed.

## Charge a stored token

Pass `payment_token` instead of collecting customer details. Amounts are integers in cents.

```bash
curl https://api.truemed.com/payments/v1/create_payment_session \
  -X POST \
  -H "Content-Type: application/json" \
  -H "x-truemed-api-key: $TRUEMED_API_KEY" \
  -d '{
    "payment_token": "dev_tm_token_8a1f0c2e-77b4-4f0a-9c31-2f5c7a9d4e10",
    "total_amount": 4200,
    "success_url": "https://example.com/account/orders",
    "failure_url": "https://example.com/account/orders",
    "idempotency_key": "sub_12345_period_7",
    "metadata": "subscription_12345",
    "order_items": [
      {
        "name": "Monthly B12",
        "quantity": 1,
        "sku": "b12-monthly",
        "price": 4200,
        "amount_details": {}
      }
    ],
    "amount_details": {}
  }'
```

```json
{
  "id": "e7d2b810-4a3c-4c11-9f5e-0c8a1b2d3e4f"
}
```

A `200` means the charge was accepted, not that funds are secured. Use a distinct `idempotency_key`
per billing period so a retried request doesn't double-charge.

> **Warning**
>
> **`order_items` must match what you're actually billing for on this charge.** Unlike a normal card
> payment, where only the amount matters, Truemed re-checks eligibility against the items on *every*
> charge. The customer's LMN covers specific items—anything outside it is blocked with a `422` and
> `next_action: "TakeHealthSurvey"`, and the billing period fails.
>
> This catches people out in two ways:
>
> * **Reusing a hardcoded or stale `order_items` payload** across billing periods. It works until the
>   subscription changes, then silently starts failing.
> * **Changing the subscription in your system without telling Truemed.** Call
>   [`update_payment_token`](/api-reference/payment-tokens/update-payment-token) at the moment items
>   change, not at charge time—see [Update a Subscription](/guides/setup/api/subscriptions/update-an-active-subscription).

## Fulfillment rules

Fulfill from the `payment_session_complete` webhook, exactly as with a one-time payment. A stored-token
charge returns no `redirect_url`—the field appears only on a `422`, where it's where you send the
customer to resolve the block.

| Status       | Customer communication                                         | Fulfillment behavior                                                |
| ------------ | -------------------------------------------------------------- | ------------------------------------------------------------------- |
| `processing` | Nothing, or "your order is being prepared".                    | Do not fulfill yet.                                                 |
| `captured`   | Confirm the order is paid.                                     | Fulfill the order.                                                  |
| `rejected`   | Tell the customer this period's payment couldn't be completed. | Don't fulfill. Ask for another payment method or retry next period. |

Make fulfillment idempotent—webhooks are at-least-once, so the same status can arrive more than once.
See [Webhooks and Fulfillment](/guides/setup/api/payment-sessions/webhooks-and-fulfillment) for the full handler
checklist.

## Prevent failures before they happen

Truemed does not warn you before a token stops working, and does not email your customers. Catching
expirations ahead of the charge is your job, and it's the difference between a customer who renews and
one who churns.

* [ ] **Store expiration dates on every token.** Keep `lmn_expires_at` and the card `expiration` from
  [`retrieve_payment_token`](/api-reference/payment-tokens/retrieve-payment-token) alongside your
  subscription record.
* [ ] **Run a daily expiration sweep.** Query
  [`list_payment_token`](/api-reference/payment-tokens/list-payment-token) with `lmn_expires_before`
  and `card_expires_before` set about 30 days out. `lmn_expires_before` only returns LMNs expiring
  between today and that date—already-lapsed ones are excluded, which is why you keep your own copy of
  `lmn_expires_at`. See [Partner Operations](/guides/setup/api/subscriptions/partner-administrative-operations#monitor-expirations).
* [ ] **Prompt those customers before their next charge.** Email them a link generated with
  [`update_payment_token`](/api-reference/payment-tokens/update-payment-token), escalating as the date
  gets closer. For an expiring card send `update_card_info: true`; for an expiring LMN send
  `renew_eligibility: true` with the subscription's current `order_items`, or the response comes back
  `next_action: "None"` with nothing to link to. See [Renew eligibility before the LMN expires](/guides/setup/api/subscriptions/update-an-active-subscription#renew-eligibility-before-the-lmn-expires).
* [ ] **Call `update_payment_token` whenever subscription items change**—at the moment of the change,
  not at charge time. A cart change that falls outside the existing LMN blocks the next charge. See
  [Update a Subscription](/guides/setup/api/subscriptions/update-an-active-subscription).

## When a charge fails

A blocked charge returns `422` with a `next_action` telling you what the customer has to do, and a
`redirect_url` to send them to. The customer isn't present, so you'll relay this by email and wait for
`payment_token_updated` before charging again.

[Token Lifecycle](/guides/setup/api/subscriptions/token-lifecycle) covers every failure cause, the
recovery loop, and suggested customer messaging.

## Next steps

#### [Token Lifecycle](/guides/setup/api/subscriptions/token-lifecycle)

Every failure state and how to recover a blocked subscription.

#### [Testing](/guides/setup/api/subscriptions/testing)

Run a full token lifecycle in the sandbox before going live.