> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maxcare.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# E-Prescribing

> Renew a prescription as a draft and send it to a pharmacy, safely

The prescription endpoints let an app renew a patient's prescription and e-prescribe it to a pharmacy
through the practice's own EHR (ModMed EMA). They are **v4 only** and ModMed only; other EHRs answer
`400 capability_unsupported`.

> [!WARNING]
>
> **Sending is the prescriber's signature.** In the EHR, releasing an eRx signs it, it transmits over
> Surescripts, and it cannot be recalled through Max AI. Controlled substances (C-II to C-V) are always
> refused, at draft and at send.

## The flow

1. **Find the source.** `GET /v4/patients/{patientId}/prescriptions` lists the patient's prescriptions with
   their e-prescribing state (`read:prescriptions`).
2. **Pick the pharmacy.** `GET /v4/patients/{patientId}/pharmacies` or `GET /v4/pharmacies/search`
   (`read:pharmacies`).
3. **Create a draft.** `POST /v4/prescriptions` with `sourcePrescriptionId` and an explicit `prescriberId`
   (`write:prescriptions`). The draft is PENDING and reaches no pharmacy. It is read back and must match your
   request; if it does not, you get `502 ehr_write_mismatch` with its id. The platform cannot void drafts
   (`POST /v4/prescriptions/{id}/void` answers `400 capability_unsupported`), so staff discard it in EMA.
4. **Send it.** `POST /v4/prescriptions/{id}/send` (`write:prescription_sends`, its own consent group).
5. **Follow it.** `GET /v4/prescriptions/{id}` is always live; its `erx.status` moves `initiated` → `sent` →
   `pharmacy_verified`, or to `error`.

## Stored prescriptions: the org-wide feed

`GET /v4/prescriptions` (`read:prescriptions`) lists the organization's prescriptions across patients from
the platform's stored copy, without calling the EHR. Filter by `dispensableId` to find every patient with a
given drug, or by `patientId` and `status`.

* **Freshness.** The stored copy is refreshed in the background, within a daily per-practice budget. A
  prescription still moving (pending, or in e-prescribing) and written in the last 30 days is re-read about
  hourly; charts with an appointment in the last week or the next two weeks about daily; older charts once,
  during a one-year backfill. Every live read above also updates it. For one chart or one prescription right
  now, use the live endpoints.
* **Resolved at read.** `providerId` and `facilityId` are looked up when the feed is read, so one can appear
  later (once that provider or location is synced) without `updatedAt` moving.
* **Change feed.** `updatedAt` moves only when the stored prescription changes. Walk it with `updatedSince`
  set to the last row's `updatedAt` and `cursorId` set to its `id`, always on page 1, until a short page;
  dedupe on `id`. Offset paging inside a window is refused.
* **Removed prescriptions** carry `deletedFromEhrAt` once two consecutive complete EHR listings no longer
  return them, and appear only with `includeDeleted=true`.

## Who sends

A send is released under the **sending user's own EHR login**, never the practice's system login. Forward
the App Bridge token of the user who pressed Send as `sessionToken`, in the same request as the click. The
platform verifies it, records that user as `authorizedBy`, and finds their personal EHR connection from it.

If the user has no usable EHR login you get `409 no_sending_identity` with `data.reason`:

| `reason` | Meaning |
| - | - |
| `none` | The user has never connected an EHR login for this practice |
| `not_live` | Their connection exists but is not live (e.g. an authentication error) |
| `no_session` | Their connection has no active session |

Call `maxcare.pickProvider()` so the user connects in place, then press Send again with the **same**
`idempotencyKey` and a fresh token. Nothing was sent.

## Idempotency: never send twice

`idempotencyKey` is required, scoped to your app and the organization, and never expires.

* The same key for the same prescription and pharmacy **returns the original send record and never sends
  again** — even without a valid `sessionToken`, so you can learn a lost outcome after the token expired.
* The same key for a different prescription or pharmacy is `409 idempotency_key_reused`.
* While the first request is still in flight you get `503`: repeat the same request, never with a new key.
* A prescription is never sent twice, whatever the key: while it has a send in flight, `unknown` or
  `submitted`, another send answers `409 prescription_send_exists` with that send's id. Only the app and
  key that created a send can read its outcome. An `unknown` send that never settles blocks its
  prescription for good; have staff check the prescription in EMA before creating a new draft, because a
  second draft to the same pharmacy is not blocked.
* Every check that refuses before sending (not pending, controlled, validation, pharmacy capability,
  `no_sending_identity`, …) frees the key.

## Send status

| `status` | HTTP | What to do |
| - | - | - |
| `submitted` | 200 | The EHR acknowledged it. Follow `erx.status` on the prescription. |
| `refused` | 200 | The EHR answered with errors. Nothing was sent. The response does not say why; leave the draft to staff in EMA (the platform cannot void it). |
| `unknown` | **202** | The send was issued and no answer arrived. **It may have reached the pharmacy — do not resend.** Repeat the request with the same key to learn the outcome. |
| `not_sent` | 200 | This request did not send it. With `statusDetail: not_released` the prescription is still PENDING: only now may you send again, with a **new** key. With `released_elsewhere` the prescription was released anyway, not provably by this request: do **not** create another draft; show `erx` to staff. |

The platform never re-issues a send. An `unknown` send is settled by re-reading the prescription in the EHR
about every 10 minutes. `submitted` from that re-read means the EHR shows the prescription released; it does
not confirm the pharmacy, so check `erx.pharmacy.name` before telling the user where it went (`erx.pharmacy.ncpdpId` is usually null from EMA).
A send that never reached the EHR reads `not_sent` only once the prescription has been PENDING for more than
**60 minutes** after the request, so about 60–70 minutes; a request lost in flight answers `503` for the first
15–25 minutes. While a send is `unknown` or answers `503`, keep repeating the request with the **same**
`idempotencyKey`; never send again under a new key. Some `unknown` sends never settle, and none is re-checked
after 7 days: stop repeating then, and have staff check the prescription in EMA before creating a new draft.

## Limits

There is no daily limit on sends. Each send draws from [your app's share of the practice's EHR rate](https://docs.maxcare.ai/guides/rate-limits.md#ehr-rate-share), and over it the send
fails with `ehr_unavailable`; retry with backoff. Every send is a real prescription, so guard against loops in your app.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.