NewInstance Documentation
View as Markdown

EHR

EHR is the NewInstance electronic health records product. This section covers the parts that are stable in this phase: reference code lookups, the outbound webhook subscriptions that tell your systems when something happens, and the event log those webhooks are built on.

How events and webhooks fit togetherlink

Every meaningful change inside EHR (a program created, a location updated, a break-the-glass session started, and so on) is appended to a per-organization event log with an increasing sequence number. A webhook subscription tells the platform which of those event types you want pushed to a URL you control; the Send a test event request lets you verify a receiver end to end without waiting for a real change.

If you would rather pull than have events pushed to you, poll List events with sinceSeq set to the nextSeq you got back last time.

Webhook URL and secret ruleslink

  • HTTPS only. Loopback, private, link-local, carrier-grade NAT and unspecified addresses are rejected, both as literal IPs and after resolving the hostname.
  • The signing secret (whsec_...) is generated on creation and returned in the response body exactly once. After that, only a masked preview (whsec_•••• plus the last four characters) is ever shown.
  • Set includePhi: true only when delivered payloads may contain protected health information, and pair it with a phiAcknowledgmentText of at least 20 characters confirming you understand that.

Schedulinglink

List appointments and Create an appointment need the scheduling scope, and Look up a client by MRN needs clients-read. Instants are always ISO 8601 in UTC, and every appointment carries the IANA zone it was booked in, so a caller in another zone can render the local wall time without guessing. A key holding scheduling alone sees the slots but no client identifiers; add clients-read to see which client each appointment belongs to.

Appointments protected by an additional consent requirement are not returned to an API key at all: they are absent from the page, from the total and from every filter, and a lookup of such a client answers exactly as an unknown record does. They still hold their slot, so a booking over one comes back as a clash without naming what is in the way.

The inbound SMS webhook is the one EHR endpoint that takes no API key: it is authenticated by your provider's request signature instead.

Permission scopes for EHR API keyslink

Scope codeDescription
full-accessAll EHR permissions
webhooksCreate, update, delete and test webhook subscriptions, and read the event log
schedulingList and create appointments
clients-readLook up a client by medical record number, and see client identifiers on appointments

Reference code lookups only need the key to carry any ehr product scope, full access or a specific group such as webhooks, not a dedicated scope of their own.

List reference codes

GET/api/v1/ehr/reference-codes

Searches ICD-10-CM, HCPCS, place of service, modifier, LOINC, RxNorm and taxonomy reference codes. Matches code prefix or display text substring, case insensitive, sorted by code. Any ehr product scope on the key is enough, no specific group is required.

Authorization

x-api-keyAPI key · headerrequired

Parameters

systemquery · stringdefault:

Optional. Code system: ICD10CM, HCPCS, POS, MODIFIER, LOINC, RXNORM or TAXONOMY. Omit it to search every system.

qquery · stringdefault:

Optional. Search text, 1 to 80 characters. Matches a code prefix or a display text substring, case insensitive.

limitquery · stringdefault:

Optional. Number of codes to return, 1 to 100. Defaults to 25.

Responses

200Reference codes
401Invalid or missing API key
403Missing permission scope
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/reference-codes?system=ICD10CM&q=chol&limit=25' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "items": [
    {
      "system": "ICD10CM",
      "code": "A00",
      "display": "Cholera"
    }
  ]
}

List webhook subscriptions

GET/api/v1/ehr/webhooks

Returns this organization's webhook subscriptions, newest first. Each item carries a masked secret preview, never the real secret.

Authorization

x-api-keyAPI key · headerrequired

Responses

200Webhook subscriptions
401Invalid or missing API key
403Missing permission scope
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/webhooks' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "items": [
    {
      "id": "66f1a2b3c4d5e6f7a8b9c0d1",
      "name": "Order sync",
      "url": "https://example.com/hooks/ehr",
      "events": [
        "ehr.program.created",
        "ehr.program.updated"
      ],
      "status": "active",
      "includePhi": false,
      "failureCount": 0,
      "secretMasked": "whsec_••••ab12",
      "createdAt": "2026-09-01T12:00:00.000Z",
      "updatedAt": "2026-09-01T12:00:00.000Z"
    }
  ]
}

Create a webhook subscription

POST/api/v1/ehr/webhooks

