Skip to main content

Questionnaire Embed Integration Guide

Version: 0.2 (Stable) Date: May 13, 2026 Package: @wearestealthhealth/questionnaire-embed CDN (production): https://embed.stealth.health | CDN (beta): https://embed-beta.stealth.health API base (production): https://app.stealth.health | API base (beta): https://beta.stealth.health Status: Generally available

What this is. A drop-in iframe component that renders any Stealth Health questionnaire on your marketing site, partner portal, or in-app intake. Submissions are written directly to Stealth Health — your code never sees PHI. After submit, the patient is auto-redirected to the matching /enroll/<slug> page (or shown a thank-you screen) and your referral.* webhooks start flowing exactly as documented in the Referral Tier guide.

Who this is for. Any partner who wants the patient intake experience to live on their own domain rather than redirecting to app.stealth.health. Works alongside any integration tier — referral, clinical, or prescriber-partner — because the embed is a delivery mechanism, not a separate API surface.

1. Overview

The questionnaire embed renders a Stealth Health intake form inside an iframe sourced from app.stealth.health (or beta.stealth.health) and embedded on a host page you control. Two integration paths are supported:

  • Vanilla JS — paste a <script> tag and a one-liner. No build tooling, no npm token, no React knowledge required. Best for Webflow, WordPress, Framer, or hand-written landing pages.
  • React / Next.js (npm) — install @wearestealthhealth/questionnaire-embed from GitHub Packages and render <QuestionnaireEmbed /> like any other component. Best for partners with a modern stack who want type definitions and tree-shaking.

Both paths render the same iframe with identical behaviour — the npm package is a thin React wrapper around the iframe URL plus the postMessage listener.

After the patient submits, the embed:

  1. Writes the response inside the iframe (so prescribers see it in real time in the doctor portal).
  2. Posts a questionnaire:submitted message to the parent window with the new responseId.
  3. Redirects the iframe to the configured post-submit destination — usually the matching /enroll/<slug> catalog page on app.stealth.health or a thank-you screen.
  4. Triggers the referral.enrolled webhook to your registered endpoint (see Referral Tier § 7.3).

2. Architecture & PHI Boundaries

PHI handling. Every byte of patient data — answers, demographics, clinical history — flows from the patient's browser directly into the iframe and from the iframe to Stealth Health. Your parent page only ever sees:

  • responseId — a 20-character opaque document ID (no PHI).
  • error.message — strings from our API like "reCAPTCHA verification failed" (no PHI).

This is the same PHI boundary as the Referral Tier: your stack is a referral source, not a HIPAA business associate handling PHI. Do not capture or persist anything from the iframe via DOM scraping or browser extensions — that would re-expose PHI to your stack and would require a full BAA.


3. Environments

You will integrate against beta first, validate end-to-end, then flip to production.

Channelnpm dist-tagAPI base URL (baseUrl option)CDN base URL (<script src>)
Betabetahttps://beta.stealth.healthhttps://embed-beta.stealth.health
Productionlatesthttps://app.stealth.healthhttps://embed.stealth.health

Each environment is a fully isolated deployment with its own database and white-label configuration. Never send production traffic to beta URLs — the data lands in a separate environment and never reaches production prescribers.

Cutover. When you flip to production, change exactly two strings:

- <script src="https://embed-beta.stealth.health/questionnaire-embed/latest/umd.js"></script>
+ <script src="https://embed.stealth.health/questionnaire-embed/latest/umd.js"></script>
- baseUrl: "https://beta.stealth.health",
+ baseUrl: "https://app.stealth.health",

4. Option A — Vanilla JS (drop-in script)

Minimum viable integration — paste this anywhere on your page.

<!-- Anywhere in your page body -->
<div id="sh-questionnaire"></div>

<!-- 1. React runtime (any modern version; cached aggressively by unpkg) -->
<script crossorigin src="https://unpkg.com/react@19/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@19/umd/react-dom.production.min.js"></script>

<!-- 2. Stealth Health embed loader (UMD). Use the BETA CDN during integration. -->
<script src="https://embed-beta.stealth.health/questionnaire-embed/latest/umd.js"></script>

