> For the complete documentation index, see [llms.txt](https://docs.mdintegrations.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mdintegrations.com/partner/integration-paths/embedding-white-label-experiences.md).

# Embedding White-Label Experiences

MDI's hosted intake, messaging, and patient portal experiences are designed to be embedded directly inside your product with a standard HTML `<iframe>` — not just linked out to in a new tab. This page walks through the full embedding flow: getting a token, retrieving the right URL for the experience you want, dropping it into an iframe, authenticating the patient automatically where needed, and reacting to what happens inside the frame.

## Prerequisites

* API credentials (Client ID and Client Secret) — see [Authentication & Credentials](/partner/troubleshooting/technical-concepts/authentication-and-credentials.md) for how to generate these in the Admin Panel.
* A valid access token, obtained from the Authorization API using those credentials.
* The target patient's UUID (for Messaging and Patient Portal embeds).
* A frontend that can render an HTML `<iframe>` and handle JavaScript `postMessage` window events.

## Step 1: Generate an access token

Exchange your Client ID and Client Secret for a bearer token via the `client_credentials` grant. This is covered in full on the Authentication & Credentials page — the short version is a `POST` to the token endpoint with your `client_id`, `client_secret`, and `scope`.

Tokens expire after 30 minutes and must be regenerated the same way, so plan for that expiry rather than treating the token as long-lived. See [Token Expiration & Refresh](/partner/troubleshooting/technical-concepts/token-expiration-and-refresh.md) for a caching and refresh strategy.

## Step 2: Retrieve the right workflow URL

There are three distinct embeddable experiences, and each one comes from a different endpoint:

| Experience     | Endpoint                | Requires                                        | Returns                                      |
| -------------- | ----------------------- | ----------------------------------------------- | -------------------------------------------- |
| Intake Forms   | Voucher endpoint        | A questionnaire ID and one or more offering IDs | `onboarding_url` (pre-authenticated)         |
| Messaging      | Messaging-app endpoint  | A patient ID                                    | `url` and `verification_code`                |
| Patient Portal | Patient-portal endpoint | A patient ID                                    | `patient_portal_url` and `verification_code` |

The Intake Forms `onboarding_url` is already pre-authenticated, so there's no separate auth handshake to perform before embedding it. See [Questionnaires & Vouchers](/partner/key-concepts/questionnaires-and-vouchers.md) for how to find a questionnaire ID and create a Voucher.

Messaging and Patient Portal URLs, by contrast, come with a `verification_code` you'll need in Step 4.

## Step 3: Embed the iframe

Point a standard `<iframe>` at the URL you retrieved, and append `?fullscreen=true` to strip MDI's own branding and borders for a seamless white-label look:

```html
<iframe
  src="https://patient.mdintegrations.com/auth/abc123?fullscreen=true"
  allow="camera; microphone"
  width="100%"
  height="800"
></iframe>
```

The `allow="camera; microphone"` permissions are required, since the intro video step and file-capture steps inside the frame both depend on them. A recommended minimum size is 800px height and 100% width, so medical questions and upload buttons stay visible without internal scrolling.

## Step 4: Handle authentication (Messaging and Patient Portal only)

Intake/Voucher embeds are pre-authenticated and need no further setup. Messaging and Patient Portal embeds, however, require one extra handshake:

1. Listen for an `otp_ready` event posted from inside the iframe.
2. When it arrives, post a message back into the iframe containing the `verification_code` you saved from Step 2.

This authenticates the patient's session automatically, with no login or OTP-entry screen shown to them.

## Step 5: Subscribe to lifecycle events

Listen for `postMessage` events dispatched by the iframe to drive your own UI or redirects:

| Event               | Meaning                                                             |
| ------------------- | ------------------------------------------------------------------- |
| `start`             | The embedded flow has started.                                      |
| `step`              | The patient advanced to a new step within the flow.                 |
| `finish`            | The embedded flow completed.                                        |
| `encounter_created` | An Encounter was created as part of the flow.                       |
| `patient_created`   | A new Patient record was created as part of the flow.               |
| `otp_ready`         | The frame is ready to receive the `verification_code` (see Step 4). |

> **Note:** Account creation differs by workflow. Voucher/intake embeds create the Patient and Encounter automatically as part of the flow. Messaging and Patient Portal embeds require a patient record to already exist — you can't bootstrap a new patient from those two.

To avoid asking a returning patient the same demographic questions twice, pass an existing `patient_id` when creating a Voucher so the intake flow skips straight to clinical questions. See [Questionnaires & Vouchers](/partner/key-concepts/questionnaires-and-vouchers.md) for details.

## Related reading

* [Authentication & Credentials](/partner/troubleshooting/technical-concepts/authentication-and-credentials.md)
* [Questionnaires & Vouchers](/partner/key-concepts/questionnaires-and-vouchers.md)
* [Messaging](/partner/key-concepts/messaging.md)
* [White-Label Apps](/partner/integration-paths/white-label-apps.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.mdintegrations.com/partner/integration-paths/embedding-white-label-experiences.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