Creates a webhook subscription. The response includes the signing secret in clear text. Copy it now, it is never shown again. A key issued by a member whose role does not reach every client is refused, because a webhook is sent events about every client. The member who issued the key becomes the member the webhook is delivered under, and nothing more is sent to it once that member no longer reaches every client or leaves the organization, until a member who does saves it again.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "name": "Order sync",
  "url": "https://example.com/hooks/ehr",
  "events": [
    "ehr.program.created",
    "ehr.program.updated"
  ],
  "includePhi": false
}

Responses

201Webhook subscription created
400Validation error
401Invalid or missing API key
403Missing permission scope
curl -X POST 'https://api.newinstance.cloud/api/v1/ehr/webhooks' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "name": "Order sync",
  "url": "https://example.com/hooks/ehr",
  "events": [
    "ehr.program.created",
    "ehr.program.updated"
  ],
  "includePhi": false
}'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0d1",
  "name": "Order sync",
  "url": "https://example.com/hooks/ehr",
  "events": [
    "ehr.program.created",
    "ehr.program.updated"
  ],
  "status": "active",
  "includePhi": false,
  "failureCount": 0,
  "secretMasked": "whsec_••••ab12",
  "secret": "whsec_5f2b9c1a7d3e4f6089ab12",
  "createdAt": "2026-09-01T12:00:00.000Z",
  "updatedAt": "2026-09-01T12:00:00.000Z"
}

Send a test event

POST/api/v1/ehr/webhooks/{ehrWebhookId}/test

Queues an ehr.webhook.test event and a pending delivery for this subscription, so you can confirm your receiver handles a delivery correctly. ehrWebhookId in the path is the id returned by Create a webhook subscription, which Postman stores after that request runs.

Authorization

x-api-keyAPI key · headerrequired

Parameters

ehrWebhookIdpath · stringrequireddefault:

Responses

202Test event queued
401Invalid or missing API key
403Missing permission scope
404Webhook subscription not found
curl -X POST 'https://api.newinstance.cloud/api/v1/ehr/webhooks/{ehrWebhookId}/test' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "eventId": "66f1a2b3c4d5e6f7a8b9c0d2",
  "deliveryId": "66f1a2b3c4d5e6f7a8b9c0d3"
}

List events

GET/api/v1/ehr/events

Returns this organization's event log in sequence order. Pass the previous nextSeq back as sinceSeq to continue from where you left off. An event that names a client protected by 42 CFR Part 2 or a client with no record, or that is about an appointment marked protected or one that cannot be found, is left out, and nextSeq still moves past it. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator.

Authorization

x-api-keyAPI key · headerrequired

Parameters

sinceSeqquery · stringdefault:

Optional. Return only events with a sequence number greater than this value. Pass the previous nextSeq to continue.

limitquery · stringdefault:

Optional. Number of events to return, 1 to 500. Defaults to 100.

Responses

200Event log page
401Invalid or missing API key
403Missing permission scope
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/events?sinceSeq=0&limit=100' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "items": [
    {
      "id": "66f1a2b3c4d5e6f7a8b9c0d2",
      "seq": 1,
      "type": "ehr.webhook.test",
      "occurredAt": "2026-09-01T12:00:00.000Z",
      "aggregate": {
        "type": "webhook_subscription",
        "id": "66f1a2b3c4d5e6f7a8b9c0d1"
      },
      "status": "pending"
    }
  ],
  "nextSeq": 1
}

List appointments

GET/api/v1/ehr/appointments

Returns appointments that overlap the requested range, oldest first. Every instant is ISO 8601 in UTC and each appointment carries the IANA zone it was booked in, so a client in another zone can render the local wall time correctly. Needs the scheduling scope. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator.

Authorization

x-api-keyAPI key · headerrequired

Parameters

fromquery · stringdefault:

Required. Range start, an ISO 8601 instant.

toquery · stringdefault:

Required. Range end, an ISO 8601 instant.

pagequery · stringdefault:

Optional. Page number, from 1. Defaults to 1.

limitquery · stringdefault:

Optional. Appointments per page, 1 to 100. Defaults to 25.

Responses

