The Qualiphy API lets clinics, medspas, and software teams launch licensed provider consultations, treatments, and pharmacy fulfillment under their own brand. Programmatic access to the same network that powers Qualiphy's products. Comprehensive reference below.
Answer 5 quick questions, get a custom integration plan with the exact endpoints, sample call, and checklist your dev team needs.
Prefer no code?
Run your site on WordPress?
Quidget is our drop-in WordPress plugin that wraps the Qualiphy API in a polished WooCommerce experience. Ship telehealth on your store without writing a line of code.
The fastest path from zero to a successfully approved exam.
i
Not technical? Run the Quick start instead. It generates a custom plan you can hand to your dev team, with the exact endpoints and sample payload tailored to your use case.
1. Get an API key
Sign in to the Qualiphy portal and find your API key under Settings → API. If you don't have a portal account yet, sign up free - it takes a minute.
2. Find an exam ID
Each treatment your clinic offers has a numeric exam ID. You can either browse them in the portal under Exam List, or fetch them programmatically:
import requests, os
r = requests.post(
'https://api.qualiphy.me/api/exam_list',
json={'api_key': os.environ['QUALIPHY_KEY']}
)
exams = r.json()
3. Send an exam invite
Build a payload with the patient's details, the exam ID from step 2, and a webhook URL where you want to receive the result. The sample below uses Test mode (state: "TE", name Test Approve) so it's safe to run as-is — swap in real values when you're ready to ship.
A licensed provider reviews the patient and approves in 2-24 hours (for test exams; real exams are processed within seconds). When approved, your webhook_url receives a POST with the result payload. See webhook reference for the schema.
✓
That's it. Once your webhook handler logs an approval, you've completed the full standard GFE integration loop. Scroll down for all RX and whitelabeling settings.
Authentication
Every Qualiphy API request includes your api_key in the JSON request body. There are no headers, OAuth tokens, or refresh flows to manage.
!
Never expose your API key in client-side code. All API calls should be made from your server. Treat your key like a database password: store it in a secrets manager or environment variable.
Qualiphy provides a dedicated Test state so you can validate exam submissions, webhooks, prescription workflows, and order set configurations without touching live patients or production providers.
✓
No real consultations run in test mode. No providers are paged, no patients are contacted, no prescriptions are filled (unless you want them to — in which case you'll have to pay for the medication). All /exam_invite samples in this documentation default to test-mode values so you can copy, paste, and run them safely.
1. Route to the test state
On any /exam_invite request, set both state and tele_state to TE. This routes the request to the test environment and prevents any live workflow from running.
Test routing
{
"state": "TE",
"tele_state": "TE"
}
2. Use a test patient name that names your expected outcome
Test providers read the patient's name to decide how to process the exam — the name is your test instruction. Variations are fine as long as the intent is unambiguous (e.g. Test GFE Approve).
Test Approve
Provider approves the exam (use for GFE / non-Rx flows).
Test Reject
Provider rejects the exam.
Test N/A
Provider marks the exam not applicable.
Test Prescription Approve
Provider approves an Rx exam (use for partner pharmacy or urgent care flows).
Test Prescription Reject
Provider rejects an Rx exam.
3. Validate end-to-end
Submit the test invite and capture patient_exam_id from the response.
Watch your webhook endpoint for the lifecycle events.
Confirm the outcome matches the name you used.
!
Test exams process asynchronously. Expect 2–24 hours for a webhook (excluding weekends). If you need faster processing, contact your Qualiphy representative and they'll be able to push your exam through sooner. Don't block deployments waiting on the response — verify wiring with the immediate /exam_invite 200 response, then poll the webhook log.
i
Don't include real patient data in test requests. Use the example email, phone_number, and dob values from our samples, or any clearly-fictional values. When you're ready to ship, switch state and tele_state to the patient's real state and use real patient details — see Going to Production.
API Reference
Quick reference for every endpoint. The most-used parameters are documented here inline. For the complete parameter schema (every optional field, every edge case), each endpoint links to its canonical reference page.
All /exam_invite samples below use Test mode by default (state: "TE", name Test Approve) so the right-rail Try now is safe to run as-is. Swap in real values when you go live.
POST/api/exam_list
Returns every exam configured on your clinic. Use this to discover the id values you'll pass to /exam_invite. Each exam record tells you whether it's a GFE or an Rx (rx_type), what attachments the patient must upload (attachments), and any preset price.
Parameters
api_key
stringRequired
Your account API key.
Response fields
clinic_id
integer
The Qualiphy clinic ID associated with the API key.
exams
array
Every exam configured on this clinic. See fields below for each item.
exams[].id
integer
Exam ID. Pass this to /exam_invite in the exams array.
exams[].title
string
Human-readable exam name as configured in the Qualiphy portal.
exams[].rx_type
integer
1 = non-Rx (GFE). 2 = Rx, including QualiphyRx Packages, Urgent Care, and Choose-Your-Own-Pharmacy flows. There is no separate "Urgent" type — urgent-care exams are rx_type: 2 and are distinguished only by their title.
exams[].price
string | null
Preset price as a decimal string (e.g. "27.99") when one is configured for the exam. null for exams that don't carry a fixed Qualiphy-side price.
exams[].attachments_required
integer
Number of files the patient must upload before the consultation. Always at least 1.
exams[].attachments
string[]
Names of the additional attachments required beyond the default ID upload — e.g. ["Lab"], ["ID", "Lab"], or ["Picture of hair loss area"]. Empty array means only the standard ID is required.
The core endpoint. Creates a patient exam invite, returns a meeting URL, and (by default) emails and texts the patient. Most integrations only call this one endpoint.
Four possible scenarios
Qualiphy supports four distinct scenarios through the /exam_invite endpoint, each achieved by passing a specific combination of parameters. While the endpoint remains the same, the parameter sets determine the behavior, as detailed below:
Good Faith Exam & Orders
GFEs for in-clinic procedures or medication clearance only, offered at a flat fee of $27.99 (does not include a prescription). Requires exam selection and patient identity. No pharmacy fields are needed since no prescription is issued.
QualiphyRx Packages
Prescriptions fulfilled through Qualiphy's network of partner pharmacies. This is an all-inclusive option covering the initial consultation, prescription, medication, and shipping (prices vary depending on the medication chosen). After sending the exam invite and completing the consultation, Qualiphy handles prescription routing and provides tracking updates via webhook events. Pickup is not available — shipping only.
Urgent Care Visit
Prescriptions sent to a retail pharmacy for urgent medications, available for pickup or delivery. Priced at $49.99, this includes both the consultation and prescription. Once the prescription is sent, the pharmacy manages fulfillment and notifications — no tracking updates are provided via webhook from Qualiphy.
Choose Your Own Pharmacy
Prescriptions sent to a retail pharmacy selected by you or the patient. Functions similarly to the Urgent Care Visit flow, but supports a broader range of non-emergency medications.
Required parameters
api_key
stringRequired
Your account API key.
exams
arrayRequired
Array of exam IDs from /exam_list. Stack non-Rx exams freely; only one Rx exam may run per meeting.
first_namelast_name
stringRequired
Patient name as it should appear on the consultation record.
email
stringRequired
Patient email. Used for invite delivery and as the patient identifier.
dob
stringRequired
Date of birth as YYYY-MM-DD. Example: 1990-06-30.
phone_number
stringRequired
Patient phone. Two formats accepted: +15552223232 or 1234567890.
tele_state
stringRequired
Two-letter state abbreviation of the patient (not your clinic). Determines provider matching.
Common optional parameters
webhook_url
stringOptional
Where to POST the result. Highly recommended - without it, you have no way to know when the exam completes.
additional_data
stringOptional
Stringified JSON. Returned unchanged in the webhook payload. Use it to round-trip your internal IDs (order ID, subscription ID, etc.).
Preselect a specific drug + dosage package. Get the ID from /partner_pharmacy_treatment_packages. Legacy: exam_pos_id is still accepted as a fallback for older integrations.
The /exam_invite endpoint returns several distinct 401 messages. Most map to a specific portal action you (or your clinic admin) need to take in app.qualiphy.me - not a code change.
Unauthorized access.
API key is missing or invalid.
Need to add Patient Care Provider via Qualiphy Portal!
Your account doesn't have a provider configured for the patient's state. Add one in Portal → Operators → Add Provider.
You need to signed docusign and signed rx
Onboarding agreements aren't complete. Sign all DocuSign documents and the Rx agreement in the portal before retrying.
Need to sign Prescriptive Services Contract via Qualiphy Portal!
Required before any Rx exam (GFE works without this). Sign in Portal → Settings → Agreements.
POSTyour webhook_url
Inbound webhook fired by Qualiphy at three lifecycle moments. Your handler dispatches on the event field. Respond 200 immediately and process asynchronously to avoid retries.
!
This is the most common integration mistake. Treating the webhook as a single payload type means missing treatment details and tracking updates. Always switch on event.
Event 1 - Consultation Complete
Fires for every exam (GFE, Rx, Urgent Care) when the provider finishes the consultation. This is the basic exam outcome.
{
"event": 1,
"reason": "Patient does not meet eligibility criteria for this treatment.",
"exam_id": "exam-001",
"exam_url": "https://d29tu1ox8kfrdk.cloudfront.net/pdfs/...",
"exam_name": "General Health Check",
"exam_status": "Rejected",
"rx_status": null,
"clinic_name": "Downtown Medical Center",
"patient_email": "[email protected]",
"patient_phone_number": "5551234567",
"patient_exam_id": "patient-exam-789",
"provider_name": "NP Liza",
"additional_data": "{\"order_id\":\"WC-12847\"}",
"questions_answers": [
{ "no": 1, "question": "How are you feeling?", "answer": "Tired and run down." }
]
}
{
"event": 1,
"reason": "Flagged for medical director review pending additional records.",
"exam_id": "exam-001",
"exam_url": "https://d29tu1ox8kfrdk.cloudfront.net/pdfs/...",
"exam_name": "General Health Check",
"exam_status": "Deferred to Medical Director",
"rx_status": null,
"clinic_name": "Downtown Medical Center",
"patient_email": "[email protected]",
"patient_phone_number": "5551234567",
"patient_exam_id": "patient-exam-789",
"provider_name": "NP Liza",
"additional_data": "{\"order_id\":\"WC-12847\"}",
"questions_answers": [
{ "no": 1, "question": "How are you feeling?", "answer": "Borderline blood pressure, on multiple medications." }
]
}
{
"event": 1,
"reason": "Patient self-disqualified during pre-screening questionnaire.",
"exam_id": "exam-001",
"exam_url": null,
"exam_name": "General Health Check",
"exam_status": "NA",
"rx_status": null,
"clinic_name": "Downtown Medical Center",
"patient_email": "[email protected]",
"patient_phone_number": "5551234567",
"patient_exam_id": "patient-exam-789",
"provider_name": null,
"additional_data": "{\"order_id\":\"WC-12847\"}",
"questions_answers": [
{ "no": 1, "question": "Are you currently pregnant or breastfeeding?", "answer": "Yes." }
]
}
{
"event": 1,
"reason": "Patient did not join the scheduled consultation window.",
"exam_id": "exam-001",
"exam_url": null,
"exam_name": "General Health Check",
"exam_status": "Missed",
"rx_status": null,
"clinic_name": "Downtown Medical Center",
"patient_email": "[email protected]",
"patient_phone_number": "5551234567",
"patient_exam_id": "patient-exam-789",
"provider_name": null,
"additional_data": "{\"order_id\":\"WC-12847\"}",
"questions_answers": []
}
Status values:Approved, Rejected, Deferred to Medical Director, NA, Missed. The exam_url is a CloudFront-hosted PDF of the consultation record. URLs include a signed-expiration query param - mirror the file to your own storage if you need long-term access.
Event 2 - Prescription Confirmed
Fires only for Rx exams, after Event 1, when the treatment order has been written and confirmed at the pharmacy. Carries the full schema below.
prescription is an array; an exam may include multiple treatment items. schedule_code reflects DEA controlled-substance schedule when applicable. Storage of these fields is regulated - design your DB schema with that in mind.
Event 3 - Prescription Tracking
Fires when the pharmacy ships the treatment. Use this to surface tracking info to the patient or your operations team.
Attach a document to a patient exam: ID photos, lab results, prior records. The provider sees attachments during the screening.
POST/api/exam_questions
Returns the screening question schema for a given exam ID. Use to build pre-fill UI on your own intake form, or to map your existing intake fields onto the Qualiphy question set.
Parameters
api_key
stringRequired
Your account API key.
exam_id
integerRequired
The exam to fetch questions for. Get the ID from /exam_list.
Submits answers on behalf of the patient. Pair with /exam_questions to pre-fill the screening from your own intake data, so patients aren't answering the same questions twice.
Parameters
api_key
stringRequired
Your account API key.
patient_exam_id
integerRequired
From the patient_exams[] array in the original /exam_invite response.
answers
arrayRequired
Array of { no, question, answer } objects. Numbering should match what /exam_questions returns for the same exam.
Sample request
POST/api/exam_submit_answers
{
"api_key": "YOUR_API_KEY",
"patient_exam_id": 149784,
"answers": [
{ "no": 1, "question": "Are you currently taking any medications?", "answer": "No." },
{ "no": 2, "question": "Have you had any reactions to anesthesia?", "answer": "No." },
{ "no": 3, "question": "Are you pregnant or breastfeeding?", "answer": "No." }
]
}
POST/api/exam_invite_resend
Re-sends the invite email and SMS to the patient. Use when a patient says they didn't receive their original invite.
Parameters
api_key
stringRequired
Your account API key.
patient_exam_id
integerRequired
From the patient_exams[] array in the original /exam_invite response.
Cancel a previously created patient exam invite. Useful when a patient cancels their order or you need to clean up a duplicate invite. Cancellation is only valid before the provider has acted on the exam.
Parameters
patient_exam_id
integerRequired
From the patient_exams[] array in the original /exam_invite response. Not the exam_id.
An exam can't be cancelled once a provider has acted on it. The 400 response tells you why:
Exam status is already approved.
Provider already approved. Trigger your refund/cleanup flow instead of trying to cancel.
Exam status is already rejected.
Provider already rejected. The exam is closed; no action needed.
Exam status is already Deferred to Medical Director.
Under medical director review. Contact support if you need to intervene.
!
Idempotency: calling /exam_invite_cancel twice on a successfully-cancelled exam returns 400 with the relevant status. Treat that as success in your retry logic.
POST/api/partner_pharmacy_list
Lists Qualiphy's partner compounding pharmacies available for your account. Returns each pharmacy's pharmacy_id, which you'll pass into /exam_invite for Rx programs.
Lists treatment packages (drug + dosage combinations + pricing) available at a specific partner pharmacy. Returns order_set_id values for use with /exam_invite. Legacy exam_pos_id is still returned alongside for older integrations.
Look up any U.S. pharmacy by name, location, or NCPDPID. Returns full address and identifier fields you'll need for /exam_invite when using custom pharmacy routing.
Parameters
api_key
stringRequired
Your account API key.
search
stringOptional
Pharmacy name fragment (e.g. "CVS").
zip_code
stringOptional
Five-digit ZIP for proximity filtering.
ncpdpid
stringOptional
Direct NCPDPID lookup. Pass alone to fetch a known pharmacy by ID.
The most common Qualiphy API integration. A patient buys a Botox or filler treatment on your store; you need a licensed provider to clear them before they show up at the clinic.
Run a GFE for Botox or fillers
~15 min implementation · 2 endpoints + 1 webhook
1
Once at setup: call /exam_list to grab your aesthetic exam ID. Store the IDs you'll use - they're stable.
2
In your e-commerce platform (WooCommerce, Shopify, custom checkout, etc.), the patient checks out for an aesthetic treatment. Your order-completion handler fires.
3
Call /exam_invite with the patient's details and your aesthetic exam ID.
4
Qualiphy emails and texts the patient a meeting link only if you want Qualiphy to contact your patient. Otherwise the meeting_url in the response is yours to deliver - see Patient Notification Settings to disable.
5
Your webhook receives an approve result. Update the order status and notify the patient that they're cleared to come in.
Tip: Use additional_data to pass your internal order ID. It comes back unchanged in the webhook payload, making it trivial to match results to orders without a separate database lookup.
Recipe: Partner Pharmacy Medication Shipping
Order medication from our partner pharmacies with negotiated rates. We handle routing the prescription and notifying you with shipping updates along the way. Works for GLP-1, peptides, hormone replacement, and other Rx programs running through Qualiphy partner pharmacies.
Order medication with Qualiphy
~30 min implementation · up to 4 endpoints + 1 webhook
1
Once at setup: call /exam_list to grab the medication exam ID(s) you'll be sending patients through.
2
Once at setup: call /partner_pharmacy_list to discover available pharmacies. Store the pharmacy_id values you want to use. Skip this step if you don't have a preferred pharmacy and want the prescriber to choose the cheapest option every time.
3
Once at setup: call /partner_pharmacy_treatment_packages with each pharmacy ID to get the available dosages. Store the order_set_id values. Skip this step if you don't care which dosage is prescribed and trust the physician to make the right decision per patient.
4
Per patient: call /exam_invite with the medication exam ID, the patient details, and the optional pharmacy_id + order_set_id if you preselected them.
5
Qualiphy emails and texts the patient a meeting link only if you want Qualiphy to contact your patient. Otherwise the meeting_url in the response is yours to deliver - see Patient Notification Settings to disable.
6
Webhook event 1 fires when the consultation completes. Webhook event 2 fires once the prescription is confirmed at the partner pharmacy, and event 3 fires when the package ships - tracking number included.
!
Repeat orders: store the pharmacy_id and order_set_id on the patient/subscription record. For the next order just rebuild the same /exam_invite payload with current patient data - no need to re-discover pharmacy or dosage IDs.
Use this flow when the prescription should ship to (or be picked up from) a pharmacy outside Qualiphy's partner network - the patient's local CVS, Walgreens, or any other retail pharmacy. Common for same-day UTI treatments, but also for any program where a patient prefers their own pharmacy over the partner-pharmacy default.
Send a prescription to a custom pharmacy
~20 min implementation · 3 endpoints + 1 webhook
1
Once at setup: call /exam_list to grab the exam ID(s) you'll be sending patients through.
2
On checkout, ask the patient which pharmacy they want to use. Call /custom_pharmacy_search to look up nearby pharmacies by name or ZIP.
3
Submit /exam_invite with the exam ID, the patient details, and the patient's chosen pharmacy.
4
Qualiphy emails and texts the patient a meeting link only if you want Qualiphy to contact your patient. Otherwise the meeting_url in the response is yours to deliver - see Patient Notification Settings to disable.
5
Patient joins the screening, talks to the provider. If approved, the prescription is sent to the chosen pharmacy.
6
Webhook event 1 fires once the consultation is approved. Webhook event 2 fires after the provider sends the prescription to the pharmacy. (No event 3 for custom pharmacies - see warning below.)
!
Qualiphy is not the contact for tracking or availability with custom pharmacies. The pharmacy itself is the source of truth for fill status, ready-for-pickup, and shipping. Direct your patient (or your support team) to the pharmacy for those updates - we don't relay them.
You already collect health screening info on your own intake form, and you don't want patients to re-answer the same questions during the Qualiphy screening. Or you want full control over the wording of every question and you'll display the form on your end - not Qualiphy's.
Submit answers programmatically
~30 min implementation · 3 endpoints + 1 webhook
1
Call /exam_questions to get the question schema for the exam. Map each question to the matching field on your intake form.
2
Call /exam_invite as usual. Capture the returned patient_exam_id.
3
Immediately call /exam_submit_answers with the patient's pre-collected answers. Every question you submit appears pre-filled on the Qualiphy side. If you submit answers for every question, the questionnaire is skipped entirely and the patient goes straight to the provider call. Submit a subset and the patient only sees the unanswered questions, with their existing answers shown alongside.
POST/api/exam_submit_answers
{
"api_key": "YOUR_API_KEY",
"patient_exam_id": 149784,
"answers": [
{ "no": 1, "question": "Are you currently taking any medications?", "answer": "No." },
{ "no": 2, "question": "Have you had any reactions to anesthesia?", "answer": "No." },
{ "no": 3, "question": "Are you pregnant or breastfeeding?", "answer": "No." }
]
}
Patient Notification Settings
Qualiphy sends two distinct kinds of patient-facing messages. Each can be disabled independently if you want full control - or you want your providers to stay out of direct patient contact. Disable one, both, or neither.
1. Auto-generated invites
When you call /exam_invite, Qualiphy automatically emails and texts the patient the meeting link. Disable these if you want to deliver the link from your own branded system using the meeting_url returned in the response.
How to disable: contact your Qualiphy rep. This is an account-level switch, not a per-request flag.
!
GLP-1 follow-up certification. If you disable auto-generated invites and you prescribe GLP-1 medications, you must agree to send the legally-required follow-up exam invitation yourself (typically ~3 weeks after the original visit, to check for adverse effects). Qualiphy normally sends this automatically; if you turn it off, the responsibility shifts to you.
2. Provider direct contact
Qualiphy providers may personally email or call the patient in specific situations - for example, when a video call drops mid-session and the provider needs to call them back, or to nudge a patient whose exam has been pending too long. These messages come from the provider's number/email, not Qualiphy's automated system.
How to disable: in the Qualiphy portal, go to Settings → Notification Settings. From there you can toggle each notification type per clinic, manage which notification contacts get copied, and choose whether providers contact patients directly for pending consultations.
Settings → Notification Settings in the Qualiphy portal. Toggle each notification type per clinic and add or remove notification contacts.
Sending invites from your own system
Once auto-generated invites are off, the integration shape is straightforward:
Deliver the meeting link yourself
~15 min implementation · 1 endpoint + 1 webhook + a one-time config change
1
Contact your Qualiphy rep to disable auto-generated invites for your account.
2
Call /exam_invite as usual. Capture the returned meeting_url.
3
Send your own email or SMS to the patient with the meeting_url embedded in your branded template.
How an Exam Works
Every Qualiphy interaction follows the same lifecycle, regardless of treatment type. Understanding this flow makes everything else easier to reason about.
1
You call /exam_invite with patient details and one or more exam IDs. Qualiphy returns a meeting_url immediately.
2
The patient receives an invite via email and SMS (or via your own system if you've configured custom delivery). They click the link and enter the screening.
3
The patient completes the screening. They answer health questions, then connect with a licensed provider for a brief video consultation.
4
The provider makes a decision: approve, reject, or defer. For Rx exams, an approval includes a treatment order that routes to your selected pharmacy.
5
Your webhook_url receives the result as a POST. Your handler updates the patient record, triggers fulfillment, sends a notification, or whatever your business logic requires.
Steps 1 and 5 are where your code lives. Steps 2-4 happen on Qualiphy's side without further integration work.
Exam Types
The same /exam_invite endpoint handles all three exam types. The exam ID determines the type; a single payload can trigger one of any kind.
Good Faith Exam (GFE)
Provider clears a patient for an in-clinic procedure. Most common for Botox, fillers, IV therapy, and other aesthetic services. No medication is dispensed.
Rx Treatment
Provider evaluates the patient and, if appropriate, issues a treatment order. Common for GLP-1 weight loss programs, hormone therapy, and other ongoing treatments. Medication routes to a partner or custom pharmacy.
Urgent Care
On-demand consultations for acute conditions: UTI, pink eye, cold sores, acne, nausea. Treatments are sent to a retail pharmacy of the patient's choice.
How to know which type an exam is
Call /exam_list; each exam record returns its type. Or check the exam in the Qualiphy portal under Exam List.
!
Multi-exam constraint: only one Rx exam may run per meeting. You can stack any number of GFE exams on a single invite, but Rx exams must be sent individually.
States & Telehealth
Telehealth in the U.S. is regulated state-by-state. Qualiphy uses the tele_state field on every /exam_invite call to match patients with providers licensed in their location.
Always pass the patient's state
Not your clinic's state. The patient's state determines which providers can serve them and which pharmacies can fulfill treatments. A clinic in Texas with a patient in California sends "tele_state": "CA".
!
Sending the wrong state is the single most common integration bug. If exams are getting "no provider available" responses, this is almost always why.
Format
Two-letter uppercase state abbreviation: NY, CA, TX, etc. Use DC for Washington D.C.
Coverage
Qualiphy serves 48 states + D.C. Alabama and Mississippi are not currently supported.
Pharmacy Routing
For Rx exams, you choose how treatments get from the provider to the patient. There are three patterns. Pick whichever fits your business model.
Partner pharmacy (recommended for Rx programs)
Use Qualiphy's pre-vetted compounding pharmacy network. Bundled, all-inclusive pricing. Qualiphy handles fulfillment and ships directly to the patient. Best for GLP-1, peptide, and other recurring Rx programs.
Workflow: call /partner_pharmacy_list to see available pharmacies and their pharmacy_id, then optionally call /partner_pharmacy_treatment_packages to get an order_set_id for a specific dosage. Pass both into your /exam_invite payload.
Custom pharmacy
Send the treatment order to a specific retail or compounding pharmacy. Required for Urgent Care exams (the patient picks a pharmacy near them). Best when the patient already has a preferred pharmacy.
Workflow: call /custom_pharmacy_search to find a pharmacy by name or ZIP, then pass the resulting ncpdpid and address fields into your /exam_invite payload.
Provider's choice
Let the licensed provider pick the right pharmacy and order set during the consultation, based on the patient's needs. Use the provider_pos_selection field on /exam_invite:
1
Provider does not choose. You've fully specified the pharmacy and order.
2
Provider picks the order set only (drug + dosage). You specified the pharmacy.
3
Provider picks both the pharmacy and the order set. Most flexible.
Field Glossary
The Qualiphy API has a few field names whose meaning isn't obvious from the name. Bookmark this section - you'll come back to it.
tele_state vs state
tele_state is the patient's telehealth jurisdiction, used to match providers and pharmacies. It must be the patient's state, even if the clinic is elsewhere. state is just the patient's home address state. They're often the same value, but conceptually different fields.
address_* vs shipping_address_* vs pharmacy_*
Three different addresses. address_* is the patient's home address. shipping_address_* is where Rx ships to (often a clinic or P.O. box, not the patient's home). pharmacy_* is the custom retail pharmacy when custom_pharmacy: 1.
custom_pharmacy
Inverted from intuition. 1=Custom Pharmacy (retail like CVS, Walgreens). 2=Partner Pharmacy (Qualiphy's compounding network).
attachments_required
Also inverted. 1=not required. 2=required. Watch for off-by-one bugs.
rx_type
On exams from /exam_list. 1=non-Rx (GFE), 2=Rx. You can stack non-Rx exams in one meeting; only one Rx exam per meeting.
gender
Integer, not string. 1=Male, 2=Female, 3=Prefer not to say.
exam_id vs patient_exam_id
exam_id is the static catalog ID for a treatment (e.g. "GLP-1 Weight Loss"). patient_exam_id is unique to one patient's instance of that exam. Always use patient_exam_id when cancelling, looking up answers, or correlating webhooks.
"POS" = Pharmacy / Order Set. 1=you specify both. 2=provider picks order set. 3=provider picks both.
Webhook Best Practices
Webhooks are the most operationally sensitive part of any integration. A failed webhook handler means a missed approval, which means a frustrated patient. Build defensively.
Respond fast, process slow
Your handler should validate the payload, queue the work, and return 200 in under 100 ms. Do the actual processing in a background worker. Long-running webhook handlers cause Qualiphy to assume delivery failed and retry, which leads to duplicate processing.
Idempotency
Treat patient_exam_id as a unique key. If your handler is invoked twice with the same ID, the second invocation should be a no-op. Store a record of processed IDs and check on every call.
Logging
Log every payload before processing, including failed deliveries. When something goes wrong months later, the raw payload is the only forensic record you'll have.
Verifying the source
Webhook source verification is on the roadmap. For now, consider IP-allowlisting Qualiphy's webhook origin if your platform supports it, and ensure your webhook endpoint is over HTTPS.
Errors & Status Codes
200
Success. Body contains the response payload.
400
Bad request. Usually a missing required field, malformed date/phone, or an invalid tele_state. The response body specifies which field.
401
Authentication failed. Your api_key is missing or invalid.
500
Server error. Retry after a brief backoff. If it persists, contact support.
Going to Production
A pre-launch checklist. Run through this before flipping your integration on for real patients.
☐Full integration validated end-to-end via Test mode (state & tele_state set to TE, expected outcomes confirmed via webhook)
☐state and tele_state now driven by the patient's real address (no hardcoded TE left in code paths)
☐Patient name fields use real patient data (no Test Approve / Test Reject fixtures left over)
☐Webhook handler tested against approve and reject paths
☐Production API key stored in your secrets manager (not in source control)
☐Idempotency check on patient_exam_id in webhook handler
☐Error monitoring on the /exam_invite call (4xx and 5xx)
☐Subscribed to API change notifications
☐For Rx programs: pharmacy routing values stored on the patient/subscription record, not hardcoded
✓
Ready to ship? Once your test exam clears the full pipeline, swap state/tele_state from TE to the patient's real state, replace test names with real patient data, and you're live. Roll out gradually — feature-flag the integration on for a small percentage of patients first.
Want a tailored plan for your team?
The quick start asks a handful of questions about your business, then generates a custom integration plan you can email straight to your dev team.