Register PHI-adjacent audiences
The PHI-adjacent audience registry is your organization’s list of contact lists and segments whose members carry PHI — for example, patients opted into treatment outreach. The HIPAA controls reference documents the two endpoints; this guide walks through running them in production: what to designate, how the write semantics work, what happens at campaign launch, and how to read the audit trail. The registry is tenant-owned. Devotel never designates audiences on your behalf and never scopes PHI for you — the designations are your attestation, they are BAA-gated controls you operate, and they only take effect once HIPAA is in scope for your organization. If you have not already executed the BAA and enabled HIPAA mode, run the HIPAA onboarding sequence first.1. When to mark an audience PHI-adjacent
Designation follows provenance: mark the audiences whose source data contains PHI, regardless of what any individual campaign sends to them. An audience is PHI-adjacent because of where its members came from — a patient appointment-reminder import, a treatment-outreach opt-in list — not because of the copy you happen to write this week. That is why the designation lives on the audience itself rather than on a campaign: whichever campaign picks the audience up, the designation travels with it. Mark an audience PHI-adjacent when:- Its members were imported from a system that holds PHI (an EHR export, a patient portal opt-in sync).
- The list or segment is filtered or assembled on PHI-bearing criteria (diagnosis-adjacent tags, treatment cohorts).
- Your compliance officer’s data map records the audience as PHI in scope.
owner or admin role — the same gate the BAA endpoints use. A developer or viewer receives 403. Keep the designation decision with your HIPAA compliance officer; the platform records who changed the registry on every write (see Audit trail).
2. Choosing list vs segment ids
The registry holds audience ids — each entry is either a contact-list id or a segment id, passed as a plain string. The campaign launch precheck only resolveslist- and segment-type audiences against the registry; audiences assembled per contact (all contacts, CSV upload, manual entry) are evaluated recipient-by-recipient at send time instead, so they have no registry id to designate.
To rederive the id for a designation:
id field of the list or segment you are designating. Ids are 1–128 characters after trimming; anything longer or empty is rejected with 422 on write. The registry holds at most 500 ids per organization — a PUT carrying more returns 422.
Designate the source id, not a downstream copy. If a PHI-bearing list feeds a derived segment, decide whether the derived segment also contains PHI and designate it explicitly — the precheck checks the id the campaign actually references, nothing else.
3. The atomic PUT swap
The registry has one write operation: a full-replacementPUT. There is no PATCH, no per-id DELETE — every write replaces the entire designated set in a single atomic statement, so a concurrent GET never sees a partially applied update.
GET the current registry, add or remove your id in the result, and PUT the whole set back. Never build the body from local state alone — you would silently drop designations another operator added.
To lift one designation, PUT the registry without that id. To re-designate, PUT it with the id added back. Individual ids that survive a swap are unchanged; only membership in the set matters.
4. How the launch precheck uses the registry
Two gates protect PHI at different points, and the registry feeds the first:- Launch precheck (campaign-level, hard gate). Before a campaign leaves draft/scheduled, the precheck resolves its audience id against the registry. A designated id plus a BAA that is not
executedand in-term refuses the launch with422 HIPAA_BAA_REQUIRED— before a single recipient is enrolled. If the compliance state cannot be read, the precheck fails closed with500 HIPAA_BAA_GATE_DB_FAILrather than silently admitting the audience. - Per-recipient send gate (message-time, unchanged). The existing send gate still applies to every individual send and does not consult the registry — legacy one-off sends are governed by it alone.
details.reason tells you exactly which BAA state de-blocks it:
There are two ways to de-block, and they are compliance decisions, not platform decisions:
- Resolve the BAA — execute or re-execute it so the gate passes. This is the right path when the audience genuinely carries PHI.
- Remove the designation —
PUTthe registry without the audience id. This is the right path only when the audience was designated in error. Lifting a designation to route around the gate is visible in your own audit log.
5. Audit trail
Two record classes land in your organization’s audit log:hipaa.phi_audiences.set— one row perPUT, recording the acting user, the organization, and the full post-write id set. This is your versioning story: the registry has no separate revision resource — the sequence of audit rows is the version history. To reconstruct what was designated at a point in time, walk thesetrows back; to revert,PUTa prior row’s id set.HIPAA_BAA_REQUIREDlaunch refusals — each blocked launch is logged with the refusing reason and the audience under evaluation. These rows double as your incident queue: a refusal means either compliance work is pending (BAA not executed) or a designation and a campaign disagree.
- Read the refusal’s
details.reasonanddetails.audience.id. - Check
GET /api/v1/compliance/baa/— if the BAA ispending/expired/not executed, resolve it through the BAA flow. - If the BAA is healthy, check whether the audience should be designated at all:
GET /api/v1/compliance/hipaa/phi-audiencesand compare against your data map. Lift an erroneous designation with a swap (PUTwithout the id). - Record the outcome in your own incident register — the audit rows above are the evidence you cite.
6. Troubleshooting concurrent-overwrite conflicts
The registryPUT itself never returns 409 — the single-statement atomic swap means a write always commits, and the last writer wins. The conflict risk is lost updates between operators, not rejected writes:
- Operator A and operator B both
GETthe registry. - A adds
list_aaaandPUTs. B — working from the pre-A snapshot — addslist_bbbandPUTs. - B’s swap silently drops
list_aaa.
- Read immediately before writing. Keep the read-modify-write window short; do not carry a fetched registry across an editing session — re-
GETwhen you are ready toPUT. - Verify after writing.
GETonce more and confirm your id is present and no unrelated designation was lost. If something disappeared, the audit log’shipaa.phi_audiences.setrows show whose write overwrote it and what set to restore. - Serialize registry edits organizationally. Because designation is a compliance attestation, route edits through one role (the compliance officer) rather than spreading them across operators — a procedural fix that removes the race entirely.
422 instead of success, the cause is validation, not conflict: more than 500 ids, an empty id after trimming, or an id over 128 characters. Trim and retry with the full set.
See also
- HIPAA compliance controls — the full control reference the registry feeds
- BAA — Business Associate Agreement — the lifecycle the launch precheck enforces
- HIPAA onboarding: from BAA to audit-ready — the sequence that brings a healthcare workspace to audit-ready before you designate audiences
- Send gates — the per-recipient gate that complements the launch precheck