Skip to main content
GET /patients and GET /patients/{id} can return a nested address object, synced from the EHR chart. It is opt-in twice over:
  1. Ask for it with ?include=address.
  2. Hold the read:patient_pii scope — the request 403s without it.
Both gates are deliberate. A street address and ZIP are HIPAA Safe Harbor identifiers, and an additive response field lands on every API version at once — so returning the address unconditionally would mean every app already holding read:patients, including v1 and v2 callers, silently began receiving it on a deploy it never opted into and the organization never re-granted. For the same reason it is returned only by the patients endpoints. The nested patient object on /appointments, /bills and /claims does not carry an address, however you scope the request.

Null semantics

address is an OBJECT whenever you pass ?include=address — it is never null. A patient the chart holds no address for comes back with every component null ({"line1": null, … }), so test the components, not the object. Individual components can still be null on a present address. The address is returned as soon as any component is known — a partial address is a real fact about the chart, and hiding it would misreport the practice’s record as empty when it is merely incomplete.
address is what the practice has on file, not a validated deliverable address. Max AI does not run CASS or NCOA. Validate before mailing, and expect a meaningful share of charts to be stale or partial.

Normalization

Two fields are normalized at sync time; the rest pass through as the EHR stored them:
  • state — a two-letter US/CA state or province code.
  • country — an ISO 3166-1 alpha-2 code.

Availability

Addresses are populated opportunistically by the EHR scrapers, so coverage depends on what each connected EHR exposes and on how completely the practice fills in its charts. Expect coverage to be high but not universal; a patient whose address components are ALL null is one the chart has no address for, and the print channel should skip them rather than guess. Test the components — address itself is present-but-empty in that case, so an address === null check never fires.
Field naming: this read shape uses zipcode, matching FacilityResponse.address — a consumer that already renders a facility address renders this one with no new mapping.