<script>
StealthHealthQuestionnaire.render('#sh-questionnaire', {
// From the catalog in §10 below.
questionnaireId: 'global-weight-loss-consultation',

// Beta during integration; flip to https://app.stealth.health for prod.
baseUrl: 'https://beta.stealth.health',

height: 720,

// Forwarded to our API. Use this for attribution + white-label routing.
queryParams: {
// Your registered white-label hostname (so emails/SMS use YOUR brand).
wl: 'partner.com',
utm_source: 'partner',
utm_medium: 'embed',
},

onSubmit: function (data) {
// data.responseId is a 20-char opaque doc ID. Stealth Health
// already has the submission — this callback is for your CRM /
// analytics only.
console.log('Stealth Health responseId:', data.responseId);
},
onError: function (err) {
console.error('Stealth Health embed error:', err);
},
});
</script>

That's it. The global StealthHealthQuestionnaire.render(selector, config) is the only public API exposed by the UMD bundle.


5. Option B — React / Next.js (npm)

Best for partners with a React stack — gives you TypeScript definitions, tree-shaking, and a component you can compose normally.

5.1 Configure npm to read from GitHub Packages

The package is published to GitHub Packages under the @wearestealthhealth scope. Create (or merge into) an .npmrc at your project root:

# .npmrc
@wearestealthhealth:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Export the personal access token (PAT) we issued you with read:packages scope:

export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

In CI, set GITHUB_TOKEN (or NPM_AUTH_TOKEN) as a secret and reference it the same way. Do not commit the token.

5.2 Install

# During integration
npm install @wearestealthhealth/questionnaire-embed@beta

# Once you ship to production users
npm install @wearestealthhealth/questionnaire-embed@latest

5.3 Render

import { QuestionnaireEmbed } from "@wearestealthhealth/questionnaire-embed";

export default function ConsultationPage() {
return (
<QuestionnaireEmbed
questionnaireId="global-weight-loss-consultation"
baseUrl="https://beta.stealth.health"
height={720}
queryParams={{
wl: "partner.com",
utm_source: "partner",
utm_medium: "embed",
}}
onSubmit={({ responseId }) => {
// Forward to your own analytics / CRM. Stealth Health already has it.
console.log("submitted:", responseId);
}}
onError={(error) => {
console.error("questionnaire error:", error);
}}
/>
);
}

The component is iframe-only — it does not depend on any global state, theme provider, or context. Render as many instances as you want on the same page (each gets its own iframe and responseId).

5.4 Server-side rendering

The component reads window.addEventListener('message', ...) in a useEffect, so it is SSR-safe (Next.js App Router and Pages Router both supported). The iframe src is computed during render and is deterministic for a given prop set, so hydration does not flicker.


6. Configuration Reference

6.1 Props / options

The Vanilla JS StealthHealthQuestionnaire.render(selector, config) and the React <QuestionnaireEmbed {...props} /> accept the same shape.

FieldTypeRequiredDefaultNotes
questionnaireIdstringyesOne of the IDs from the catalog in § 10.
baseUrlstringyes (recommended)https://app.stealth.healthMust be HTTPS, or http://localhost / http://127.0.0.1 for local dev. Insecure URLs are rejected with a console error and the embed renders nothing.
heightnumber | stringno700CSS pixel value (number) or CSS length (string, e.g. "100vh").
widthnumber | stringno"100%"Same conventions as height. The embed is responsive by default.
queryParamsRecord<string, string>noForwarded to the iframe URL as ?key=value pairs. See § 6.2.
recaptchaSiteKeystringno(Stealth Health default)Override the reCAPTCHA v3 site key. Only set this if Stealth Health has provisioned a custom site key for your domain.
onSubmit(data: { responseId: string }) => voidnoCalled when the iframe posts questionnaire:submitted. Use it to fire your own analytics/CRM events; do not call your own backend with PHI from this callback (the callback only contains responseId, which is fine).
onError(error: Error) => voidnoCalled when the iframe posts questionnaire:error. The error message is a short string (e.g. "Submission failed"); the iframe surfaces full validation UX to the patient.
className / stylenoApplied to the <iframe> element. Useful for fitting the embed into your design system. The iframe ships with border: none baked in via style.

6.2 Forwarded query parameters

Anything you put in queryParams is appended to the iframe URL: https://app.stealth.health/q/<questionnaireId>?<your-params>&embed=1. Stealth Health honors the following keys explicitly; everything else is captured on the response document for your own attribution.

KeyHonored by Stealth HealthPurpose
wlyesWhite-label hostname. Drives per-request branding lookup so the post-submit emails/SMS to the patient use your brand. The value must exactly match a hostname registered in our white-label configuration (see § 8).
utm_source / utm_medium / utm_campaign / utm_content / utm_termyesPersisted on the response doc and on any downstream referral, appointment, and transaction records for your reporting joins.
partner_referenceyesIf present, used as the idempotency key on the resulting referral. Equivalent to passing partner_reference to POST /partner/referrals (see Referral Tier § 6.1). Recommended: pass your own customer ID here so your webhook handler can join on it without an extra API call.
Anything elseno (passed through)Captured verbatim on the response doc under metadata and echoed back in webhook payloads under metadata.<key>.

