amirmh's picture
Audit pass: merge duplicate docs (57 total), fix ADR index links, header overflow, mobile tables, members button in header, WebP illustrations
612e777 verified
Raw
History Blame Contribute Delete
28.9 kB
<article aria-hidden="true" class="doc" id="doc-reference-api">
<div class="strip"><span class="path">reference/api.md</span></div>
<h1>8. API Specification &amp; Integration</h1>
<h2 id="doc-reference-api--h1">8.1 Conventions</h2>
<ul>
<li>Base URL <code>https://api.travi ai agent.health/v1</code>; JSON only; <code>Authorization: Bearer &lt;jwt&gt;</code>; TLS 1.2+.</li>
<li>Errors: RFC 9457 problem+json (<code>type</code>, <code>title</code>, <code>status</code>, <code>detail</code>, <code>trace_id</code>); no PHI in error bodies.</li>
<li>All mutating POSTs accept <code>Idempotency-Key</code> header (UUID); server stores response hash 48 h and replays on retry.</li>
<li>Pagination: cursor (<code>?cursor=&amp;limit≤100</code>); list responses <code>{items, next_cursor}</code>.</li>
<li>Rate limits (WAF+Redis): activation 10/min/IP; patient APIs 60/min/session; clinician brief open 30/min/grant; 429 with <code>Retry-After</code>.</li>
<li>ETag/If-Match on <code>GET /today</code> and task PATCH bound to <code>episode.version</code>, stale writes get 409 with refresh directive.</li>
</ul>
<p style="font-size:15px;color:var(--slate);margin-bottom:28px;max-width:700px;line-height:1.6;">
A lightweight integration specification covering the FHIR R4 endpoints Travi consumes and exposes, authentication flow, webhook contracts, and a self-assessment checklist for hospital IT teams evaluating integration complexity.
</p>
<!-- ── AUTH FLOW ─────────────────────────────────────────────────────────── -->
<h2 id="api-auth">8.2 Authentication</h2>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:18px 20px;margin:16px 0 24px;">
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px;">
<div>
<div style="font-size:11px;font-weight:700;color:#38bdf8;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px;">SMART on FHIR 2.0</div>
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0;">Travi registers as a SMART on FHIR app in the hospital's EHR App Gallery. OAuth 2.0 authorization code flow with PKCE. Scopes requested: <code>patient/*.read</code>, <code>user/Task.write</code>, <code>user/Communication.write</code>, <code>user/ClinicalImpression.write</code>.</p>
</div>
<div>
<div style="font-size:11px;font-weight:700;color:#38bdf8;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px;">JWT Bearer Tokens</div>
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0;">All Travi API endpoints require a signed JWT bearer token. Tokens are scoped per hospital, expire in 1 hour, and are rotated automatically. Hospital IT teams receive a client ID and client secret during onboarding, no API keys are shared with clinical staff.</p>
</div>
<div>
<div style="font-size:11px;font-weight:700;color:#38bdf8;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px;">Mutual TLS (mTLS)</div>
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0;">For hospitals that require it, Travi supports mTLS on the FHIR ingest endpoint. The hospital provides a client certificate during onboarding; Travi pins the certificate and rejects connections from any other source.</p>
</div>
</div>
</div>
<!-- ── INBOUND ENDPOINTS (what Travi reads from the EHR) ─────────────────── -->
<h2 id="api-inbound">8.3 Inbound: FHIR Resources Travi Reads</h2>
<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin:16px 0 28px;">
<table style="width:100%;border-collapse:collapse;min-width:580px;">
<thead>
<tr style="background:var(--surface);border-bottom:2px solid var(--border);">
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">FHIR Resource</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Trigger</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Key Fields Used</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Required</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Encounter</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">status = <code>finished</code>, class = <code>IMP</code> (inpatient)</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">period.end, subject, hospitalization.dischargeDisposition</td>
<td style="padding:10px 14px;"><span style="background:rgba(239,68,68,0.12);color:#f87171;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">YES</span></td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Patient</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Pulled on discharge event</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">name, telecom (phone), birthDate, address, language</td>
<td style="padding:10px 14px;"><span style="background:rgba(239,68,68,0.12);color:#f87171;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">YES</span></td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">MedicationRequest</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">status = <code>active</code>, linked to Encounter</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">medication.code, dosageInstruction, dispenseRequest.numberOfRepeatsAllowed</td>
<td style="padding:10px 14px;"><span style="background:rgba(239,68,68,0.12);color:#f87171;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">YES</span></td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">DocumentReference</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">type = discharge summary (LOINC 18842-5)</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">content.attachment (base64 or URL), context.encounter</td>
<td style="padding:10px 14px;"><span style="background:rgba(239,68,68,0.12);color:#f87171;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">YES</span></td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Appointment</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">status = <code>booked</code>, linked to Patient</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">start, end, participant, serviceType</td>
<td style="padding:10px 14px;"><span style="background:rgba(245,158,11,0.12);color:#fbbf24;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">OPTIONAL</span></td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Observation</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">category = vital-signs or laboratory, last 30 days</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">code (LOINC), valueQuantity, effectiveDateTime</td>
<td style="padding:10px 14px;"><span style="background:rgba(245,158,11,0.12);color:#fbbf24;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">OPTIONAL</span></td>
</tr>
<tr>
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Condition</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">clinicalStatus = <code>active</code>, linked to Patient</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">code (ICD-10), severity, onsetDateTime</td>
<td style="padding:10px 14px;"><span style="background:rgba(245,158,11,0.12);color:#fbbf24;font-size:11px;font-weight:700;padding:2px 8px;border-radius:4px;">OPTIONAL</span></td>
</tr>
</tbody>
</table>
</div>
<!-- ── OUTBOUND ENDPOINTS (what Travi writes back) ────────────────────────── -->
<h2 id="api-outbound">8.4 Outbound: FHIR Resources Travi Writes</h2>
<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin:16px 0 28px;">
<table style="width:100%;border-collapse:collapse;min-width:580px;">
<thead>
<tr style="background:var(--surface);border-bottom:2px solid var(--border);">
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">FHIR Resource</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Purpose</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Trigger</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Frequency</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Task</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Care plan task status (completed, in-progress, failed)</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Patient SMS response or daily batch</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Daily or on event</td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Communication</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Log of all patient-Travi SMS interactions</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Each SMS sent or received</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Real-time</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">ClinicalImpression</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">AI-generated risk assessment with score and rationale</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Risk score threshold crossed or daily</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Daily + on escalation</td>
</tr>
<tr>
<td style="padding:10px 14px;font-size:13px;font-weight:600;color:var(--ink);font-family:monospace;">Flag</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">High-risk patient alert visible in EHR patient banner</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Escalation engine fires</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">On escalation only</td>
</tr>
</tbody>
</table>
</div>
<!-- ── WEBHOOK CONTRACT ────────────────────────────────────────────────────── -->
<h2 id="api-webhooks">8.5 Webhook Contract</h2>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:18px 20px;margin:16px 0 24px;">
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0 0 14px;">Travi exposes a single inbound webhook endpoint for EHR systems that push rather than allow polling:</p>
<pre style="background:rgba(0,0,0,0.3);border:1px solid var(--border);border-radius:8px;padding:14px 16px;overflow-x:auto;margin:0 0 14px;"><code style="font-size:12px;color:#e2e8f0;font-family:'JetBrains Mono',monospace;">POST https://api.travi.ai/v1/fhir/webhook
Authorization: Bearer &lt;hospital_jwt&gt;
Content-Type: application/fhir+json
X-Travi-Signature: sha256=&lt;hmac_signature&gt;
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{ "resource": { "resourceType": "Encounter", ... } },
{ "resource": { "resourceType": "Patient", ... } }
]
}</code></pre>
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0;">All webhook payloads are HMAC-SHA256 signed using the hospital's shared secret. Travi validates the signature before processing. Idempotency key: <code>Encounter.id</code>, duplicate discharge events for the same encounter are deduplicated automatically. Response: <code>202 Accepted</code> within 200ms; processing is async.</p>
</div>
<!-- ── ANALYTICS API ───────────────────────────────────────────────────────── -->
<h2 id="api-analytics">8.6 Analytics API (Hospital Read-Only)</h2>
<div style="overflow-x:auto;-webkit-overflow-scrolling:touch;margin:16px 0 28px;">
<table style="width:100%;border-collapse:collapse;min-width:540px;">
<thead>
<tr style="background:var(--surface);border-bottom:2px solid var(--border);">
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Endpoint</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Returns</th>
<th style="padding:10px 14px;text-align:left;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--slate);">Auth</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:12.5px;font-family:monospace;color:var(--ink);">GET /v1/analytics/readmissions</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">30-day readmission rate by cohort, DRG, and month</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Hospital admin JWT</td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:12.5px;font-family:monospace;color:var(--ink);">GET /v1/analytics/adherence</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Medication fill rate, appointment attendance, task completion by cohort</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Hospital admin JWT</td>
</tr>
<tr style="border-bottom:1px solid var(--border);">
<td style="padding:10px 14px;font-size:12.5px;font-family:monospace;color:var(--ink);">GET /v1/analytics/hrrp</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Projected HRRP penalty reduction and estimated dollar savings</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Hospital admin JWT</td>
</tr>
<tr style="border-bottom:1px solid var(--border);background:rgba(255,255,255,0.015);">
<td style="padding:10px 14px;font-size:12.5px;font-family:monospace;color:var(--ink);">GET /v1/analytics/tcm-billing</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">TCM-eligible encounters, billed vs. unbilled, CPT code breakdown</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Hospital admin JWT</td>
</tr>
<tr>
<td style="padding:10px 14px;font-size:12.5px;font-family:monospace;color:var(--ink);">GET /v1/patients/{id}/timeline</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Full 30-day task and interaction timeline for a single patient</td>
<td style="padding:10px 14px;font-size:13px;color:var(--slate);">Care coordinator JWT (own cohort only)</td>
</tr>
</tbody>
</table>
</div>
<!-- ── IT SELF-ASSESSMENT CHECKLIST ───────────────────────────────────────── -->
<h2 id="doc-reference-api--h2">8.7 Endpoint Catalog</h2>
<h3 id="doc-reference-api--h3">Patient &amp; Caregiver surface</h3>
<div class="tbl-wrap"><table class="col-table compact" style="table-layout:fixed;"><colgroup><col class="col-xs" style="width:60px"/><col class="col-md" style="width:220px"/><col class="col-lg" style="width:auto"/></colgroup>
<thead>
<tr>
<th>Verb</th>
<th>Path</th>
<th>Purpose / Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/patient/activate/start</td>
<td data-label="Purpose / Notes">Body: activation token. Returns verification challenge spec. Never discloses episode existence on failure (ENR-005).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/patient/activate/verify</td>
<td data-label="Purpose / Notes">DOB + channel proof → access+refresh tokens; consent state included; 5/24 h lockout.</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/auth/refresh · /auth/logout</td>
<td data-label="Purpose / Notes">Rotating refresh with reuse detection → family revocation; logout kills session + SW purge signal.</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/today</td>
<td data-label="Purpose / Notes">≤3 primary actions + secondary list; server-ordered (PAT-001); ETag=episode.version.</td>
</tr>
<tr>
<td data-label="Verb">PATCH</td>
<td data-label="Path">/tasks/{id}/response</td>
<td data-label="Purpose / Notes">Body: done|not_yet|cannot_do|not_sure (+barrier_code). Drives §7.1 transitions (PAT-005).</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/medications</td>
<td data-label="Purpose / Notes">Plan items + latest status per dimension; <code>verified</code> flag explicit (MED-006).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/medications/{id}/status</td>
<td data-label="Purpose / Notes">Patient-report status event; server assigns evidence_class=patient_report.</td>
</tr>
<tr>
<td data-label="Verb">GET/POST</td>
<td data-label="Path">/appointments · /appointments/assist</td>
<td data-label="Purpose / Notes">List reqs+appts; submit assisted-scheduling request without re-entering demographics (APT-004).</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/plan · /visit-prep/{apptId} · /handoff</td>
<td data-label="Purpose / Notes">30-day timeline w/ provenance labels; visit prep questions; day-30 summary.</td>
</tr>
<tr>
<td data-label="Verb">GET/POST</td>
<td data-label="Path">/consents · /caregivers · DELETE /caregivers/{id}</td>
<td data-label="Purpose / Notes">Consent views/updates; caregiver invite (own token flow) &amp; instant revoke (CGV-004).</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/emergency-card</td>
<td data-label="Purpose / Notes">Minimal offline payload (contact, 911 text, med names+sig); served with SW cache headers (ADR-012).</td>
</tr>
</tbody>
</table></div>
<h3 id="doc-reference-api--h4">Clinician surface</h3>
<div class="tbl-wrap"><table class="col-table compact" style="table-layout:fixed;"><colgroup><col class="col-xs" style="width:60px"/><col class="col-auto" style="width:220px"/><col class="col-lg" style="width:auto"/></colgroup>
<thead>
<tr>
<th>Verb</th>
<th>Path</th>
<th>Purpose / Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/clinician/access/start · /verify</td>
<td data-label="Purpose / Notes">Magic-link token → email OTP (6-digit, 10 min) → grant JWT bound to device fingerprint (§9.3).</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/clinician/brief/{grantId}</td>
<td data-label="Purpose / Notes">Runs staleness check (§14.4); returns snapshot or 202 {regenerating} → poll ≤5 s.</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/clinician/brief/{id}/source/{factId}</td>
<td data-label="Purpose / Notes">Source viewer: span text + hierarchy decision (DPC-008).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/clinician/confirmations</td>
<td data-label="Purpose / Notes">Confirm/reject pending material items; <strong>requires step-up OTP ≤5 min old</strong> (VIS-007).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/clinician/post-visit</td>
<td data-label="Purpose / Notes">Upload note/AVS (S3 presigned) or structured summary → reprocess loop (VIS-005).</td>
</tr>
</tbody>
</table></div>
<h3 id="doc-reference-api--h5">Admin, integration &amp; webhooks</h3>
<div class="tbl-wrap"><table class="col-table compact" style="table-layout:fixed;"><colgroup><col class="col-xs" style="width:60px"/><col class="col-auto" style="width:220px"/><col class="col-lg" style="width:auto"/></colgroup>
<thead>
<tr>
<th>Verb</th>
<th>Path</th>
<th>Purpose / Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Verb">CRUD</td>
<td data-label="Path">/admin/cohorts · /templates · /config</td>
<td data-label="Purpose / Notes">Versioned publish (draft→review→published); never mutates active episodes (§2.2).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/admin/kill-switches</td>
<td data-label="Purpose / Notes">Six scopes (§16.4); takes effect ≤10 s; reason mandatory; audited.</td>
</tr>
<tr>
<td data-label="Verb">GET</td>
<td data-label="Path">/admin/reports/execution · /outcomes</td>
<td data-label="Purpose / Notes">ADM-004 categories; ADM-007 with completeness/coverage footers (ADR-016).</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/admin/overrides/eligibility</td>
<td data-label="Purpose / Notes">ENR-002 override with reason; duplicate-episode guard.</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/integration/adt</td>
<td data-label="Purpose / Notes">HL7v2 over MLLP→HTTPS bridge from interface engine (VPN); HMAC-signed; idempotent on MSH-10.</td>
</tr>
<tr>
<td data-label="Verb">POST</td>
<td data-label="Path">/webhooks/twilio · /webhooks/ses</td>
<td data-label="Purpose / Notes">Delivery status; signature-validated; drives channel ladder.</td>
</tr>
</tbody>
</table></div>
<h2 id="doc-reference-api--h6">8.8 Representative Payload</h2>
<pre><code>PATCH /v1/tasks/9f2e.../response GET /v1/today (excerpt)
{ {
"response": "cannot_do", "episode_version": 41,
"barrier_code": "cost" "primary": [{
} "task_id": "9f2e...",
→ 200 "category": "medication",
{ "priority": "critical",
"task": {"id":"9f2e...", "title": "Pick up spironolactone",
"state":"blocked", "due_at": "2026-07-15",
"barrier_code":"cost"}, "provenance": {"label":"From your signed
"next": {"type":"barrier_flow", discharge summary","level":1},
"flow":"med_cost_assist"} "actions": ["done","not_yet",
} "cannot_do","not_sure"]}]
}
</code></pre>
<div class="pn"><a class="pn-prev" href="#"></a><a class="pn-next" href="#"></a></div>
<h2 id="api-checklist">8.9 Hospital IT Self-Assessment Checklist</h2>
<p style="font-size:13.5px;color:var(--slate);margin:8px 0 16px;line-height:1.6;">Use this checklist to estimate integration complexity before the first call with Travi's integration team. All "YES" answers indicate a standard 6–8 week integration. Each "NO" adds 1–3 weeks.</p>
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;margin-bottom:28px;">
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">FHIR R4 endpoint available</div><div style="font-size:12px;color:var(--slate);">EHR exposes a FHIR R4 API (Epic FHIR, Oracle FHIR, or equivalent)</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">SMART on FHIR app registration supported</div><div style="font-size:12px;color:var(--slate);">IT team can register a third-party SMART app in the EHR app gallery</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">ADT events accessible via FHIR Subscription or webhook</div><div style="font-size:12px;color:var(--slate);">Discharge events can be pushed or polled in near-real-time</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">Discharge summaries in DocumentReference</div><div style="font-size:12px;color:var(--slate);">Discharge summary text accessible as FHIR DocumentReference (LOINC 18842-5)</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">Task resource write-back permitted</div><div style="font-size:12px;color:var(--slate);">Third-party apps can write Task, Communication, and ClinicalImpression resources back to the EHR</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">Patient phone numbers in telecom field</div><div style="font-size:12px;color:var(--slate);">Patient.telecom contains a mobile phone number for SMS delivery</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">BAA can be executed with Travi</div><div style="font-size:12px;color:var(--slate);">Legal and compliance team can sign a Business Associate Agreement before go-live</div></div>
</div>
<div style="background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px 14px;display:flex;align-items:flex-start;gap:10px;">
<span style="font-size:16px;flex-shrink:0;"></span>
<div><div style="font-size:12.5px;font-weight:600;color:var(--ink);margin-bottom:2px;">Sandbox / test environment available</div><div style="font-size:12px;color:var(--slate);">EHR has a non-production sandbox with synthetic patient data for integration testing</div></div>
</div>
</div>
<div style="background:color-mix(in srgb,#0ea5e9 8%,var(--surface));border:1px solid color-mix(in srgb,#0ea5e9 30%,var(--border));border-radius:10px;padding:16px 20px;">
<div style="font-size:11px;font-weight:700;color:#38bdf8;letter-spacing:.08em;text-transform:uppercase;margin-bottom:8px;">Integration Support</div>
<p style="font-size:13px;color:var(--slate);line-height:1.6;margin:0;">Travi provides a dedicated integration engineer for every pilot and contract customer. The integration engineer handles SMART app registration, data mapping, UAT coordination, and go-live monitoring. A sandbox environment with synthetic patient data is available for testing before any production data is accessed. Full integration documentation is available under NDA.</p>
</div>
<p style="margin-top:20px;font-size:13px;color:var(--slate);">
<strong>See also:</strong>
<a href="#doc-engineering-dataflow" style="color:var(--accent);text-decoration:none;" onclick="showDoc('doc-engineering-dataflow')">FHIR R4 Data Flow</a>, architecture diagram showing how these resources move through the pipeline, and
<a href="#doc-engineering-security" style="color:var(--accent);text-decoration:none;" onclick="showDoc('doc-engineering-security')">Security Architecture</a>, for PHI handling and compliance details.
</p>
</article>