Intake & provider approval
An embeddable per-product questionnaire, evaluated deterministically to a verdict, then reviewed by a licensed provider — and only an approved intake lets an order proceed.
Before a compounded drug ships, someone has to establish that it's appropriate for this patient. neolife makes that a first-class object: a versioned questionnaire the patient answers, a deterministic verdict derived from those answers, and a licensed provider's approval on top. An order can't be submitted until an intake has been approved — the rail enforces the clinical gate, so your integration doesn't have to.
The shape of an intake#
An intake questionnaire is a versioned document tied to a product (or product family). Each version has:
- A stable
key(e.g.glp-weightloss) and aversionplus aneffectiveDate. - A list of questions — text, numeric, single/multi choice, consent blocks, uploads, and display-only info.
- Rules the engine runs over the answers: conditional visibility, disqualifying answers, computed values (e.g. BMI from height + weight), and product/dose routing.
You author and publish versions through the API; publishing a change mints a new immutable version. Every submission is pinned to the exact version it was answered against, which is what makes a verdict reproducible later — store the version pin and the answers, and the verdict can always be re-derived.
Submitting an intake#
There are two ways answers reach the rail, and they resolve to the same evaluation and the same object.
In-app — your staff (or your own patient-facing UI) submits answers through the authenticated API on a patient's behalf. This is a normal Bearer-authenticated call. See /api/intake.
The public embed widget — a drop-in questionnaire the patient completes directly, hosted at /public/intake. It authenticates with a per-tenant embed key (not your secret API key), is origin-locked to your domains, and returns a patient-safe response — verdict and certificate only, never the internal rule detail or the provider packet. This is the surface to use when the patient fills out the form themselves, on your storefront:
<div id="neolife-intake"></div>
<script
src="https://api.neolife.health/embed/intake.js"
data-embed-key="pk_embed_…"
data-questionnaire="glp-weightloss"
data-target="#neolife-intake"></script>
Both paths accept an Idempotency-Key so a retried submission is never counted twice.
The verdict#
Evaluation is a pure function of (questionnaire version, answers) — no model sits in the eligibility path. The engine returns one of three verdicts:
| Verdict | Meaning | What happens next |
|---|---|---|
eligible |
Complete, and no disqualifying answer. | Enters provider review (pending_review). |
disqualified |
A disqualifying answer or a rule guard hit. | Hard stop — no provider can override it into an order. |
incomplete |
A required, visible question is unanswered. | Nothing ships; finish the missing answers. |
Because it's deterministic, the same answers always yield the same verdict. A disqualification is decisive even when other answers are missing — a hard stop is a hard stop.
The certificate#
An eligible submission is issued a certificate: a tamper-evident record binding the questionnaire key + version, the answers, the verdict, and the timestamp under a single hash. It's the durable proof that this patient answered this version of the questions and cleared the deterministic gate.
{
"submissionId": "sub_…",
"verdict": "eligible",
"certificate": {
"hash": "…",
"questionnaire": { "key": "glp-weightloss", "version": "3", "effectiveDate": "2026-05-01" },
"submittedAt": "2026-07-06T14:20:00Z"
}
}
The certificate is PHI-free by construction — a hash and version pins, no names or answers — so it travels safely through your logs and over events.
Provider approval gates the order#
The verdict says the answers cleared the rules. It does not authorize a prescription. Only a licensed provider — a reviewer with prescribing licensure (an NPI) — can review an eligible submission and approve or reject it. That review is a licensure act, gated exactly like order approval: an eligible intake sits in pending_review until a provider decides.
Approval is what unlocks the order:
- Patient submits an intake → verdict
eligible→ certificate issued → statuspending_review. - A licensed provider reviews the submission and approves it.
- The order the intake is bound to becomes eligible for submission.
Skip or fail any step and the rail refuses. An unapproved order returns order_not_approved on submit — the API will not ship an order that no provider has stood behind. See how that constraint lands on the order lifecycle in Orders.
Each stage emits a PHI-free event (intake.certificate.issued, intake.review.approved, intake.review.rejected) carrying ids, verdicts, and the certificate hash — never answers or patient identity. That's why your webhook endpoint stays outside PHI scope; the details on that split live in The PHI boundary.
Next steps#
- Intake API — publish versions, submit answers, review submissions.
- Orders — how approval gates the order lifecycle.
- The PHI boundary — why certificates and events carry no patient data.