6.3 postMessage event protocol

The iframe communicates with the parent page via window.postMessage. The component verifies that the message origin includes the baseUrl hostname before invoking your callbacks — you do not need to filter origins yourself.

event.data.typeDirectionPayloadTriggered when
questionnaire:submittediframe → parent{ type: "questionnaire:submitted", responseId: string }Submission persisted. responseId is the new response document ID.
questionnaire:erroriframe → parent{ type: "questionnaire:error", message?: string }Submission failed (network error, reCAPTCHA failure, validation rejection from server). The patient sees an inline error UI inside the iframe; the parent callback fires so you can log it.

If you want to listen for these events without using the npm package or UMD bundle (e.g. you embed the iframe yourself), the contract is:

window.addEventListener('message', (event) => {
// Always validate the origin before trusting the payload.
if (!event.origin.endsWith('.stealth.health')) return;
if (event.data?.type === 'questionnaire:submitted') {
// event.data.responseId
}
});

6.4 Cleanup / unmount

The Vanilla JS render() returns a handle for tear-down when the parent navigates away without a full page reload (single-page apps).

const handle = StealthHealthQuestionnaire.render('#sh-questionnaire', config);

// Later, e.g. on route change:
handle.unmount();

The React component cleans up its message listener on unmount automatically — no manual call required.


7. Content Security Policy

If your page ships a strict CSP, allowlist the following directives for whichever environment you're on. Beta and production use distinct hosts so you can keep them separate in your headers.

DirectiveProductionBeta
script-srchttps://embed.stealth.health https://unpkg.comhttps://embed-beta.stealth.health https://unpkg.com
connect-srchttps://app.stealth.health https://*.googleapis.comhttps://beta.stealth.health https://*.googleapis.com
frame-srchttps://app.stealth.healthhttps://beta.stealth.health
img-srchttps://*.stealth.health data:https://*.stealth.health data:
style-src'self' 'unsafe-inline'same

Why each entry:

  • script-src allows the UMD loader and the React UMD runtime from unpkg.
  • connect-src allows the iframe to talk back to our API and to Google's reCAPTCHA verification endpoint.
  • frame-src allows the iframe itself.
  • img-src allows our brand assets and inline data: previews.
  • style-src 'unsafe-inline' is required because the embed injects a <style> tag for layout. If your CSP forbids inline styles globally, set style-src 'self' https://*.stealth.health and email partners@stealth.health — we can ship a hashed-style build on request.

8. White-label branding

Submission emails and SMS to the patient use your brand only if your public hostname is registered in our white-label configuration. This is a one-time onboarding step on our side. Email your Stealth Health contact:

  1. The public hostname(s) where the embed will appear (e.g. consult.partner.com).
  2. Your brand name, sender email, support email, logo URL (PNG/SVG, transparent background), and favicon.
  3. Whether navigation links should override our defaults.

We will register your branding against beta first, then production after you sign off. Verify by submitting a test response on beta and confirming the test inbox receives a message branded as you (not Stealth Health).

Important. Pass your registered hostname in queryParams.wl on every render. The lookup happens per-request inside the iframe — if wl is missing or doesn't match a registered host, branding silently falls back to Stealth Health.

Security note. Every registered white-label hostname is automatically considered a trusted SSO redirect target by our central identity provider at app.stealth.health/login. Treat the white-label registration step with the same scrutiny you'd give a manual addition to an OAuth redirect allowlist.


9. Version pinning & release channels

/latest/umd.js follows the current channel's tip — that's usually what you want, because patch and minor releases ship via this URL with no integration work.

If you require a byte-for-byte reproducible build (e.g. to satisfy a change-management policy or a SOC 2 control), pin to an immutable URL:

<script src="https://embed.stealth.health/questionnaire-embed/v0.2.0/umd.js"></script>

Discover the currently deployed version on a channel:

curl -s https://embed.stealth.health/questionnaire-embed/version.json
# { "name": "@wearestealthhealth/questionnaire-embed", "version": "0.2.0", "channel": "latest", "builtAt": "…" }

Cache headers:

URL patternCache-Control
/v<x.y.z>/umd.js (pinned)public, max-age=31536000, immutable
/latest/umd.js (rolling)public, max-age=300, stale-while-revalidate=86400

