Skip to main content

HIPAA first-enablement runbook

This runbook stands alone. Every curl command and expected response is inline, so a compliance officer can print it, follow it end to end, tick each box, and hand the result to operations — without chasing the pointer links on the wider HIPAA onboarding walkthrough, which remains the page for context and explanation.

When this page applies

Run this sequence only when Protected Health Information (PHI) is entering your workspace — clinic messaging, patient notifications, care-coordination over voice or SMS. If PHI is never in scope, the default attestation is not_required, both gates stay open, and nothing below applies:
  • Enabling HIPAA mode returns 403 Forbidden while BAA status is not executed.
  • Any PHI send is rejected with 422 HIPAA_BAA_REQUIRED until HIPAA mode is enabled.
Run every call below against https://api.orbit.devotel.io/api/v1 with an X-API-Key header on an owner or admin key. Sandbox keys (dv_test_sk_…) return the same envelopes without touching live compliance state:
Success bodies are { "data": { … }, "meta": { "request_id", "timestamp" } }; errors are { "error": { code, message, status }, "meta": … }.

First-enablement sequence

1. Execute the BAA — owner

Distinguish who does what: steps 1a and 1b require an owner key (execute binds the legal agreement); 1c reads back with an owner-or-admin key. 1a — Attest that PHI is in scope. Move the organization from not_required to pending:
Expected: data.baa_status is pending. 1b — Execute with a type-the-name e-signature. typed_attestation must match signer_name exactly:
Expected: data.baa_status is executed, with baa_executed_at, expires_at (one-year term), and days_until_expiry populated. Dashboard equivalent: Compliance → BAA. 1c — Confirm the BAA is executed:
Expected: data.baa_status: "executed". Note days_until_expiry — an executed BAA expires after its one-year term and must be re-executed. Without executed status, the next step returns 403 Forbidden and PHI sends are rejected with 422 HIPAA_BAA_REQUIRED.

2. Enable HIPAA mode — owner

One call activates the controls: it turns on the per-organization HIPAA flag, arms the 365-day retention default, starts PHI access logging, and begins reporting BAA posture in the status object.
  • Dashboard: Settings → Compliance → HIPAA Mode Toggle.
  • API:
Expected response shape (key fields):
Enabling is a single call — it tightens posture, so no re-authentication challenge is required. Disabling is destructive and does require one. If BAA status is not executed, the call returns 403 Forbidden.

3. Restrict roles and API scopes to minimum necessary — administrator

HIPAA’s minimum necessary standard is tenant-owned. Provision honestly, with the controls that exist today:
  • Assign the billing role to finance-only staff — billing members are confined to billing, pricing, and usage and receive 403 on message-content endpoints.
  • Mint API keys with only the scopes the integration needs; grant messages:read only to services that genuinely read PHI-bearing content — every read lands in the PHI access log.
  • Known limitation: message-content reads are not restricted to a narrower set of roles beyond the billing confinement, and the message read endpoints do not require an operator-supplied reason code. Meet the standard by keeping workspace membership and API-key scopes tight. If your program requires per-role read restriction on message content, contact support@orbit.devotel.io before relying on it.

4. Designate PHI-adjacent audiences — owner / admin

Register the lists and segments whose members carry PHI so the campaign launch precheck gates them on the BAA. Without a designation, a PHI-bearing list launches like any other; with one, the precheck warns operators before a send goes out under an un-executed BAA. Endpoint semantics: PHI-adjacent audience designations.

5. Set the retention window — owner

data_retention_days accepts 30–3,650; enablement arms the 365-day default, so set this only when your policy window differs:
Expected: data.data_retention.days echoes your value. Dashboard equivalent: Settings → Compliance → HIPAA → Data Retention. A background job deletes expired message content, call recordings, and media attachments; audit logs and PHI access logs are retained independently — the deletion clock does not erase your evidence trail. If you record calls, pin the voice region to match your residency obligations at the same time — see Voice Data Residency & Retention.

Verify after every enablement

Run all four reads after the last write, in order — owner or admin key — and compare each against its expected output:
  1. The status object agrees with what you set.
    Expected: enabled is true, baa_status is executed, data_retention.days matches your window, disabled_at is null. Treat encryption_algorithm as reporting-only — platform-wide at-rest encryption (Google-managed AES-256 on Cloud SQL), not a per-organization application-layer cipher. Do not cite it to an auditor as evidence that message bodies are individually encrypted at the application layer.
  2. PHI access logging is recording. Exercise a message read in the dashboard or API, then page the log:
    Expected: your read appears as an entry (resource: "message:msg_…", reason: "read"). Pass the last entry’s id as ?cursor= to page forward while has_more is true.
  3. The designated-audience gate behaves as intended. Attempt a draft-campaign launch against one of the lists you designated in step 4. With the BAA executed it launches; run the same attempt against a scratch organization without an executed BAA to see the 422 HIPAA_BAA_REQUIRED rejection operators would hit. Details: PHI-adjacent audience designations.
  4. The compliance-health score moved.
    Expected: the HIPAA posture no longer reads as an open risk surface. Compare against a snapshot taken before step 1 — an open HIPAA posture scores as an unresolved risk until this sequence resolves it. Scoring semantics: Compliance health scores.

Checklist

Tick in order; the role on each line owns that line.
  • BAA executed and baa_status: "executed" confirmed — owner
  • HIPAA mode enabled; 403 on enable without BAA understood — owner
  • Membership trimmed to minimum necessary; messages:read scoped — administrator
  • PHI-adjacent audiences designated — owner / admin
  • Retention window set to your policy days — owner
  • GET /settings/hipaa verified; encryption_algorithm filed as reporting-only — compliance officer
  • PHI access log returning entries — compliance officer
  • Designated-audience gate exercised once — compliance officer
  • Compliance-health score compared before/after — compliance officer
  • Evidence binder generated via POST /api/v1/compliance/binder/generate and handed off through the 24-hour download link — compliance officer (step 9)

9. Generate the evidence binder — compliance officer

The verification above proves the controls work today; the binder is what you hand to an auditor or a buyer’s procurement team. Generate the HIPAA pack of the evidence binder — it assembles PHI access logging, BAA posture, and your configured retention into a signed, download-ready pack recorded in your audit log:
  • Dashboard: Settings → Compliance → Binder → generate HIPAA.
  • API:
Expected: 202 with data.jobId and data.status: "pending". Poll GET /api/v1/compliance/binder/{jobId} until the download is ready, then hand the link off — it expires after 24 hours; if it lapses, generate a fresh one. If the binder opens with a tamper-alert banner, treat it as a signal to investigate before handing it to anyone external.
HIPAA posture is tenant-owned — Orbit provides the controls and the ledger; the legal determination that PHI is in scope is yours. This page is not legal advice.