200Appointment page
400Validation error
401Invalid or missing API key
403Missing permission scope
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/appointments?from=2026-10-25T00%3A00%3A00.000Z&to=2026-10-26T00%3A00%3A00.000Z&page=1&limit=25' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "items": [
    {
      "id": "66f1a2b3c4d5e6f7a8b9c0e1",
      "seriesId": null,
      "typeId": "66f1a2b3c4d5e6f7a8b9c0a1",
      "status": "scheduled",
      "clientIds": [
        "66f1a2b3c4d5e6f7a8b9c0b1"
      ],
      "primaryStaffId": "66f1a2b3c4d5e6f7a8b9c0c1",
      "staffIds": [
        "66f1a2b3c4d5e6f7a8b9c0c1"
      ],
      "roomLocationId": "66f1a2b3c4d5e6f7a8b9c0d4",
      "locationId": null,
      "programId": null,
      "serviceCodeId": null,
      "start": "2026-10-25T11:00:00.000Z",
      "end": "2026-10-25T12:00:00.000Z",
      "timezone": "America/New_York",
      "checkInAt": null,
      "checkOutAt": null,
      "encounterId": null
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 25
}

Create an appointment

POST/api/v1/ehr/appointments

Books an appointment. Send start and end in UTC and the zone the time was chosen in. A clash returns 409 naming the resource already booked, unless the organization double-booking policy allows it or you send allowConflicts. A client, staff member, room, program or appointment type that cannot take the booking is refused with 4xx and a message saying what to change; a 503 means the service could not confirm its own indexes and the request is worth retrying. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "typeId": "66f1a2b3c4d5e6f7a8b9c0a1",
  "clientIds": [
    "66f1a2b3c4d5e6f7a8b9c0b1"
  ],
  "primaryStaffId": "66f1a2b3c4d5e6f7a8b9c0c1",
  "start": "2026-10-26T13:00:00.000Z",
  "end": "2026-10-26T14:00:00.000Z",
  "timezone": "America/New_York"
}

Responses

201Appointment booked
400Validation error
401Invalid or missing API key
403Missing permission scope
409Booking clash
curl -X POST 'https://api.newinstance.cloud/api/v1/ehr/appointments' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "typeId": "66f1a2b3c4d5e6f7a8b9c0a1",
  "clientIds": [
    "66f1a2b3c4d5e6f7a8b9c0b1"
  ],
  "primaryStaffId": "66f1a2b3c4d5e6f7a8b9c0c1",
  "start": "2026-10-26T13:00:00.000Z",
  "end": "2026-10-26T14:00:00.000Z",
  "timezone": "America/New_York"
}'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0e2",
  "seriesId": null,
  "typeId": "66f1a2b3c4d5e6f7a8b9c0a1",
  "status": "scheduled",
  "clientIds": [
    "66f1a2b3c4d5e6f7a8b9c0b1"
  ],
  "primaryStaffId": "66f1a2b3c4d5e6f7a8b9c0c1",
  "staffIds": [
    "66f1a2b3c4d5e6f7a8b9c0c1"
  ],
  "roomLocationId": null,
  "locationId": null,
  "programId": null,
  "serviceCodeId": null,
  "start": "2026-10-26T13:00:00.000Z",
  "end": "2026-10-26T14:00:00.000Z",
  "timezone": "America/New_York",
  "checkInAt": null,
  "checkOutAt": null,
  "encounterId": null
}

List claims

GET/api/v1/ehr/billing/claims

Lists claims newest first with what each one is worth and whether the clearinghouse answered. Needs the billing-read group on the key and a creator who holds the permission to view billing amounts. Claims for a client protected by 42 CFR Part 2 are in neither the rows nor the total. Payer reason codes are on the single claim read, never here. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator.

Authorization

x-api-keyAPI key · headerrequired

Parameters

pagequery · stringdefault:

Optional. Page number, from 1. Defaults to 1.

limitquery · stringdefault:

Optional. Claims per page, 1 to 100. Defaults to 25.

Responses

200Claims
401Invalid or missing API key
403Missing permission scope
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/billing/claims?page=1&limit=25' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "items": [
    {
      "id": "66f1a2b3c4d5e6f7a8b9c0e1",
      "payerId": "66f1a2b3c4d5e6f7a8b9c0e2",
      "controlNumber": "10001",
      "status": "queued",
      "chargeCount": 1,
      "totalAmountMinor": 12500,
      "currency": "USD",
      "transmission": {
        "status": "acknowledged",
        "sentAt": "2026-09-02T11:00:00.000Z",
        "acknowledgedAt": "2026-09-03T11:00:00.000Z"
      },
      "submittedAt": "2026-09-02T10:00:00.000Z"
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 25
}

Read one claim

GET/api/v1/ehr/billing/claims/{ehrClaimId}