Channel mapping:

  • main branch → npm @latest and embed.stealth.health/.../latest/ (production).
  • staging branch → npm @beta prereleases (e.g. 0.2.1-beta.3) and embed-beta.stealth.health/.../latest/ (beta).

If a regression slips out, roll back by pinning the previous immutable version:

<script src="https://embed.stealth.health/questionnaire-embed/v0.1.4/umd.js"></script>

…or for the React package:

npm install @wearestealthhealth/questionnaire-embed@0.1.4

We follow semantic versioning. Breaking changes bump the major version and are announced in the changelog ≥ 90 days in advance.


10. Questionnaire catalog

For each questionnaireId below, the patient submits the questionnaire, sees the thank-you screen (or our redirect into the matching enroll page), and is then offered the medications listed in the right-hand column. Every medication ID below has been verified live in our production medication catalog.

Excluded: the multi-step Mold/CIRS workup (global-mold-cirs-consultation-step-{1,2,5}) is intentionally omitted — those questionnaires gate a sync visit and do not auto-route to a medication catalog.

US only. The catalogs below cover US patients. Canadian SKUs exist for some categories but are routed through different enroll pages and are not listed here.

questionnaireIdPost-submit enroll pageUS medications offered
global-erectile-dysfunction-consultation/enroll/edstrive-tadalafil-5mg-flextab — Tadalafil 5 mg flextab (daily sublingual)
strive-tadalafil-20mg-flextab — Tadalafil 20 mg flextab (on-demand, 36 h window)
global-weight-loss-consultation/enroll/weight-lossCalifornia only: strive-semaglutide-b12-glycine-0.5ml, strive-semaglutide-b12-glycine-1ml, strive-semaglutide-b12-glycine-2ml — Semaglutide / B12 / Glycine 5 mg/mL
Every other US state: wells-tirzepatide-glycine-2ml (2 mL), wells-tirzepatide-glycine-4.5ml (4.5 mL) — Tirzepatide + Glycine 16.6/7.5 mg/mL
global-male-trt-consultation/enroll/trtwells-enclomiphene-citrate-12-5mg-per-capsule — Enclomiphene Citrate 12.5 mg cap
wells-perigo-testosterone-200mg-10ml-vial — Perigo brand T 200 mg/mL (10 mL)
wells-testosterone-cypionate-bpi-labs-200mg-ml-5ml-vial — T-cypionate (BPI Labs) 200 mg/mL (5 mL)
global-progesterone-consultation/enroll/female-hrtstrive-progesterone-100mg-sr — Progesterone 100 mg SR
strive-progesterone-200mg-sr — Progesterone 200 mg SR
global-thyroid-consultation/enroll/thyroidstrive-liothyronine-t3-5mcg — Liothyronine (T3) 5 mcg
strive-armour-thyroid-15mg — Armour Thyroid 15 mg
strive-np-thyroid-15mg — NP Thyroid 15 mg
global-scream-cream-consultation (female libido)/enroll/hyposexuality-femalewells-testosterone-cypionate-in-grapes-20-mg-ml-low-d-5ml-vial — Low-dose T in grapeseed oil 20 mg/mL (5 mL)
wells-testosterone-cypionate-in-grapes-50mg-ml-1ml-vial — T in grapeseed oil 50 mg/mL (1 mL)
wells-testosterone-cypionate-in-grapes-50mg-ml-1-5ml-vial — T in grapeseed oil 50 mg/mL (1.5 mL)
global-synapsyn-nad-consultation/enroll/brain-healthwells-synapsin-0-2-mg-0-1ml-15-ml-bottle — Synapsin 0.2 mg / 0.1 mL (15 mL)
wells-synapsin-b12-m-alpha-gpc-10-mg-0-2-mg-3-15-ml-bottle — Synapsin / B12 / Alpha-GPC stack (15 mL)
global-bpc-157-peptide-consultation/enroll/growth-hormone-supportwells-sermorelin-ship-cold-3-mg-ml-2ml-vial — Sermorelin 3 mg/mL (2 mL)
wells-sermorelin-ship-cold-3-mg-ml-5ml-vial — Sermorelin 3 mg/mL (5 mL)
global-b12-niagen-glutathione-consultation/enroll/vitamin-nadstrive-nad-200mg-10ml, strive-nad-200mg-6ml — NAD+ 200 mg/mL
wells-niagen-plus-kit-500mg — Niagen+ Kit 500 mg
wells-glutathione-l-200mg-10ml, strive-glutathione-200mg-30ml — Glutathione
wells-cyanocobalamin-b12-commercial-pr-1-000-mcg-ml-10ml-vial — B12 1,000 mcg/mL
global-low-dose-naltrexone-ldn-consultation/enroll/ldnwells-naltrexone-ldn-1-5-mg-per-capsule — LDN 1.5 mg cap
wells-naltrexone-ldn-3-mg-per-capsule — LDN 3 mg cap
wells-naltrexone-ldn-4-5-mg-per-capsule — LDN 4.5 mg cap
global-hair-growth-consultation/enroll/hair-losswells-latanoprost-minoxidil-latanostim-0-06-2-2-30ml — LatanoSTIM-X 0.06 % / 2.2 % (30 mL)
wells-latanoprost-minoxidil-latanostim-0-06-10-30ml — LatanoSTIM-X 0.06 % / 10 % (30 mL)
wells-hydrocortisone-latanoprost-minox-1-0-05-6-5-0-0-30ml — HLMT — Vit E 5-in-1 (30 mL)
wells-zinc-thymulin-ghk-cu-0-001-0-5-ml-25-ml-bottle — Zinc-Thymulin / GHK-Cu (25 mL)
global-acne-consultation (Skin Care path)/enroll/skin-carewells-ghk-cu-hyaluronic-acid-minimum-b-0-055-0-5-30ml — GHK-Cu + Hyaluronic Acid (30 mL)
wells-niacinamide-tretinoin-navra-gel-mild — Navra-Gel Mild (Niacinamide 5 % / Tretinoin 0.025 %)
wells-niacinamide-tretinoin-navra-gel-moderate — Navra-Gel Moderate (0.05 %)
wells-niacinamide-tretinoin-navra-gel-max — Navra-Gel Max (0.1 %)
global-acne-consultation (Acne enroll path) ‡/enroll/acneacne-chronic-us — Stealth Health Chronic Acne §
acne-brightening-hydroquinone-us — Stealth Health Brightening §
acne-scars-scarbase-us — Stealth Health Scars (ScarBase) §
acne-multiprofen-cc-abx-us — Stealth Health Acne (Multiprofen-CC ABX) §
global-pain-management-consultation/enroll/pain-management (no-payment intake)pain-management-pain-cream-us — Stealth Health Pain Cream §
pain-management-pain-cream-plus-us — Stealth Health Pain Cream Plus §
global-pain-management-consultation (paid path)/enroll/pain-creamSame SKUs as above. §
global-metabolic-code-assessment/enroll/metabolic-code (one-time / monthly / yearly)metabolic-code-silver-us — Metabolic Code Silver
metabolic-code-gold-us — Metabolic Code Gold
metabolic-code-platinum-us — Metabolic Code Platinum
global-regen-quantum-consultation/enroll/regen-quantumregen-quantum-black — Quantum Black (Deep Reset)
regen-quantum-blue — Quantum Blue (Daily Optimization)
regen-quantum-red — Quantum Red (Baseline Support)
global-vcpr-multivisk-equine/enroll/multiviskha-multivisk-us — Multivisk (HA injection) §

