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

# The patient flow

> The stages a patient moves through from first click to delivered order, the public status vocabulary your storefront reads, and where the payment step sits.

A patient's enrollment is one continuous flow: they arrive on your storefront, answer the intake
questionnaire, sign in, verify their identity, pay, and a clinician reviews the case — then the
order ships. Your storefront never drives that flow; it **observes** it through one read and a
webhook stream, and surfaces the platform's answer to the patient. This page walks the stages
end-to-end, defines the eleven status values, and covers the other documented outcomes this read
can return.

## The stages, end to end

1. **Arrival.** The patient lands on your storefront and starts an enrollment — through an entry
   link or your own [headless start](/pages/integrate/how-it-works#1-send-a-patient-in). An
   enrollment id (`jny_...`) exists from this first step, and the status read accepts it right
   away — but a status value is not the only documented outcome. The read may instead return
   [no status yet](#when-a-status-is-not-yet-reportable), so do not assume a status value on the
   first read.
2. **The intake questionnaire.** The server serves the questionnaire
   [one question at a time](/pages/integrate/how-serving-works); the patient answers until it is
   complete.
3. **Sign-in and identity.** The patient signs in (passwordless) and proves their identity on the
   [hosted identity step](/pages/integrate/the-identity-handoff). Neither step changes the public
   status — a patient mid-verification simply keeps the status they had.
4. **Payment.** The patient pays through [the checkout door](/pages/integrate/the-checkout-door).
   Where this step sits is configured per program — see
   [the ordering note](#where-the-payment-step-sits) below.
5. **Clinical review.** A licensed clinician reviews the completed case and decides. Your
   storefront never announces an outcome before the review returns it.
6. **Fulfillment.** An approved order is prepared, shipped, and delivered. The vocabulary carries
   these stages so your handling is complete; enrollments begin reporting them when shipment
   tracking arrives on the platform.

## Read the status

One endpoint tells you where a patient is:
[`GET /v1/journeys/{journey_id}/status`](/api-reference/enrollment/read-a-patients-public-enrollment-status).

```bash theme={null}
curl "$BASE_URL/v1/journeys/jny_31f8k2/status" \
  --header "Authorization: Bearer $TEST_API_KEY" \
  --header "X-Brand-Id: $BRAND_ID"
```

```json theme={null}
{
  "journey_id": "jny_31f8k2",
  "public_status": "IN_REVIEW",
  "status_version": "v1"
}
```

Identifiers and a status value only — never patient data, never an answer, never a clinical
detail. The read is a pure view: calling it changes nothing, and nothing on the platform ever uses
it as an input. Poll it as often as you like, or let webhooks tell you when to re-read.

### When a status is not yet reportable

A `200` carrying `public_status` is not the only documented outcome of this read. It sits alongside
the refusals every key-authenticated call can return — `401` when the key is missing or not valid,
`404` when the enrollment is unknown or not yours, `400` on a malformed id — plus two more the
contract declares specifically for this read. **Keep your normal authentication and error
handling; what follows is in addition to it, not a replacement for it.**

**`422` — a typed "no status yet" response.** When the platform has no status to report for an
enrollment, this read returns `422` instead of a status value. The `type` is a stable,
machine-readable token, and you can branch on it today:

```
https://purple.md/problems/journey-status-pending
```

The platform currently returns it with this body:

```json theme={null}
{
  "type": "https://purple.md/problems/journey-status-pending",
  "title": "Enrollment status not yet available",
  "status": 422,
  "detail": "This enrollment exists — it was started through the hosted intake experience under your brand. Reporting live status for enrollments started there is a declared platform capability that is not yet in service, so no status can be returned for it yet. Retrying this read will not change the answer; once the capability ships, this same read will return the status."
}
```

That `detail` is the platform describing the situation it is in at the time of the call. **Branch
on the `type`; read `detail` as explanation, not as a promise this page is making to you** — the
circumstances a `422` covers can change, and the `type` is the part that stays stable.

Two things to design around:

* **It is not a failed call and not a missing enrollment.** Your request was well-formed and the
  enrollment is yours. Do not treat it as a `404`, and do not surface it to the patient as an
  error.
* **The body carries nothing patient-specific** — no enrollment id, no brand, no detail about the
  person — so nothing in it can be read as information about a particular patient.

Treat `422` as a state your storefront can sit in: show that enrollment status is currently
unavailable, and **do not infer clinical progress or completion from it** — a missing status is
not evidence of movement. Re-read with bounded backoff rather than in a tight loop — the body
above tells you a retry will not change the answer, so re-reading is how your integration notices
a later change of state, never a way to force one.

**`503` — the read itself did not succeed.** The status source was unavailable, so the platform
could not tell you where the enrollment is. **This says nothing about the enrollment** — it may
have moved on, it may not have. Retry with backoff, and never treat the absence of an answer as an
answer.

## The status vocabulary

When the read answers `200`, `public_status` is one of exactly eleven values. Each value is **stable within `v1`** — if a
value's meaning ever needs to change, the platform publishes a new `status_version` rather than
quietly editing this one, so your handling can never be silently invalidated.

| Status          | The patient is...                                                                                                      | What your storefront does                                                            |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `RECEIVED`      | Started — the enrollment exists and intake is underway or just submitted.                                              | Show progress; nothing is decided yet.                                               |
| `IN_REVIEW`     | Waiting on the platform — the case is with the clinical review, or has cleared it and the order is not yet authorized. | Show "in review"; no action from the patient.                                        |
| `ACTION_NEEDED` | Needed — the review needs something more from the patient, or they dropped off mid-flow.                               | Bring the patient back in; the platform has told them what it needs.                 |
| `APPROVED`      | Approved — the review cleared the case and the order is authorized.                                                    | Show the approval.                                                                   |
| `DECLINED`      | Declined — the review did not clear the case.                                                                          | Show the outcome plainly; the platform has communicated the decision to the patient. |
| `ON_HOLD`       | Paused — the review put the case on hold.                                                                              | Show a holding state; no patient action unless the platform asks.                    |
| `PREPARING`     | Approved and in the pharmacy's hands — the order is being prepared.                                                    | Show fulfillment progress.                                                           |
| `SHIPPED`       | Shipped — the order is on its way.                                                                                     | Show shipment progress.                                                              |
| `DELIVERED`     | Delivered — the order arrived.                                                                                         | Close the loop.                                                                      |
| `SUPERSEDED`    | Replaced — a newer decision on this patient replaced this one.                                                         | Follow the patient's current enrollment instead.                                     |
| `REFILL_DUE`    | Due — the plan has a refill coming up.                                                                                 | Prompt the patient if your program surfaces refills.                                 |

Two rules of the vocabulary worth designing around:

* **The status never runs ahead of the money.** A patient never shows `APPROVED` before their
  order is actually authorized — so "approved" on your storefront always means a real, backed
  order, never a prediction.
* **Quiet steps stay quiet.** Sign-in, identity verification, and a completed payment do not have
  their own statuses — the enrollment keeps its current value through them. If you need
  payment-level detail for an order, read
  [the payment status endpoint](/api-reference/payments/read-the-payment-status-of-an-order)
  instead.

## Where the payment step sits

By default a patient **finishes the questionnaire first and pays afterwards**, before the clinical
review — the sequence the [how it works](/pages/integrate/how-it-works) guide describes. Programs
can instead be configured **pay-first**, where payment is collected before the questionnaire
begins.

The ordering is a per-program setting, arranged with your onboarding contact — it can be set for
your whole account or for a single offering, and the more specific setting wins. Three facts hold
either way:

* **Each enrollment picks its ordering once, at its start**, and keeps it — a configuration change
  never reshuffles a patient already in flight.
* **The clinical and identity safeguards are identical in both orderings** — pay-first changes
  when the card is collected, never what the review requires.
* **A payment is never a decision.** Paying first does not advance the public status past the
  review; the case still shows `IN_REVIEW` until the clinician decides.

## Watching without polling

Every status change also reaches you through [webhooks](/pages/integrate/how-it-works#3-observe-progress):
register an endpoint, receive the reference-only event, and re-read the status endpoint for the
current value. The [walkthrough](/pages/integrate/walkthrough) wires this end to end.