Returns one claim with its service lines, the state of its transmission, and the payer reason and remark codes where the payer denied it, with deniedAt, the date the payer gave for the denial, as that calendar date in the form YYYY-MM-DD, such as 2026-09-11, with no time of day. The claim file itself, which carries the member number, the name, the date of birth and the diagnoses, is never returned. A claim for a Part 2 client answers 404. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator. ehrClaimId in the path is a claim id from List claims, which Postman stores after that request runs.

Authorization

x-api-keyAPI key · headerrequired

Parameters

ehrClaimIdpath · stringrequireddefault:

Responses

200Claim
401Invalid or missing API key
403Missing permission scope
404Claim not found
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/billing/claims/{ehrClaimId}' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0e1",
  "payerId": "66f1a2b3c4d5e6f7a8b9c0e2",
  "controlNumber": "10001",
  "payerClaimControlNumber": null,
  "status": "queued",
  "format": "837P",
  "frequencyCode": "1",
  "totalAmountMinor": 12500,
  "currency": "USD",
  "transmission": {
    "status": "acknowledged",
    "sentAt": "2026-09-02T11:00:00.000Z",
    "acknowledgedAt": "2026-09-03T11:00:00.000Z"
  },
  "lines": [
    {
      "lineNo": 1,
      "chargeId": "66f1a2b3c4d5e6f7a8b9c0e3",
      "serviceCode": "90834",
      "modifiers": [],
      "units": 1,
      "amountMinor": 12500,
      "dateOfService": "2026-09-01"
    }
  ],
  "denial": {
    "status": "open",
    "reasons": [
      "CO-97"
    ],
    "remarkCodes": [
      "N19"
    ],
    "deniedMinor": 2500,
    "allowedMinor": 10000,
    "deniedAt": "2026-09-11"
  },
  "submittedAt": "2026-09-02T10:00:00.000Z",
  "updatedAt": "2026-09-02T10:00:00.000Z"
}

Read one charge and its ledger

GET/api/v1/ehr/billing/charges/{ehrChargeId}

Returns one charge and every ledger entry posted against it, with what each party still owes on it: payerOwedMinor for the insurer, clientOwedMinor for the client, and transferredToClientMinor for what has moved from one to the other. There is no single party blind balance, because once responsibility has moved between the two a single figure names neither of them. The entry count is there because nothing owed is also what a charge nothing ever posted to looks like. Diagnoses are not returned. The figures are worked out from the entries returned beside them when the charge is read, so the two always agree. A charge for a Part 2 client answers 404. A key issued by a member whose role does not reach every client, such as a clinician who reads a caseload, is refused before a record is read; issue the key from the front desk or an administrator. ehrChargeId in the path is a chargeId from the lines of Read one claim.

Authorization

x-api-keyAPI key · headerrequired

Parameters

ehrChargeIdpath · stringrequireddefault:

Responses

200Charge and ledger
401Invalid or missing API key
403Missing permission scope
404Charge not found
curl -X GET 'https://api.newinstance.cloud/api/v1/ehr/billing/charges/{ehrChargeId}' \
  -H 'x-api-key: YOUR_API_KEY'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0e3",
  "serviceCode": "90834",
  "modifiers": [],
  "units": 1,
  "dateOfService": "2026-09-01",
  "amountMinor": 12500,
  "currency": "USD",
  "status": "ready",
  "payerOwedMinor": 0,
  "clientOwedMinor": 2500,
  "transferredToClientMinor": 2500,
  "entryCount": 4,
  "entries": [
    {
      "kind": "charge",
      "sourceType": "charge",
      "amountMinor": 12500,
      "currency": "USD",
      "payerId": "66f1a2b3c4d5e6f7a8b9c0e2",
      "postedAt": "2026-09-01T12:00:00.000Z"
    },
    {
      "kind": "payer_payment",
      "sourceType": "remittance_line",
      "amountMinor": 8000,
      "currency": "USD",
      "payerId": "66f1a2b3c4d5e6f7a8b9c0e2",
      "postedAt": "2026-09-10T12:00:00.000Z"
    },
    {
      "kind": "contractual_adjustment",
      "sourceType": "remittance_line",
      "amountMinor": 2000,
      "currency": "USD",
      "payerId": "66f1a2b3c4d5e6f7a8b9c0e2",
      "postedAt": "2026-09-10T12:00:00.000Z"
    },
    {
      "kind": "transfer_to_client",
      "sourceType": "remittance_line",
      "amountMinor": 2500,
      "currency": "USD",
      "payerId": null,
      "postedAt": "2026-09-10T12:00:00.000Z"
    }
  ],
  "capturedAt": "2026-09-01T12:00:00.000Z"
}