Direct-enroll catalogs (no questionnaire required)

These enroll pages don't have a screening questionnaire — patients land directly on the catalog. Link to them straight from your site if you'd rather skip the embed for these categories.

Enroll pageMedications
/enroll/peptidesBPC-157 Inj. 2,000 mcg/mL · BPC-157 Capsules 500 mcg · Sermorelin Troche 500 mcg · Sermorelin Inj. 9 mg/vial · BPC-157 / TB-500 / GHK-Cu Inj. · Ipamorelin Inj. 2 mg/mL · NAD+ 200 mg/mL · GHK-Cu Cream · Thymosin-α1 (TA-1) Inj. · Bremelanotide (PT-141) Inj. · Elamipretide (SS-31) Inj. · Pentadecapeptide Arginate (PDA) Inj.
/enroll/scream-creamNow to WOW
/enroll/multiviskMultivisk

Footnotes

Weight-loss state split. The Weight Loss enroll page lists both groups, but checkout fulfilment is per-state: California ships the Strive semaglutide line, every other US state ships the Wells tirzepatide line. The split is enforced server-side by jurisdiction overrides on the weight-loss-program doc — the embed does not need to know which state the patient is in.

global-acne-consultation is shared by two enroll pages. /enroll/skin-care exposes the Navra-Gel + GHK-Cu protocols; /enroll/acne exposes the direct-pay Hydroquinone / ScarBase / Multiprofen line. Pick the destination that matches your landing page's intent — the questionnaire ID is the same.

