Checklist recommendations
Return encounter-scoped partner checklist recommendations.
Launch
Implement the launch context endpoint ChartHero calls to verify and hydrate launched patient or appointment context.
v1.0This page is the field-level reference for the launch-context callback — the full request, every response field, and all denial cases. For how this callback fits the end-to-end launch, start with Launch Flow.
ChartHero calls launch context after it validates the launch URL and resolves the adapter installation.
POST {base_url}/v1/launch/context
This endpoint receives the opaque launch state from the encrypted link, verifies it in your system, and returns the patient-bearing context ChartHero should use.
Route label: Required for first launch.
ChartHero makes a single attempt at this callback — there is no automatic retry
for launch context. The timeouts are bounded per phase: up to 2 seconds to
establish the connection and up to 5 seconds to read your response. So resolve
launch_state and respond within a few seconds; a timeout fails the launch closed.
Size the endpoint for a synchronous lookup, not a long-running job. Returning retryable: true or 503 temporarily_unavailable from this callback is informational only — ChartHero does not retry launch context regardless.
Because there is no retry, launch_id is for your own deduplication, tracing, and
replay-safe logging — not for retry-safety. Returning the same context for a repeated
launch_id is good practice, but ChartHero will not call this endpoint twice for one
launch.
{
"actor": {
"actor_type": "user",
"actor_id": "11111111-1111-4111-8111-111111111111",
"email": "clinician@example.com",
"display_name": "Dr. Chris Smith",
"first_name": "Chris",
"last_name": "Smith",
"specialty": "Cardiology",
"governance_role": "member",
"functional_roles": ["provider"],
"active": true,
"external_ids": [
{
"source": "provider_acme_care_prod",
"type": "provider_id",
"value": "prov-456"
}
]
},
"launch_state": {
"appointment_id": "apt-789",
"correlation_id": "partner-click-123"
},
"launch_id": "01JZ123456789ABCDEFGHJKLM"
}
Rules:
launch_state is the JSON object from the encrypted launch payload. Treat it as adapter-owned state and resolve it using your system's own authorization and workflow rules.actor is the authenticated ChartHero user for this callback. ChartHero sends it whenever the launch is valid and an authenticated actor is resolved. In required provider-linking mode, a valid callback requires a durable mapped provider link; otherwise ChartHero rejects the launch before calling this endpoint.actor.actor_type, actor.actor_id, actor.display_name, actor.first_name, actor.last_name, actor.active, and actor.external_ids[] use the same field names and semantics as public External API actor resources where those concepts overlap. Adapter launch-context calls currently send only actor_type: "user".actor.actor_id is the ChartHero public user id. actor.email, name, specialty, governance role, and functional roles are ChartHero user and membership context for the launching organization.launch_id is the validated launch jti, included for deduplication, tracing, and replay-safe partner logging. ChartHero does not retry this callback, so it is not needed for retry-safety.launch_state. Return one validated launch subject after your adapter verifies and hydrates the launch: encounter with required encounter.patient for encounter or appointment launches, or top-level patient for patient-only launches.{source,type,value}. Actor and provider identifiers use the enabled provider identifier source; the currently published provider helper contract uses type: "provider_id".source is required even when the adapter has one default source. type is the identifier kind, such as patient_id, mrn, or appointment_id. The source and type you return must exactly match an enabled external identifier binding for that subject — unrecognized sources or types are rejected.The callback actor is not the raw top-level actor object from the encrypted launch URL. ChartHero first validates the encrypted actor evidence against the authenticated ChartHero user. If validation succeeds, this request sends enriched ChartHero actor context plus any mapped partner provider identifiers. In optional or disabled provider-linking modes, actor.external_ids is an empty array when no mapped provider identifiers are available. In required provider-linking mode, missing mapped provider identifiers produce launch_mapping_missing before this callback is sent.
Minimal top-level patient response for patient-only launch flows:
{
"patient": {
"external_ids": [
{
"source": "acme_care_prod",
"type": "patient_id",
"value": "pat-123"
}
]
}
}
Encounter response with embedded patient:
{
"encounter": {
"external_ids": [
{
"source": "acme_care_prod",
"type": "appointment_id",
"value": "apt-789"
}
],
"patient": {
"external_ids": [
{
"source": "acme_care_prod",
"type": "patient_id",
"value": "pat-123"
}
]
},
"start_at": "2026-06-01T14:00:00Z"
}
}
Response with optional demographics, encounter, and setup defaults:
{
"encounter": {
"external_ids": [
{
"source": "acme_care_prod",
"type": "appointment_id",
"value": "apt-789"
}
],
"patient": {
"external_ids": [
{
"source": "acme_care_prod",
"type": "patient_id",
"value": "pat-123"
}
],
"first_name": "Jane",
"middle_name": null,
"last_name": "Doe",
"suffix": null,
"dob": "1970-01-01",
"sex": "female"
},
"participants": [
{
"actor_type": "provider",
"role": "scheduled_provider",
"provider": {
"external_ids": [
{
"source": "provider_acme_care_prod",
"type": "provider_id",
"value": "prov-456"
}
],
"email": "clinician@example.com",
"display_name": "Dr. Chris Smith"
}
}
],
"start_at": "2026-06-01T14:00:00Z",
"end_at": "2026-06-01T14:30:00Z"
},
"setup_defaults": {
"mode": "phone_call",
"template_id": "00000000-0000-0000-0000-000000000013",
"phone_call": {
"to_e164": "+15551234567"
}
}
}
Rules:
encounter for an encounter or
appointment launch, or patient for a patient-only launch.patient and encounter are mutually exclusive at the top level. Do not return
both in the same success response.encounter when your adapter resolves encounter or appointment state,
and include the patient as required encounter.patient. Return top-level
patient when the launch is not tied to an encounter. ChartHero creates a new
local encounter for each newly minted patient-only launch; internal resolution
retries use the launch ID to avoid creating duplicates.encounter.start_at and encounter.end_at must be timezone-aware datetimes. When end_at is present, it must not be before start_at.setup_defaults is optional. Omit it or return null when there are no effective defaults.setup_defaults is an object, it must include at least one of mode, template_id, or phone_call. First-level null values are treated as omitted; include at least one non-null value when you want ChartHero to create setup.mode must be one of dictation, ambient, or phone_call. Only phone_call uses the phone_call object: if setup_defaults.phone_call is non-null and mode is supplied, mode must be phone_call. If mode is omitted or null while phone_call is present, ChartHero treats the defaults as phone-call defaults.setup_defaults.phone_call is non-null, phone_call.to_e164 is required.setup_defaults.template_id must be a ChartHero core template id provisioned as selectable for the launching user. ChartHero provides valid ids during adapter onboarding; omit template_id when no provisioned template should be selected.setup_defaults makes the launch-context response invalid; ChartHero does not ignore malformed defaults.Return the standard adapter error body with a stable error_code. ChartHero recognizes these four denial cases for this endpoint:
| Case | Status | error_code |
|---|---|---|
| Supplied actor cannot access the resolved patient or encounter | 403 |
permission_denied |
| Launch state cannot resolve to the expected patient | 404 |
patient_not_found |
| Launch state identifies an upstream appointment that cannot resolve | 404 |
appointment_not_found |
| Resolved patient and encounter do not belong together | 409 |
identifier_mismatch |
These four status + error_code pairs are the only ones ChartHero maps to a specific denial reason. Any other response — including a malformed request body you reject with 400 — is treated as a generic failure that fails the launch closed, not as a recognized denial. Use the four codes above when you want ChartHero to attribute the specific reason.
See Request IDs and errors for the full error body shape and request-correlation headers.
A minimal handler authenticates ChartHero's call, resolves your opaque launch_state, and answers in ChartHero's schema.
import express from 'express';
const app = express();
app.use(express.json());
// The full Authorization header value you issued to ChartHero,
// e.g. "Bearer abc123", "ApiKey abc123", or a bare token.
// Fail closed at startup: with no expected value, a request with no
// Authorization header would otherwise compare undefined === undefined.
const CHARTHERO_AUTHORIZATION = process.env.CHARTHERO_AUTHORIZATION;
if (!CHARTHERO_AUTHORIZATION) {
throw new Error('CHARTHERO_AUTHORIZATION must be set');
}
app.post('/v1/launch/context', (req, res) => {
// 1. Authenticate ChartHero's call with the authorization header value you issued.
if (req.get('authorization') !== CHARTHERO_AUTHORIZATION) {
return res
.status(401)
.json({ error_code: 'unauthorized', message: 'Invalid authorization', retryable: false });
}
// 2. Resolve your opaque launch_state against your own system.
const appointment = lookupAppointment(req.body.launch_state.appointment_id); // your code
if (!appointment) {
return res
.status(404)
.json({ error_code: 'appointment_not_found', message: 'Unknown appointment', retryable: false });
}
// 3. Return encounter with embedded patient in ChartHero's schema.
return res.json({
encounter: {
external_ids: [{ source: 'acme_care_prod', type: 'appointment_id', value: appointment.id }],
patient: {
external_ids: [{ source: 'acme_care_prod', type: 'patient_id', value: appointment.patientId }],
},
start_at: appointment.startAt,
},
});
});
app.listen(8080);
To self-test before activation, fire the exact shape ChartHero will POST at your own endpoint:
curl -sS -X POST https://ehr.example.com/integrations/charthero/v1/launch/context \
-H 'Authorization: Bearer <partner_issued_token>' \
-H 'X-ChartHero-Contract-Version: 1.0' \
-H 'Content-Type: application/json' \
-d '{
"actor": { "actor_type": "user", "actor_id": "11111111-1111-4111-8111-111111111111", "email": "clinician@example.com", "active": true, "external_ids": [] },
"launch_state": { "appointment_id": "apt-789", "correlation_id": "partner-click-123" },
"launch_id": "01JZ123456789ABCDEFGHJKLM"
}'
Return encounter-scoped partner checklist recommendations.
Return stable errors for not-found, mismatch, and denied cases.
Inspect the generated launch-context operation.