Look up a client by MRN

POST/api/v1/ehr/clients/lookup

Returns the demographic summary for one client by medical record number. The number is sent in the request body, never in the path or the query string, because those reach an access log. Needs the clients-read scope, and a key issued by a member whose role reaches every client, such as the front desk or an administrator; any other key is refused before a record is read. Every call is written to the access log with the API key as the actor.

Authorization

x-api-keyAPI key · headerrequired

Request body

application/json
{
  "mrn": ""
}

Responses

200Client summary
401Invalid or missing API key
403Missing permission scope
404No such client
curl -X POST 'https://api.newinstance.cloud/api/v1/ehr/clients/lookup' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "mrn": ""
}'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0b1",
  "mrn": "MRN-1042",
  "firstName": "Ada",
  "lastName": "Okafor",
  "dob": "1984-03-09",
  "status": "active",
  "part2": false,
  "primaryProgramId": "66f1a2b3c4d5e6f7a8b9c0f4",
  "primaryClinicianStaffId": "66f1a2b3c4d5e6f7a8b9c0c1"
}

Inbound SMS webhook

POST/api/v1/ehr/sms/inbound

Receives the message replies your SMS provider posts. The request carries the provider signature, so no API key is used. A signature that does not verify answers 401 with an empty body. A reply of C, CONFIRM, YES or Y confirms the next appointment within seven days, except from a number more than one client shares, where it confirms nothing and the reply is recorded as ignored. STOP, STOPALL, UNSUBSCRIBE, CANCEL, END or QUIT removes text message consent for that number immediately, so a reply of CANCEL opts the number out of text messages and cancels no appointment.

Headers

x-twilio-signature

Request body

application/x-www-form-urlencoded
{
  "To": "+15550100000",
  "From": "+15550101234",
  "Body": "C",
  "MessageSid": "SM00000000000000000000000000000001"
}

Responses

204Reply handled
400Validation error
401Signature did not verify, empty body
404No organization owns that number
curl -X POST 'https://api.newinstance.cloud/api/v1/ehr/sms/inbound' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-raw '{
  "To": "+15550100000",
  "From": "+15550101234",
  "Body": "C",
  "MessageSid": "SM00000000000000000000000000000001"
}'
Response
null

Delete a webhook subscription

DELETE/api/v1/ehr/webhooks/{ehrWebhookId}

Soft deletes a webhook subscription. It stops receiving deliveries immediately and drops out of the list. ehrWebhookId in the path is the id returned by Create a webhook subscription. A key issued by a member whose role does not reach every client is refused, because a webhook is sent events about every client.

Authorization

x-api-keyAPI key · headerrequired

Parameters

ehrWebhookIdpath · stringrequireddefault:

Responses

204Subscription deleted
401Invalid or missing API key
403Missing permission scope
404Webhook subscription not found
curl -X DELETE 'https://api.newinstance.cloud/api/v1/ehr/webhooks/{ehrWebhookId}' \
  -H 'x-api-key: YOUR_API_KEY'
Response
null

Update a webhook subscription

PATCH/api/v1/ehr/webhooks/{ehrWebhookId}

Updates one or more fields on a webhook subscription: name, url, events, or status. At least one field is required. ehrWebhookId in the path is the id returned by Create a webhook subscription. A key issued by a member whose role does not reach every client is refused, because a webhook is sent events about every client. The member who issued the key becomes the member the webhook is delivered under, and nothing more is sent to it once that member no longer reaches every client or leaves the organization, until a member who does saves it again.

Authorization

x-api-keyAPI key · headerrequired

Parameters

ehrWebhookIdpath · stringrequireddefault:

Request body

application/json
{
  "status": "paused"
}

Responses

200Webhook subscription updated
400Validation error
401Invalid or missing API key
403Missing permission scope
404Webhook subscription not found
curl -X PATCH 'https://api.newinstance.cloud/api/v1/ehr/webhooks/{ehrWebhookId}' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "status": "paused"
}'
Response
{
  "id": "66f1a2b3c4d5e6f7a8b9c0d1",
  "name": "Order sync",
  "url": "https://example.com/hooks/ehr",
  "events": [
    "ehr.program.created",
    "ehr.program.updated"
  ],
  "status": "paused",
  "includePhi": false,
  "failureCount": 0,
  "secretMasked": "whsec_••••ab12",
  "createdAt": "2026-09-01T12:00:00.000Z",
  "updatedAt": "2026-09-01T12:05:00.000Z"
}