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

# Packages, pricing and checkout

> Buy treatment plans (packages) through the API, and what price the patient is charged.

# Packages, pricing and checkout

Everything here works through the API — your patients never have to go to the VitaRelay
portal to buy.

## Patient ids

You don't need to store VitaRelay's patient id. Create the patient with your own
`external_patient_id` (`POST /patients`) and then use **that** id anywhere a patient is needed:
`external_patient_id` on `POST /orders` and `POST /intakes`, and in the path of
`/patients/{id}/payment-methods` and `/patients/{id}/partner`. The VitaRelay patient id (UUID) works
everywhere too. A patient who isn't in VitaRelay yet is created first with `POST /patients`, which
returns both ids.

## Who pays decides the price

| `billing_mode` | Who pays | Lines are priced at |
| - | - | - |
| `patient_checkout` | The **patient**, on your own page with Accept.js | **Your clinic's own storefront prices** |
| `card_on_file` (default) / `clinic_card` | **Your clinic's** saved card | VitaRelay catalog price — you bill your own customer yourself |

With `patient_checkout`, what the patient sees in your storefront is what they pay:

* A listed product is charged at its **shop price**.
* A package is charged at the **package price you set**. The price is spread exactly over
  the package's products, so the lines always add up to it, to the cent.
* The shop's **doctor consult fee** (503A orders) and a **shipping line** are added the
  same way as in your storefront. `total_cents` and `checkout.amount_cents` are the full
  amount the patient pays — display that total, don't recompute it.
* Your markup accrues to you once the order is paid, exactly like a storefront order.
* Pass `shipping_method` (`ground` or `overnight`) to carry the patient's delivery choice.

If your storefront isn't enabled, `patient_checkout` falls back to catalog prices.

### The doctor consult fee

The consult fee is **always charged** on a 503A order, and VitaRelay always collects its
base. Your clinic chooses only how it is *shown*: as its own line, or built into the
displayed product prices (the patient pays the same total either way). Shipping is
always its own line.

## Buying a package (treatment plan)

A package is an item in your storefront (`item_kind: "bundle"`, see `GET /shop`).

### One-time

```json theme={null}
POST /orders
{
  "patient_id": "…",
  "billing_mode": "patient_checkout",
  "items": [{ "item_kind": "bundle", "item_id": "<package id>", "quantity": 1 }]
}
```

The package goes through the normal prescription, consult-fee and fulfilment pipeline,
the same as product lines. A package that includes a **clinic service** can't be ordered
through the API (`422 bundle_has_services`); an unlisted or ineligible package returns
`422 product_not_found`.

### As a subscription

```json theme={null}
POST /orders
{
  "patient_id": "…",
  "payment_method_id": "<patient's saved card>",
  "items": [{ "item_kind": "bundle", "item_id": "<package id>",
              "purchase": "subscription", "cadence": "monthly", "quantity": 1 }]
}
```

A subscription needs the patient's **saved card** (`payment_method_id`) — a one-time purchase
does **not**; the patient just pays with the card form. If the patient has no saved card yet,
there are two ways to get one, neither needs the portal:

**A. Save a card without charging** — best when the patient is starting with a subscription:

1. Tokenize the card on your own page with Accept.js (you get a single-use nonce).
2. `POST /patients/{id}/payment-methods` with `{ "opaque_data": { "dataDescriptor": "…", "dataValue": "…" } }`.
   Billing details default to the patient record; nothing is charged.
3. Use the returned `id` as `payment_method_id` on the subscription order above.

You can list a patient's saved cards (brand, last four, expiry only) with
`GET /patients/{id}/payment-methods`.

**B. Save it while paying** — have the patient pay any order with `save_card: true` on
`POST /orders/{id}/pay`; the response returns `saved_payment_method_id`.

## 503B products

503B (bulk office-use) products are **never** available in a patient store, for any
organization. Adding one to your shop returns an error. A clinic can order 503B only
through Place Order, with an NPI and your office address on file.


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