Manage CE courses, enrollments, learner progress, certificates, and transactions through a unified REST API
Go to Developer API in your dashboard. Keys are prefixed with cbapi_.
Use the Authorization: Bearer header with any of the 9 services below.
All responses return { "success": true, "data": ... } with pagination.
All API requests require a Bearer token. API keys must start with cbapi_.
Authorization: Bearer cbapi_YOUR_API_KEYcourses:readView CE courses and activitiescourses:writeCreate, update, and delete CE coursescontent:readFetch course phases, HTML content, and quiz questions for native renderingenrollments:readView course enrollments and sales dataenrollments:writeCreate, update, and cancel enrollmentsprogress:readView learner progress and phase completionsprogress:writeSubmit phase completions and quiz answers for server-side validationcompletions:writeMark an entire activity complete in a single call (external LMS / portal ingest)certificates:readView and verify completion certificatestransactions:readView payment and transaction historyevents:readView virtual and in-person live events, schedules, venues, and capacityregistrations:readView event registrations, attendance, and verified durationregistrations:writeRegister learners for live and virtual eventsoutcomes:readReceive follow-up recheck answer keys (is_correct) in course content for server-side gradingpayouts:readView marketplace payouts and revenue-share recordswebhooks:readList and view registered webhook endpointswebhooks:writeCreate, update, and delete webhook endpointsadminFull access to all resources and operationsNine REST services for course management, content delivery, enrollments, progress tracking, certificates, transactions, webhooks, and utility endpoints
Create, manage, and query CE courses and continuing education activities
/api-courses• 60 req/minFetch course phases with HTML content and quiz questions for native rendering in your app. Answer keys are stripped server-side.
/api-course-content• 60 req/minManage learner enrollments, track sales, and handle payment status for courses
/api-enrollments• 60 req/minSubmit phase completions and quiz answers. Server validates answers, calculates scores, and triggers certificate generation.
/api-submit-progress• 60 req/minTrack learner progress through courses, view phase completions and time spent
/api-progress• 60 req/minRetrieve and verify completion certificates for learners who finished courses
/api-certificates• 60 req/minQuery payment history, revenue data, and transaction status for course sales
/api-transactions• 60 req/minList virtual (Zoom) and in-person live events with schedule, venue, capacity, pricing, and the CE activity they award credit for
/api-events• 60 req/minRegister learners for live events and read back verified attendance, duration, and check-in times used for live-activity credit
/api-event-registrations• 60 req/minRead marketplace payouts and Stripe Connect revenue-share transfers for your provider organization
/api-payouts• 60 req/minRegister, list, update, and delete webhook endpoints for event-driven integrations
/api-webhooks• 60 req/minRetrieve active subscription plans with pricing and feature limits — no API key required
/get-subscription-plans• Unlimited# List your courses
curl -X GET "https://aeljuvrsbvkajosclvxs.supabase.co/functions/v1/api-courses" \
-H "Authorization: Bearer cbapi_YOUR_API_KEY"
# Create an enrollment
curl -X POST "https://aeljuvrsbvkajosclvxs.supabase.co/functions/v1/api-enrollments" \
-H "Authorization: Bearer cbapi_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"activity_id": "COURSE_ID",
"user_id": "USER_ID"
}'
# Check learner progress
curl -X GET "https://aeljuvrsbvkajosclvxs.supabase.co/functions/v1/api-progress?activity_id=COURSE_ID" \
-H "Authorization: Bearer cbapi_YOUR_API_KEY"The api-course-content endpoint returns phases containing these component types. Answer keys and correct mappings are stripped server-side for all graded types.
| Type | Description | Stripped? | Submit Format |
|---|---|---|---|
html | Static HTML content block | No | No submission needed — mark phase complete when viewed |
video | Embedded video player | No | No submission needed — mark phase complete when viewed |
mcq | Multiple-choice questions (assessment) | ✓ Yes | answers: [{ question_id, selected }] |
drag-drop-match | Match source items to target items by dragging | ✓ Yes | matches: [{ source_id, target_id }] |
grouping | Drag items into the correct category group | ✓ Yes | placements: [{ item_id, group_id }] |
timed-quiz | Speed-round quiz with per-question timers | ✓ Yes | answers: [{ question_id, selected_index }] |
card-flip | Memory-match card flipping game | ✓ Yes | matched_pairs: [{ card1_id, card2_id }] |
narrative-escape | Interactive escape-room with scenes and hotspot puzzles | ✓ Yes | No standardized submission — mark phase complete when all puzzles solved |
choice | Single-choice selector (optionally graded) | ✓ Yes | answers: [{ question_id, selected }] |
Embed courses natively in your application. Learners never leave your app — you fetch content via API, render it in your own UI, and submit completions back for server-side scoring and certification.
courses:readPull published courses to display in your UI. The response includes name, description, pricing, therapeutic_area, and disease_state.
GET /api-courses?status=published&limit=50
Authorization: Bearer cbapi_YOUR_API_KEY💡Use include_unlisted=true to also retrieve non-marketplace courses you own.
enrollments:writeWhen a user clicks "Enroll" in your app, create an enrollment record. Pass the course ID as activity_id and the learner's user ID.
POST /api-enrollments
Content-Type: application/json
Authorization: Bearer cbapi_YOUR_API_KEY
{
"activity_id": "COURSE_UUID",
"user_id": "LEARNER_UUID",
"enrollment_type": "api"
}💡Ensure your API key has the enrollments:write scope.
content:readRetrieve the full phase structure with HTML content, video URLs, quiz questions, and interactive games (drag-drop, grouping, card-flip, timed-quiz, escape rooms). All answer keys are stripped server-side.
GET /api-course-content?course_id=COURSE_UUID
Authorization: Bearer cbapi_YOUR_API_KEY
// Response includes phases[] with components:
// - type: "html" → render as HTML content
// - type: "video" → embed video player
// - type: "mcq" → render quiz (no answer keys)
// - type: "drag-drop-match" → sourceItems[] + targetItems[] (shuffled)
// - type: "grouping" → groups[] + items[] (correctGroup removed)
// - type: "timed-quiz" → questions[] with timeLimit per question
// - type: "card-flip" → cards[] (pairId removed, shuffled)
// - type: "narrative-escape" → scenes[] with hotspot puzzles💡See the Component Types Reference above for the full schema of each type and the correct submission format.
progress:writeWhen a learner finishes a phase or submits quiz answers, post the completion back. The server validates answers, calculates scores, and auto-generates certificates when all required phases are done.
POST /api-submit-progress
Content-Type: application/json
Authorization: Bearer cbapi_YOUR_API_KEY
{
"activity_id": "COURSE_UUID",
"user_id": "LEARNER_UUID",
"phase_type": "post-assessment",
"phase_id": "phase-1",
"answers": [
{ "question_id": "q1", "selected": "B" },
{ "question_id": "q2", "selected": "A" }
],
"time_spent_minutes": 12
}💡For content phases (no quiz), omit the answers array. The server returns score, passed status, and whether all phases are complete.
progress:readPoll learner progress to update your UI. The response includes current_phase, completed_phases, time_spent_minutes, and certificate status.
GET /api-progress?activity_id=COURSE_UUID&user_id=LEARNER_UUID
Authorization: Bearer cbapi_YOUR_API_KEY💡For detailed phase-level data (scores, pass/fail), use GET /api-progress/{id} with the activity record ID.
certificates:readOnce all required phases are complete, the certificate is auto-generated. Query certificates to get the certificate_id and completion timestamp.
GET /api-certificates?activity_id=COURSE_UUID&user_id=LEARNER_UUID
Authorization: Bearer cbapi_YOUR_API_KEY💡Certificates include a unique certificate_id that can be used for verification.
Subscribe to real-time event notifications. Configure webhooks in your Developer Portal to receive HTTP POST callbacks when key CE lifecycle events occur.
enrollment.createdSupported event type. When delivered, it is triggered when a learner enrolls in a CE activity{
"event": "enrollment.created",
"timestamp": "2025-04-13T14:30:00Z",
"data": {
"enrollment_id": "enr_abc123",
"activity_id": "act_xyz789",
"user_id": "usr_456",
"enrollment_type": "marketplace",
"payment_completed": true,
"enrolled_at": "2025-04-13T14:30:00Z"
}
}progress.updatedSupported event type. When delivered, it is triggered when a learner completes a phase or submits quiz answers{
"event": "progress.updated",
"timestamp": "2025-04-13T15:10:00Z",
"data": {
"enrollment_id": "enr_abc123",
"activity_id": "act_xyz789",
"user_id": "usr_456",
"phase_type": "mcq",
"phase_title": "Post-Test Assessment",
"score": 85,
"passed": true,
"time_spent_minutes": 12,
"completed_phases": 3,
"total_phases": 5
}
}certificate.issuedSupported event type. When delivered, it is triggered when a completion certificate is generated after all phases pass{
"event": "certificate.issued",
"timestamp": "2025-04-13T16:00:00Z",
"data": {
"certificate_id": "cert_xyz789",
"enrollment_id": "enr_abc123",
"activity_id": "act_xyz789",
"user_id": "usr_456",
"certificate_number": "CE-2025-00042",
"activity_title": "Advanced Pharmacology Update 2025",
"credit_hours": 2.0,
"verification_url": "https://iqapparatus.com/verify/cert_xyz789",
"issued_at": "2025-04-13T16:00:00Z"
}
}event.registration.createdSupported event type. Triggered when a learner is registered for a live or virtual event, whether through the API or your branded portal{
"event": "event.registration.created",
"timestamp": "2025-08-20T14:00:00Z",
"data": {
"registration_id": "reg_uuid",
"event_id": "evt_uuid",
"event_title": "ICI Myocarditis: Live Case Debrief",
"user_id": "usr_456",
"status": "registered",
"created_at": "2025-08-20T14:00:00Z"
}
}event.attendance.recordedSupported event type. Triggered when verified attendance is written back for a live event participant — the signal that decides live-activity credit{
"event": "event.attendance.recorded",
"timestamp": "2025-09-12T18:05:00Z",
"data": {
"registration_id": "reg_uuid",
"event_id": "evt_uuid",
"user_id": "usr_456",
"attended": true,
"attendance_percentage": 92,
"duration_minutes": 55,
"meets_minimum": true
}
}payout.paidSupported event type. Triggered when a marketplace payout is transferred to a provider organization through Stripe Connect{
"event": "payout.paid",
"timestamp": "2025-08-01T09:00:00Z",
"data": {
"payout_id": "po_uuid",
"organization_id": "org-uuid",
"amount": 268.95,
"currency": "usd",
"status": "paid",
"purchase_id": "pur_uuid",
"stripe_transfer_id": "tr_1P..."
}
}Every webhook delivery includes an X-Webhook-Signature header and an X-Webhook-Timestamp header. Verify the signature using HMAC-SHA256 with your webhook secret:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}Your endpoint must respond within 30 seconds with a 2xx status code.
Webhook is automatically disabled after 5 consecutive failures. Re-enable from the Developer Portal.
X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetA complete GET /api-course-content response for a published microlearning-series module — avatar video, debrief card, structured references, and series roadmap included. Use it as a test fixture while building your renderer.
video_url is a temporary signed URL that expires atmedia_expires_at (about six hours) — re-fetch the course rather than caching it. The talking-avatar and ai-videoblocks illustrate the ready and pending states.{
"success": true,
"data": {
"course_id": "00000000-0000-4000-8000-000000000001",
"name": "The New PE Classification: A to E",
"description": "Bramwell Method microlearning activity on classifying acute pulmonary embolism using the 2026 AHA/ACC five-category system (Categories A–E).",
"activity_type": null,
"delivery_format": "enduring",
"format": "bramwell",
"delivery_style": "Case-based microlearning",
"learning_objectives": [
"Classify acute pulmonary embolism using the 2026 AHA/ACC five-category system.",
"Match each category to its initial management pathway.",
"Recognize when escalation to advanced therapy is indicated."
],
"accreditation": {
"credits": [
{
"id": "cme-1",
"name": "Physician CME",
"profession": "physician",
"credit_type": "AMA PRA Category 1 Credit(s)™",
"credit_type_slug": "ama-pra-cat1",
"credit_hours": 0.25,
"accredited_provider": "Example Joint Providership",
"provider_statement": "This activity has been planned and implemented in accordance with the accreditation requirements and policies of the ACCME."
}
],
"total_credit_hours": 0.25,
"accreditation_statement": "Accredited for 0.25 AMA PRA Category 1 Credit™.",
"commercial_support": "None",
"disclosure_summary": "All planners and faculty have disclosed no relevant financial relationships.",
"release_date": "2026-01-01",
"expiration_date": "2027-01-01"
},
"landing_page": {
"statementOfNeed": "Acute PE classification drives management, yet the five-category system is unevenly applied.",
"estimatedTime": "15 minutes",
"targetAudience": [
"Physicians",
"Nurse Practitioners",
"Physician Assistants",
"Pharmacists"
],
"howToEarnCredit": "Complete the microlearning, submit the evaluation, and download your certificate.",
"hardwareSoftwareRequirements": "Modern browser with a stable internet connection."
},
"confidence_baseline": {
"id": "confidence-baseline",
"prompt": "Before you start, how confident are you in classifying acute PE severity?",
"min": 1,
"max": 5,
"minLabel": "Not at all confident",
"maxLabel": "Very confident"
},
"evaluation_questions": [
{
"id": "eval-overall-quality",
"question": "The activity was:",
"type": "single-select",
"options": [
"Excellent",
"Very Good",
"Good",
"Fair",
"Poor"
],
"category": "satisfaction",
"mooreLevel": 1,
"required": true
}
],
"total_phases": 5,
"phases": [
{
"id": "phase-hook",
"title": "Meet the Patient",
"type": "introduction",
"required": true,
"order": 0,
"components": [
{
"id": "phase-hook-html",
"type": "html",
"content": "<h2>15 minutes. Four decisions.</h2><p>Meet Carlos — 55, presents with acute dyspnea, O₂ sat 93% on room air, BP 118/74. CT angiography confirms bilateral pulmonary emboli. Troponin I is elevated. Bedside echo shows RV dilation with an RV:LV ratio >0.9, but he is hemodynamically stable. Walk his workup in four decisions.</p>"
}
]
},
{
"id": "phase-decisions",
"title": "Four Clinical Decisions",
"type": "pre-assessment",
"required": true,
"order": 1,
"components": [
{
"id": "phase-decisions-mcq",
"type": "mcq",
"questions": [
{
"id": "m1",
"type": "multiple-choice",
"matchId": "m1",
"options": [
"Category C — elevated biomarkers/RV dysfunction, no hemodynamic failure",
"Category B — low risk, symptomatic",
"Submassive PE (legacy terminology)",
"Category D — incipient cardiopulmonary failure"
],
"question": "Carlos, 55, acute PE, troponin elevated, RV:LV >0.9, BP 118/74. How do you classify his PE under the 2026 guideline?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "d2",
"type": "multiple-choice",
"matchId": "d2",
"options": [
"Yes — Category C requires inpatient monitoring",
"No — he is hemodynamically stable and can go home",
"Only if he fails a 6-hour observation period",
"Only if D-dimer exceeds 4,000 ng/mL"
],
"question": "Does Carlos require hospitalization?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "d3",
"type": "multiple-choice",
"matchId": "d3",
"options": [
"DOAC (e.g., rivaroxaban or apixaban)",
"Warfarin with heparin bridge",
"Unfractionated heparin drip alone",
"Aspirin plus clopidogrel"
],
"question": "What is the preferred anticoagulant class for Carlos?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "d4",
"type": "multiple-choice",
"matchId": "d4",
"options": [
"Yes — Class 1 recommendation for complex PE with RV dysfunction",
"No — PERT is only for Category E with cardiac arrest",
"Only after 48 hours of failed anticoagulation",
"Only if systemic thrombolysis is the plan"
],
"question": "Should you activate PERT for Carlos?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
}
]
}
]
},
{
"id": "phase-teach",
"title": "What the Guideline Says",
"type": "content",
"required": true,
"order": 2,
"components": [
{
"id": "phase-teach-avatar",
"type": "talking-avatar",
"title": "Faculty walkthrough: classifying Carlos",
"video_status": "ready",
"video_url": "https://example-signed-media.invalid/avatar/EXAMPLE.mp4?token=PLACEHOLDER_SIGNED_URL",
"expires_at": "2026-08-18T04:39:00.000Z",
"poster_url": "https://example-signed-media.invalid/avatar/EXAMPLE-poster.jpg",
"duration_seconds": 96
},
{
"id": "phase-teach-html",
"type": "html",
"content": "<h3>Decision 1 — Classify PE severity: Category C</h3><p>The 2026 AHA/ACC guideline introduces a <strong>five-category clinical classification</strong> that replaces the legacy massive/submassive/low-risk model [1]:</p><ul><li><strong>Category A</strong> — Asymptomatic (incidental PE): normal hemodynamics, no symptoms, negative biomarkers.</li><li><strong>Category B</strong> — Low risk: symptomatic but normal RV function, negative biomarkers.</li><li><strong>Category C</strong> — Elevated biomarkers and/or RV dysfunction <em>without</em> hemodynamic compromise.</li><li><strong>Category D</strong> — Incipient cardiopulmonary failure: hemodynamic instability not yet refractory.</li><li><strong>Category E</strong> — Cardiopulmonary failure with persistent hypotension or cardiac arrest.</li></ul><p>Carlos has elevated troponin, RV dilation (RV:LV >0.9), and stable blood pressure — he is <strong>Category C</strong> [1].</p><h3>Decision 2 — Does Carlos need hospitalization? Yes</h3><p>Category C patients require inpatient monitoring because they carry an elevated short-term risk of hemodynamic deterioration. The 2026 guideline recommends hospitalization with serial reassessment for all Category C, D, and E patients [1]. Only Category A (and select Category B) patients may be considered for early or home discharge.</p><h3>Decision 3 — Anticoagulate with a DOAC</h3><p>The 2026 guideline recommends <strong>DOACs over vitamin K antagonists</strong> for acute PE in patients without contraindications (active cancer requiring LMWH, antiphospholipid syndrome, severe renal impairment CrCl <15 mL/min) [1]. Carlos has no contraindication — start a DOAC today. Rivaroxaban (15 mg BID × 21 days, then 20 mg daily) and apixaban (10 mg BID × 7 days, then 5 mg BID) do not require heparin bridging [1].</p><h3>Decision 4 — Activate PERT for Category C with RV dysfunction</h3><p>The 2026 guideline elevates the <strong>Pulmonary Embolism Response Team (PERT) to a Class 1 recommendation</strong> for complex PE [1]. Carlos’s RV dilation and elevated troponin place him at risk of deterioration. Activating PERT brings pulmonology, interventional radiology, cardiology, and critical care to the table in real time to determine whether anticoagulation alone is sufficient or whether catheter-directed therapy should be prepared [1,3]. Over 100 medical centers participate in the National PERT Consortium, yet most U.S. hospitals still lack a formal PERT [3].</p>"
},
{
"id": "phase-teach-aivideo",
"type": "ai-video",
"title": "Case animation (still rendering)",
"video_status": "pending"
}
]
},
{
"id": "phase-check",
"title": "Confirm Your Knowledge",
"type": "post-assessment",
"required": true,
"order": 3,
"debrief_readout": {
"title": "Before vs. after — your matched item",
"confidenceKeys": {
"baselineId": "confidence-baseline"
},
"matches": [
{
"matchId": "m1",
"label": "Which category describes elevated biomarkers with stable hemodynamics?"
}
]
},
"components": [
{
"id": "phase-check-mcq",
"type": "mcq",
"questions": [
{
"id": "posttest-m1",
"type": "multiple-choice",
"matchId": "m1",
"options": [
"Category C — elevated biomarkers/RV dysfunction, no hemodynamic failure",
"Category B — low risk, symptomatic",
"Submassive PE (legacy terminology)",
"Category D — incipient cardiopulmonary failure"
],
"question": "Carlos, 55, acute PE, troponin elevated, RV:LV >0.9, BP 118/74. How do you classify his PE under the 2026 guideline?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "posttest-d2",
"type": "multiple-choice",
"matchId": "d2",
"options": [
"Yes — Category C requires inpatient monitoring",
"No — he is hemodynamically stable and can go home",
"Only if he fails a 6-hour observation period",
"Only if D-dimer exceeds 4,000 ng/mL"
],
"question": "Does Carlos require hospitalization?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "posttest-d3",
"type": "multiple-choice",
"matchId": "d3",
"options": [
"DOAC (e.g., rivaroxaban or apixaban)",
"Warfarin with heparin bridge",
"Unfractionated heparin drip alone",
"Aspirin plus clopidogrel"
],
"question": "What is the preferred anticoagulant class for Carlos?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "posttest-d4",
"type": "multiple-choice",
"matchId": "d4",
"options": [
"Yes — Class 1 recommendation for complex PE with RV dysfunction",
"No — PERT is only for Category E with cardiac arrest",
"Only after 48 hours of failed anticoagulation",
"Only if systemic thrombolysis is the plan"
],
"question": "Should you activate PERT for Carlos?",
"difficulty": "intermediate",
"mooreLevel": 3,
"deliveryStyle": "embedded",
"outcomeMetric": "knowledge"
},
{
"id": "m1",
"type": "multiple-choice",
"matchId": "m1",
"options": [
"Category B — low risk",
"Category C — elevated biomarkers/RV dysfunction without hemodynamic failure",
"Category D — incipient cardiopulmonary failure",
"Category E — cardiopulmonary failure"
],
"question": "A 60-year-old presents with acute PE: troponin elevated, echo shows RV:LV ratio 1.0, BP 122/78. Which 2026 classification applies?",
"badgeLabel": "MATCHED TO DECISION 1",
"difficulty": "intermediate",
"mooreLevel": 3,
"outcomeMetric": "knowledge"
}
]
}
]
},
{
"id": "phase-commit",
"title": "Commit to Change",
"type": "evaluation",
"required": true,
"order": 4,
"components": [
{
"id": "phase-commit-evaluation",
"type": "evaluation",
"questions": [
{
"id": "eval-overall-quality",
"type": "single-select",
"options": [
"Excellent",
"Very Good",
"Good",
"Fair",
"Poor"
],
"category": "satisfaction",
"question": "The activity was:",
"required": true,
"mooreLevel": 1,
"outcomeMetric": "satisfaction",
"response_type": "single-select",
"response_options": [
"Excellent",
"Very Good",
"Good",
"Fair",
"Poor"
],
"scale": null
},
{
"id": "eval-fair-balanced",
"type": "yes-no",
"category": "bias",
"question": "The activity was fair and balanced:",
"required": true,
"mooreLevel": 1,
"outcomeMetric": "bias",
"response_type": "yes-no",
"response_options": null,
"scale": null
},
{
"id": "eval-evidence-based",
"type": "yes-no",
"category": "evidence",
"question": "The activity content was evidence based:",
"required": true,
"mooreLevel": 1,
"outcomeMetric": "evidence",
"response_type": "yes-no",
"response_options": null,
"scale": null
},
{
"id": "eval-disclosures-shown",
"type": "yes-no",
"category": "disclosure",
"question": "The author’s relevant financial relationships (or lack thereof) were disclosed:",
"required": true,
"mooreLevel": 1,
"outcomeMetric": "disclosure",
"response_type": "yes-no",
"response_options": null,
"scale": null
},
{
"id": "eval-confidence-post",
"max": 5,
"min": 1,
"step": 1,
"type": "slider",
"category": "confidence",
"maxLabel": "Very confident",
"minLabel": "Not at all confident",
"question": "After this activity, how confident are you in classifying acute PE using the 2026 five-category system?",
"required": true,
"mooreLevel": 2,
"outcomeMetric": "confidence",
"response_type": "slider",
"response_options": null,
"scale": null
},
{
"id": "commit-to-change",
"type": "multi-select",
"options": [
"Apply the A–E classification instead of massive/submassive/low-risk",
"Hospitalize all Category C patients with serial reassessment",
"Start a DOAC as first-line anticoagulation for eligible PE patients",
"Activate PERT for Category C patients with RV dysfunction",
"Establish or join a PERT at my institution",
"Other"
],
"category": "commitment-to-change",
"question": "Commit to change — select every action you will take for the next patient like Carlos (choose one or more):",
"required": true,
"mooreLevel": 3,
"outcomeMetric": "intent",
"response_type": "multi-select",
"response_options": [
"Apply the A–E classification instead of massive/submassive/low-risk",
"Hospitalize all Category C patients with serial reassessment",
"Start a DOAC as first-line anticoagulation for eligible PE patients",
"Activate PERT for Category C patients with RV dysfunction",
"Establish or join a PERT at my institution",
"Other"
],
"scale": null
}
]
}
]
}
],
"debrief": {
"caseTakeaway": "<p>Carlos’s PE is not ‘submassive’ anymore — it’s <strong>Category C</strong>. The 2026 AHA/ACC five-category system (A–E) gives every PE a letter that maps directly to disposition, anticoagulation, and escalation. Carlos’s elevated troponin and RV dilation without hemodynamic compromise put him squarely in Category C: admit, start a DOAC, and activate PERT to decide whether anticoagulation alone is enough or catheter-directed therapy should be on standby [1].</p><h3>What to do differently for your next patient like Carlos</h3><ul><li><strong>Classify, don’t label.</strong> Replace ‘massive/submassive/low-risk’ with Categories A–E at the point of diagnosis.</li><li><strong>Hospitalize C, D, and E.</strong> Only Category A (and select Category B) patients may be considered for home or early discharge.</li><li><strong>Start DOAC first line</strong> unless the patient has active cancer, antiphospholipid syndrome, or CrCl <15 mL/min.</li><li><strong>Activate PERT early</strong> for Category C with RV dysfunction, and for all Category D and E patients.</li></ul><h3>When to escalate</h3><p>If Carlos deteriorates — falling BP, rising lactate, worsening RV function — he reclassifies to Category D. PERT should already be at the table to pivot to catheter-directed therapy or systemic thrombolysis.</p>",
"answerKeyHtml": "",
"nextStepsHtml": ""
},
"references": [
{
"doi": "10.1161/CIR.0000000000001415",
"year": 2026,
"title": "2026 AHA/ACC/ACCP/ACEP/CHEST/SCAI/SHM/SIR/SVM/SVN Guideline for the Evaluation and Management of Acute Pulmonary Embolism in Adults",
"number": "1",
"authors": [
"Defined Authorship Committee"
],
"journal": "Circulation"
},
{
"doi": "10.1093/eurheartj/ehz405",
"year": 2020,
"title": "2019 ESC Guidelines for the Diagnosis and Management of Acute Pulmonary Embolism",
"number": "2",
"authors": [
"Konstantinides SV",
"Meyer G",
"Becattini C",
"et al."
],
"journal": "Eur Heart J"
},
{
"url": "https://pertconsortium.org",
"year": 2025,
"title": "Pulmonary Embolism Response Team Database: 12,346 Patients Across 35 Institutions, 2015–2024",
"number": "3",
"authors": [
"National PERT Consortium"
],
"journal": "pertconsortium.org"
},
{
"doi": "10.3389/fmed.2025.1708409",
"year": 2025,
"title": "Catheter-Directed Therapy for Acute Pulmonary Embolism: Evidence, Gaps, and Future Directions",
"number": "4",
"authors": [
"Bikdeli B",
"Mazzeffi MA",
"Engstrom BI",
"et al."
],
"journal": "Front Med"
},
{
"doi": "10.1016/S2213-2600(23)00093-2",
"year": 2023,
"title": "Chronic Thromboembolic Pulmonary Hypertension and Post-PE Syndrome",
"number": "5",
"authors": [
"Klok FA",
"Barco S",
"Konstantinides SV"
],
"journal": "Lancet Respir Med"
}
],
"series": {
"series_id": "bramwell-2026-acute-pe-management-series-41953f",
"name": "2026 Acute PE Management Series",
"description": "Five 15-minute Bramwell Method microlearnings translating the landmark 2026 AHA/ACC Pulmonary Embolism Guideline — the new five-category clinical classification, safe ED discharge for asymptomatic PE, DOAC selection and dosing, the Class 1 PERT recommendation, and structured post-PE follow-up for chronic thromboembolic disease — into point-of-care decisions. Designed for emergency physicians, hospitalists, pulmonologists, NPs, PAs, and pharmacists who diagnose and manage acute PE.",
"position": 1,
"total": 5,
"modules": [
{
"course_id": "00000000-0000-4000-8000-000000000001",
"title": "The New PE Classification: A to E",
"status": "available",
"position": 1
},
{
"course_id": "00000000-0000-4000-8000-000000000002",
"title": "Category A PE: Home from the ED",
"status": "available",
"position": 2
},
{
"course_id": "00000000-0000-4000-8000-000000000003",
"title": "DOACs: Choosing and Dosing for Acute PE",
"status": "available",
"position": 3
},
{
"course_id": "00000000-0000-4000-8000-000000000004",
"title": "PERT Class 1: Building and Using Your PE Response Team",
"status": "available",
"position": 4
},
{
"course_id": "00000000-0000-4000-8000-000000000005",
"title": "Post-PE Syndrome: The Follow-Up Nobody Is Doing",
"status": "available",
"position": 5
}
]
},
"media_expires_at": "2026-08-18T04:39:00.000Z"
},
"error": null
}IQ Apparatus owns the render contract. Every response carries contract_version in the envelope, and course payloads repeat it inside data. Changes are additive only: fields are never removed or retyped within a revision. Ignore unknown fields, render unknown component and phase types as a notice rather than dropping them, and treat an unrecognized revision as newer than yours.
Zero-import TypeScript. Vendor it directly — no dependency on our package.
/contract/iq-render-contract.tsImmutable revision. Pin this if you want to opt into upgrades deliberately.
/contract/iq-render-contract-2026-09-03.tsFor non-TypeScript consumers and CI validation of stored payloads.
/contract/iq-render-contract.schema.jsonCatalog, full Bramwell series module, pending/failed media, unknown-revision probe.
/contract/fixtures/index.jsonSequential gating is yours
series.sequential_gating_enforced is always false. The API will serve module N even if N−1 is incomplete. Use series.next / series.previous plus your own completion records to gate the roadmap.
When data.format === "bramwell", the payload carries the Bramwell structure — learning_objectives, accreditation, landing_page, evaluation_questions, confidence_baseline, and per-phase debrief_readout. Pair it with the spec and the namespaced theme below to reproduce the IQ Apparatus experience one-for-one.
| Type | Required rendering | Accepted fallback |
|---|---|---|
| talking-avatar / ai-video | Video with poster + captions; pending state when video_status !== "ready" | Poster + transcript |
| choice (decision card) | Card list, single select, no rationale before submission | Radio group |
| confidence-check | Slider min→max with end labels | Radio scale, same values |
| image-hotspot | Image with clickable hotspot regions | Static image + list of hotspot labels |
| card-flip | Flip cards | Term / definition list |
| drag-drop-match | Drag sources onto targets | Per-source dropdown of targets |
Every fallback must post the same answer shape to POST /api-submit-progress — outcomes reporting depends on answer shape, not on widget fidelity.
required + order)api-submit-progress only)expires_at, and the payload carries media_expires_at. Never cache or static-render a video_url past that time — re-fetch the course right before playback.:root; every token and recipe is scoped under .iq-bramwell-theme, so it cannot leak into your layout.