This guide walks through adding a form to your website that lets a patient enter their payment details (credit card, bank account, or Apple Pay). The details are saved securely — no payment is taken.
There are two ways to use this:
- Iframe mode — embed the form inside your page. Apple Pay is not available in this mode.
- Redirect mode — link the patient to the form directly, then redirect them back to your site when done. Supports Apple Pay.
Step 1: Build the URL
Construct the URL for the store details form:
https://app.decodahealth.com/{tenant}/embed/store-details/{patientId}
Replace:
{tenant} — your organization’s subdomain
{patientId} — the patient’s ID
URL parameters
| Parameter | Description |
|---|
theme | light or dark |
showHeader | true (default) or false to hide the patient name at the top |
allowedMethods | Comma-separated payment methods: CARD, ACH, APPLE_PAY. Default is CARD,ACH,APPLE_PAY. |
redirect_url | URL to redirect the patient to after saving (adds status, patientId, and on success paymentMethodId) |
redirectParent | true with redirect_url and an iframe: navigate the top browser window to your redirect URL (so your own page’s query string includes paymentMethodId). Without this, only the iframe navigates and your site’s address bar does not update. |
Simplest pattern if you use an iframe and want paymentMethodId in your page URL: add both redirect_url and redirectParent=true to the embed src. No postMessage handler required (we still send postMessage for compatibility).
Option A: Iframe mode
Embed the URL in an iframe on your site:
<iframe
src="https://app.decodahealth.com/your-tenant/embed/store-details/pat_xxx"
width="100%"
height="400px"
style="border: none; border-radius: 8px;"
></iframe>
Listen for events via postMessage:
window.addEventListener('message', function (event) {
if (event.data.type === 'store_details_success') {
// Decoda payment method id — use with POST .../billing/payment-terminal/charge-card/{paymentMethodId}
const paymentMethodId = event.data.paymentMethodId;
// If you passed redirect_url, the iframe navigates internally; your top-level page URL does not change.
// Use paymentMethodId here, or navigate the top window yourself:
if (event.data.fullRedirectUrl) {
window.location.assign(event.data.fullRedirectUrl);
}
} else if (event.data.type === 'store_details_failure') {
// Something went wrong — event.data.error has details
} else if (event.data.type === 'store_details_loaded') {
// Form is ready
}
});
Apple Pay requires the payment form to be on the top-level page, not inside an iframe. If you need Apple Pay, use redirect mode instead.
Getting paymentMethodId (for charge-card and follow-up payments)
After the patient saves a card or bank account, Decoda creates a tenant payment method record. The id you need for POST /billing/payment-terminal/charge-card/{payment_method_id} is paymentMethodId (camelCase in JSON and query strings).
-
Iframe embed (recommended) — Read it from
postMessage on success:
event.data.paymentMethodId — Decoda id (not Rainforest’s id).
- If you used
redirect_url, the embed also sends event.data.fullRedirectUrl: the same URL it would open inside the iframe (includes status, patientId, paymentMethodId). The parent page’s address bar does not update automatically when the form is in an iframe; either use event.data.paymentMethodId in your own state or call window.location.assign(event.data.fullRedirectUrl) if you want the top-level browser URL to match.
-
Top-level redirect (no iframe) — Open the store-details URL with
redirect_url as the main window. After save, the patient is sent to your URL with query parameters including paymentMethodId.
-
Iframe + your URL in the address bar — Add
redirectParent=true alongside redirect_url on the embed src. The whole tab will navigate to your redirect URL with paymentMethodId in the query string (no postMessage required).
Behind the scenes, after Rainforest fires approved, the console calls POST /billing/embed-store-details/{patientId}/payment-method with the Rainforest payment method id; the API returns the saved Decoda payment method (including id). If that request fails, the user sees a failure state and paymentMethodId is not produced.
Event types
| Event | When it fires |
|---|
store_details_loaded | The form finished loading and is ready for input |
store_details_success | The patient’s payment details were saved (paymentMethodId present when registration succeeded) |
store_details_failure | The save failed (declined card, network error, etc.) |
store_details_error | The form could not load at all |
Option B: Redirect mode (supports Apple Pay)
Link the patient directly to the store details page with a redirect_url parameter. After saving their payment details, the patient is redirected back to your site.
<a href="https://app.decodahealth.com/your-tenant/embed/store-details/pat_xxx?redirect_url=https://yoursite.com/done">
Save Payment Method
</a>
After the patient saves their details, they are redirected to:
https://yoursite.com/done?status=success&patientId=pat_xxx&paymentMethodId=pm_xxx
If the save fails:
https://yoursite.com/done?status=failure&patientId=pat_xxx&error=The+method+was+declined
Redirect parameters
| Parameter | Description |
|---|
status | success or failure |
patientId | The patient’s ID |
paymentMethodId | Decoda payment method id (success only). Use with charge-card/{paymentMethodId}. |
error | Error message (only present when status=failure) |
Because the form loads as the top-level page (not in an iframe), Apple Pay is fully supported in this mode.
API flow
When the page loads, it calls the Create Embed Store Details Config endpoint. The endpoint:
- Looks up the patient.
- Creates a Rainforest payment method configuration tied to that patient.
- Returns the session key and config ID.
The form uses these to initialize the Rainforest payment component in “store details” mode — it collects the card or bank account and saves it without taking a payment.
When Rainforest reports success (approved), the page calls POST /billing/embed-store-details/{patientId}/payment-method (public, same auth rules as the config endpoint) with the Rainforest payment method id. That endpoint loads the method from Rainforest and creates or reuses the Decoda PaymentMethod row. The returned id is what you receive as paymentMethodId in postMessage and redirect query parameters.
Charging the saved card (charge-card)
paymentMethodId is the Decoda id (pm_…). To run the charge you still need a Rainforest pay-in configuration for the outstanding charge:
POST /billing/payment-terminal/payin-config — body includes your charge(s), payment medium, merchant account, etc. (same idea as setting up the virtual terminal). The response includes payinConfigId.
POST /billing/payment-terminal/charge-card/{paymentMethodId} — JSON body only:
Do not send chargeId or amount on charge-card; those are not part of this body. A missing payinConfigId often surfaces from Rainforest as “Field is required”.
See Charge payment method for the full note.
Using it from the console
You can also generate embed code from the Payment Management settings page. Look for the Embed Store Details Component section, where you can:
- Search for a patient
- Choose the theme, dimensions, and allowed payment methods
- Set a redirect URL for Apple Pay support
- Preview the form
- Copy the ready-to-use code