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 ownexternal_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
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_centsandcheckout.amount_centsare 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(groundorovernight) to carry the patient’s delivery choice.
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
422 bundle_has_services); an unlisted or ineligible package returns
422 product_not_found.
As a subscription
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:
- Tokenize the card on your own page with Accept.js (you get a single-use nonce).
POST /patients/{id}/payment-methodswith{ "opaque_data": { "dataDescriptor": "…", "dataValue": "…" } }. Billing details default to the patient record; nothing is charged.- Use the returned
idaspayment_method_idon the subscription order above.
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.

