API

Patients API

Read and write patient records over authenticated, permissioned requests — the endpoints you hydrate PHI from when you need it.

Patient records are the one place PHI lives, so every patient endpoint is an authenticated, permissioned read or write — never something your webhook payloads carry. Webhooks and events move ids and status only; when you need a name, an address, or a date of birth, you GET it here, on the neolife side of the PHI boundary.

The hydrate-over-GET model#

Fulfillment status flows to you PHI-free. A patient's identifying detail does not travel with it — you fetch it, on demand, over an authenticated request scoped to your tenant. That keeps your callback endpoints, your event log, and your analytics out of PHI scope, and confines patient data to the specific requests that actually need it.

Two consequences worth designing around:

  • Reads require the patients.view scope. A key without it gets 403. Writes require patients.create / patients.edit. See Authentication for how scopes attach to a key.
  • Everything is tenant-scoped. A patient id that isn't on your tenant returns 404, not 403 — there is no cross-tenant read.

List patients#

curl https://api.neolife.health/v1/patients \
  -H "Authorization: Bearer $NEOLIFE_API_KEY"

Returns your tenant's patients, ordered by last name then first name. Each element is a full patient object (below).

Get a patient#

curl https://api.neolife.health/v1/patients/pat_123 \
  -H "Authorization: Bearer $NEOLIFE_API_KEY"
{
  "id": "pat_123",
  "firstName": "Jordan",
  "middleName": null,
  "lastName": "Rivera",
  "dob": "1988-04-12",
  "gender": "f",
  "species": "human",
  "address": {
    "address1": "500 Cedar St",
    "address2": null,
    "city": "Austin",
    "state": "TX",
    "zip": "78701",
    "country": "US"
  },
  "phoneMobile": "+15125550142",
  "email": "[email protected]",
  "externalRefs": { "shopify": "gid://shopify/Customer/900" },
  "createdAt": "2026-06-01T15:22:04.000Z",
  "updatedAt": "2026-06-01T15:22:04.000Z"
}

externalRefs is a free-form map you can use to carry your own identifiers (for example a Shopify customer id) so you never have to store a neolife↔patient mapping yourself.

Create a patient#

Provide identity, an address, and at least one contact detail. State is normalized to a two-letter code and country defaults to US.

curl -X POST https://api.neolife.health/v1/patients \
  -H "Authorization: Bearer $NEOLIFE_API_KEY" \
  -H "Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jordan",
    "lastName": "Rivera",
    "dob": "1988-04-12",
    "gender": "f",
    "address1": "500 Cedar St",
    "city": "Austin",
    "state": "TX",
    "zip": "78701",
    "email": "[email protected]",
    "phoneMobile": "+15125550142"
  }'
Field Required Notes
firstName, lastName yes Non-empty.
dob yes YYYY-MM-DD.
address1, city, state, zip yes state is upper-cased to two letters.
middleName, gender, address2, country no country defaults to US.
email, phoneMobile, phoneHome no At least one contact method is recommended for fulfillment.

Creation is a mutation, so it takes an Idempotency-Key — a retried create replays the first result instead of inserting a duplicate patient.

Update a patient#

PATCH the same shape to change a record. Fields you send are written; the id, tenant, and timestamps are server-managed.

curl -X PATCH https://api.neolife.health/v1/patients/pat_123 \
  -H "Authorization: Bearer $NEOLIFE_API_KEY" \
  -H "Idempotency-Key: b1f2c3d4-5678-4abc-9def-0123456789ab" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Jordan",
    "lastName": "Rivera",
    "dob": "1988-04-12",
    "address1": "12 Maple Ave",
    "city": "Austin",
    "state": "TX",
    "zip": "78702"
  }'

Updating a patient id that isn't on your tenant returns 404. Like every mutation, it accepts an Idempotency-Key.

Related detail#

When you're rendering a patient in context — the orders, subscriptions, and intake attached to them — use the relational detail read:

curl https://api.neolife.health/v1/detail/patient/pat_123 \
  -H "Authorization: Bearer $NEOLIFE_API_KEY"

It returns the patient plus their linked records, gated by the same patients.view scope.

Related#

  • The PHI boundary — why patient detail lives behind a GET and never rides on events.
  • API reference — base URL, versioning, errors, and rate limits.