§ Limited US state coverage. The acne-*-us, pain-management-*-us, and ha-multivisk-us SKUs currently fulfil to AZ, CO, CT, DE, FL, GA, IL, IN, MD, MO, NJ, NY, NC, OH, PA, UT, WA, WY only. Every other SKU in the table fulfils to all US states (subdivisions: ['*']). Patients outside the supported states see an "out of network" message on the enroll page rather than a checkout button.

Veterinary. global-vcpr-multivisk-equine is a veterinary client-patient relationship intake for Multivisk Equine HA. Skip this row if you do not serve veterinary customers.


11. Pre-production testing checklist

Run these against beta first; repeat against production on cutover day.

  1. The questionnaire renders inside the embed with no console errors.
  2. You can complete every required field and hit Submit.
  3. Either the page redirects to /enroll/<slug> on the iframe (beta.stealth.health or app.stealth.health) or you see the thank-you screen — depending on the questionnaire.
  4. Your onSubmit callback fires with a responseId matching ^[A-Za-z0-9]{20}$.
  5. The patient email and SMS the test address receives are branded with your brand (logo, sender, support footer), not Stealth Health's. If they're branded as Stealth Health, the wl param doesn't match a seeded host — re-check the queryParams.wl value and confirm the white-label doc is seeded for that exact hostname.
  6. Stealth Health confirms the submission landed in our doctor portal under the correct questionnaire with the right answers.
  7. (Clinical-tier and prescriber-partner tiers only) Your webhook receiver at the registered URL receives the matching event (referral.enrolled, plus appointment.intake_completed for clinical tier) and verifies the X-Stealth-Signature header. See Referral Tier § 7.4 for the verification snippet.

If any check fails on beta, fix it before touching production — the production iframe and production webhook secret are not interchangeable with their beta counterparts.


12. Troubleshooting

SymptomLikely causeFix
Iframe renders blank, console says Insecure baseUrl rejectedbaseUrl is http:// (not localhost)Use https://app.stealth.health (prod) or https://beta.stealth.health (beta).
onSubmit never fires after a successful submissionOrigin mismatch — your baseUrl doesn't match the iframe's event.originMake sure baseUrl exactly matches the host serving the iframe. Don't pass app.stealth.health while loading from beta.stealth.health.
reCAPTCHA error in the iframeCSP blocks *.googleapis.com on connect-srcAdd https://*.googleapis.com to connect-src (see § 7).
Patient receives a Stealth-Health-branded email instead of yoursqueryParams.wl is missing or doesn't match a registered hostPass wl: '<your-host>' in queryParams; confirm the host is registered in our white-label configuration (see § 8).
Webhook never arrivesYour webhook URL isn't set, or the receiver returned non-2xx for all 6 retriesCheck delivery status via GET /partner/events?delivery_status=failed. To update the URL, contact your Stealth Health account manager.
Webhook receiver gets the same event multiple timesWorking as intended — events are at-least-onceDedupe on event.event_id (treat as the idempotency key). See Referral Tier § 7.5.
npm install fails with 401 UnauthorizedGITHUB_TOKEN env var missing or PAT lacks read:packages scopeRe-issue a PAT with read:packages and re-export. Verify .npmrc is at the project root, not inside node_modules/.
/latest/umd.js is serving an old versionBrowser/CDN cacheHard-refresh, or pin to an immutable /v<x.y.z>/ URL (§ 9).

If you're still stuck, drop the network HAR for the iframe load and the parent page, plus the browser console output, into an email to partners@stealth.health.


13. Cross-references & support

  • Referral Tier guide — webhook contract, signature verification, retry policy, and the dead-letter event replay endpoint that fires after the embed submission: Partner API Integration Guide.
  • Clinical Tier guide — full PHI access, intake response API, partner-submitted prescriptions: Clinical Partner API Integration Guide.
  • Prescriber-Partner guide — alternate flow where you collect intake in your own UI and submit it server-to-server: Prescriber-Partner Integration Guide.
  • Package source & examples — the questionnaire-embed package ships a working React example under its examples/ directory.
  • Support channels:
    • Technical bugs: email partners@stealth.health with the details from § 12.
    • Branding rotations, new questionnaire IDs, white-label registration, webhook URL changes: contact your Stealth Health account manager (or partners@stealth.health).
    • Security disclosures: security@stealth.health — do not file a public issue.