Prescriptions
A prescription represents a medication a clinician has prescribed or dispensed for a patient. It is tied to the patient receiving the medication, the doctor prescribing it, and (unless it is a written script) the product in the clinic catalog being dispensed. Refills are tracked as related refill records with their own endpoint, so the original prescription stays the source of truth for the script.
Use prescriptions to surface a patient’s active medications, drive pharmacy fulfilment, or feed compliance dashboards.
Schema
Section titled “Schema”Authoritative schemas live in the live Swagger UI. The fields below are a representative subset for orientation.
| Field | Type | Notes |
|---|---|---|
id | UUID | Server-assigned identifier. |
patientId | UUID | Patient the prescription is written for. |
prescribingDoctorId | UUID | User who prescribed the medication. |
productId | UUID | Catalog product being dispensed. Null when isWritten is true. |
name | string | Name of the prescription. |
direction | string | Free-text directions explaining how to use the medication. |
quantity | decimal | Quantity dispensed. |
refillQuantity | integer | Total available refill amount. |
refillCount | integer | Refills available on the script; cannot exceed refillQuantity. |
refillPrn | boolean | Whether PRN (as-needed) refills are supported. |
isRefillAllowed | boolean | True when refillQuantity is greater than 0. |
isWritten | boolean | True for a written script filled outside the clinic; use writtenProduct instead of productId. |
writtenProduct | string | Product name for a written prescription. |
writtenIsControlled | boolean | Whether the written product is a controlled substance. |
isChronicMedication | boolean | Flags long-term medications. |
soapId | UUID | Optional SOAP record this prescription was created against. |
expirationDate | ISO 8601 | Labeled “Rx Valid Thru” in Shepherd: the last date the script is valid for refills. |
isCanceled | boolean | Whether the prescription was canceled (cancelNote carries the reason). |
clinicId | UUID | Clinic the prescription belongs to. |
createdByUserId | UUID | User who created the record. |
dateCreated | ISO 8601 | Server-assigned creation timestamp (UTC). Cannot be set or overridden. |
dateUpdated | ISO 8601 | Last server-side mutation (UTC). |
List / search
Section titled “List / search”/pav2/open-api-prescriptions Standard collection envelope. Filter with comma-separated ID lists (patientIds, productIds, clientIds), embed related records such as createdByUser, and page through results with page and rpp.
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-prescriptions \ -H "Content-Type: application/json" \ -H "X-Integration-Public-Key: $SHEPHERD_PUBLIC_KEY" \ -H "X-Integration-Private-Key: $SHEPHERD_PRIVATE_KEY" \ -H "X-Clinic-Id: $SHEPHERD_CLINIC_ID" \ -d '{ "patientIds": "12ab...", "page": 1, "rpp": 50, "sort": "dateCreated|desc" }'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-prescriptions", headers={ "Content-Type": "application/json", "X-Integration-Public-Key": os.environ["SHEPHERD_PUBLIC_KEY"], "X-Integration-Private-Key": os.environ["SHEPHERD_PRIVATE_KEY"], "X-Clinic-Id": os.environ["SHEPHERD_CLINIC_ID"], }, json={"patientIds": "12ab...", "page": 1, "rpp": 50, "sort": "dateCreated|desc"}, timeout=30,)resp.raise_for_status()page = resp.json()for rx in page["item"]: print(rx["name"], rx["quantity"], rx["expirationDate"])using System.Net.Http.Json;
using var http = new HttpClient();http.DefaultRequestHeaders.Add("X-Integration-Public-Key", publicKey);http.DefaultRequestHeaders.Add("X-Integration-Private-Key", privateKey);http.DefaultRequestHeaders.Add("X-Clinic-Id", clinicId);
var body = JsonContent.Create(new { patientIds = "12ab...", page = 1, rpp = 50, sort = "dateCreated|desc",});var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-prescriptions", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-prescriptions');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Integration-Public-Key: ' . getenv('SHEPHERD_PUBLIC_KEY'), 'X-Integration-Private-Key: ' . getenv('SHEPHERD_PRIVATE_KEY'), 'X-Clinic-Id: ' . getenv('SHEPHERD_CLINIC_ID'), ], CURLOPT_POSTFIELDS => json_encode([ 'patientIds' => '12ab...', 'page' => 1, 'rpp' => 50, 'sort' => 'dateCreated|desc', ]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch('https://open-api.shepherd.vet/pav2/open-api-prescriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Integration-Public-Key': process.env.SHEPHERD_PUBLIC_KEY, 'X-Integration-Private-Key': process.env.SHEPHERD_PRIVATE_KEY, 'X-Clinic-Id': process.env.SHEPHERD_CLINIC_ID, }, body: JSON.stringify({ patientIds: '12ab...', page: 1, rpp: 50, sort: 'dateCreated|desc' }),});if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);const page = await resp.json();for (const rx of page.item) { console.log(rx.name, rx.quantity, rx.expirationDate);}Response
Section titled “Response”{ "item": [ { "id": "7ad2...", "clinicId": "c3f1...", "patientId": "12ab...", "prescribingDoctorId": "bb55...", "createdByUserId": "9c0d...", "productId": "44de...", "name": "Amoxicillin 250 mg", "direction": "Give one tablet by mouth every 12 hours for 7 days.", "quantity": 14, "refillQuantity": 2, "refillCount": 2, "refillPrn": false, "isRefillAllowed": true, "isWritten": false, "writtenProduct": null, "writtenIsControlled": null, "isChronicMedication": false, "isCanceled": false, "cancelNote": null, "substitutionPermitted": false, "soapId": null, "expirationDate": "2026-10-21T00:00:00Z", "dateCreated": "2026-04-21T14:11:09Z", "dateUpdated": "2026-04-21T14:11:09Z" } ], "totalRecords": 312, "page": 1, "recordsPerPage": 50, "sort": "dateCreated|desc", "searchQuery": null, "embed": null, "links": []}Create
Section titled “Create”/pav2/open-api-prescriptions/write Creates a new prescription record. patientId and expirationDate are required. For an in-clinic product, provide productId; for a written script filled outside the clinic, set isWritten to true, provide writtenProduct instead, and omit productId. See the live Swagger UI for the authoritative schemas.
The created record’s dateCreated is assigned by the server at insert time; there is no request field that sets or overrides it (see Dates and backdating).
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-prescriptions/write \ -H "Content-Type: application/json" \ -H "X-Integration-Public-Key: $SHEPHERD_PUBLIC_KEY" \ -H "X-Integration-Private-Key: $SHEPHERD_PRIVATE_KEY" \ -H "X-Clinic-Id: $SHEPHERD_CLINIC_ID" \ -d '{ "patientId": "12ab...", "prescribingDoctorId": "bb55...", "productId": "44de...", "quantity": 14, "refillQuantity": 2, "direction": "Give one tablet by mouth every 12 hours for 7 days.", "expirationDate": "2026-12-31T00:00:00Z", "isChronicMedication": false }'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-prescriptions/write", headers={ "Content-Type": "application/json", "X-Integration-Public-Key": os.environ["SHEPHERD_PUBLIC_KEY"], "X-Integration-Private-Key": os.environ["SHEPHERD_PRIVATE_KEY"], "X-Clinic-Id": os.environ["SHEPHERD_CLINIC_ID"], }, json={ "patientId": "12ab...", "prescribingDoctorId": "bb55...", "productId": "44de...", "quantity": 14, "refillQuantity": 2, "direction": "Give one tablet by mouth every 12 hours for 7 days.", "expirationDate": "2026-12-31T00:00:00Z", "isChronicMedication": False, }, timeout=30,)resp.raise_for_status()print(resp.json())using System.Net.Http.Json;
using var http = new HttpClient();http.DefaultRequestHeaders.Add("X-Integration-Public-Key", publicKey);http.DefaultRequestHeaders.Add("X-Integration-Private-Key", privateKey);http.DefaultRequestHeaders.Add("X-Clinic-Id", clinicId);
var body = JsonContent.Create(new { patientId = "12ab...", prescribingDoctorId = "bb55...", productId = "44de...", quantity = 14, refillQuantity = 2, direction = "Give one tablet by mouth every 12 hours for 7 days.", expirationDate = "2026-12-31T00:00:00Z", isChronicMedication = false,});var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-prescriptions/write", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-prescriptions/write');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Integration-Public-Key: ' . getenv('SHEPHERD_PUBLIC_KEY'), 'X-Integration-Private-Key: ' . getenv('SHEPHERD_PRIVATE_KEY'), 'X-Clinic-Id: ' . getenv('SHEPHERD_CLINIC_ID'), ], CURLOPT_POSTFIELDS => json_encode([ 'patientId' => '12ab...', 'prescribingDoctorId' => 'bb55...', 'productId' => '44de...', 'quantity' => 14, 'refillQuantity' => 2, 'direction' => 'Give one tablet by mouth every 12 hours for 7 days.', 'expirationDate' => '2026-12-31T00:00:00Z', 'isChronicMedication' => false, ]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch( 'https://open-api.shepherd.vet/pav2/open-api-prescriptions/write', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Integration-Public-Key': process.env.SHEPHERD_PUBLIC_KEY, 'X-Integration-Private-Key': process.env.SHEPHERD_PRIVATE_KEY, 'X-Clinic-Id': process.env.SHEPHERD_CLINIC_ID, }, body: JSON.stringify({ patientId: '12ab...', prescribingDoctorId: 'bb55...', productId: '44de...', quantity: 14, refillQuantity: 2, direction: 'Give one tablet by mouth every 12 hours for 7 days.', expirationDate: '2026-12-31T00:00:00Z', isChronicMedication: false, }), },);if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);console.log(await resp.json());Dates and backdating
Section titled “Dates and backdating”Two date behaviors matter when you work with prescriptions, especially if you are moving data from another system:
dateCreated is server-assigned and cannot be backdated. A prescription in Shepherd represents an active dispensing event: creating one runs the live clinical workflow, including label generation, so the system always treats the prescription as something happening now. The API does not expose a prescribed or created date on the write model; this is deliberate and preserves the integrity and auditability of prescription records. Shepherd itself does not support backdating prescriptions, and the API mirrors the product.
expirationDate is the date you control. It is required on create, appears in Shepherd as “Rx Valid Thru”, and represents the last date the script is valid for refills. It can be a date in the past, for example when recording a script whose validity window has already ended.
Passing a soapId associates the prescription with a SOAP record, but it does not change the prescription’s own dateCreated; a prescription linked to an older visit still carries the timestamp of the moment it was created.
Migrating historical prescriptions
Section titled “Migrating historical prescriptions”Do not create native prescriptions for historical scripts. Every migrated record would carry the migration date as its creation date, which misrepresents the patient’s medication history and triggers the active dispensing workflow for medications that were dispensed long ago.
Instead, import each historical prescription as a patient note. This is the same approach Shepherd’s own data-migration process uses (those notes are labeled “imported prescription”): the note preserves the historical fact that a prescription was issued at a specific point in time, without creating a new dispensing event. Put the original prescribed date, drug, strength, directions, quantity, and refill details in the note body.
curl -X POST https://open-api.shepherd.vet/pav2/open-api-patient-notes/write \ -H "Content-Type: application/json" \ -H "X-Integration-Public-Key: $SHEPHERD_PUBLIC_KEY" \ -H "X-Integration-Private-Key: $SHEPHERD_PRIVATE_KEY" \ -H "X-Clinic-Id: $SHEPHERD_CLINIC_ID" \ -d '{ "patientId": "12ab...", "title": "Imported prescription: Carprofen 75 mg", "note": "Prescribed 2024-03-14 by Dr. Alvarez. Carprofen 75 mg, give 1 tablet by mouth every 12 hours for 14 days. Quantity 28, no refills. Rx valid through 2024-09-14." }'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-patient-notes/write", headers={ "Content-Type": "application/json", "X-Integration-Public-Key": os.environ["SHEPHERD_PUBLIC_KEY"], "X-Integration-Private-Key": os.environ["SHEPHERD_PRIVATE_KEY"], "X-Clinic-Id": os.environ["SHEPHERD_CLINIC_ID"], }, json={ "patientId": "12ab...", "title": "Imported prescription: Carprofen 75 mg", "note": ( "Prescribed 2024-03-14 by Dr. Alvarez. Carprofen 75 mg, give 1 tablet " "by mouth every 12 hours for 14 days. Quantity 28, no refills. " "Rx valid through 2024-09-14." ), }, timeout=30,)resp.raise_for_status()print(resp.json())using System.Net.Http.Json;
using var http = new HttpClient();http.DefaultRequestHeaders.Add("X-Integration-Public-Key", publicKey);http.DefaultRequestHeaders.Add("X-Integration-Private-Key", privateKey);http.DefaultRequestHeaders.Add("X-Clinic-Id", clinicId);
var body = JsonContent.Create(new { patientId = "12ab...", title = "Imported prescription: Carprofen 75 mg", note = "Prescribed 2024-03-14 by Dr. Alvarez. Carprofen 75 mg, give 1 tablet " + "by mouth every 12 hours for 14 days. Quantity 28, no refills. " + "Rx valid through 2024-09-14.",});var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-patient-notes/write", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-patient-notes/write');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Integration-Public-Key: ' . getenv('SHEPHERD_PUBLIC_KEY'), 'X-Integration-Private-Key: ' . getenv('SHEPHERD_PRIVATE_KEY'), 'X-Clinic-Id: ' . getenv('SHEPHERD_CLINIC_ID'), ], CURLOPT_POSTFIELDS => json_encode([ 'patientId' => '12ab...', 'title' => 'Imported prescription: Carprofen 75 mg', 'note' => 'Prescribed 2024-03-14 by Dr. Alvarez. Carprofen 75 mg, give 1 tablet ' . 'by mouth every 12 hours for 14 days. Quantity 28, no refills. ' . 'Rx valid through 2024-09-14.', ]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch( 'https://open-api.shepherd.vet/pav2/open-api-patient-notes/write', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Integration-Public-Key': process.env.SHEPHERD_PUBLIC_KEY, 'X-Integration-Private-Key': process.env.SHEPHERD_PRIVATE_KEY, 'X-Clinic-Id': process.env.SHEPHERD_CLINIC_ID, }, body: JSON.stringify({ patientId: '12ab...', title: 'Imported prescription: Carprofen 75 mg', note: 'Prescribed 2024-03-14 by Dr. Alvarez. Carprofen 75 mg, give 1 tablet ' + 'by mouth every 12 hours for 14 days. Quantity 28, no refills. ' + 'Rx valid through 2024-09-14.', }), },);if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);console.log(await resp.json());List refills
Section titled “List refills”/pav2/open-api-refills Refills are read-only through the API: they are recorded in Shepherd when the clinic fills a script. Filter by prescriptionIds to pull the refill history for a script, or by patientIds and refillStatusIds; embed refillStatus to inline the status lookup.
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-refills \ -H "Content-Type: application/json" \ -H "X-Integration-Public-Key: $SHEPHERD_PUBLIC_KEY" \ -H "X-Integration-Private-Key: $SHEPHERD_PRIVATE_KEY" \ -H "X-Clinic-Id: $SHEPHERD_CLINIC_ID" \ -d '{ "prescriptionIds": "7ad2...", "embed": "refillStatus" }'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-refills", headers={ "Content-Type": "application/json", "X-Integration-Public-Key": os.environ["SHEPHERD_PUBLIC_KEY"], "X-Integration-Private-Key": os.environ["SHEPHERD_PRIVATE_KEY"], "X-Clinic-Id": os.environ["SHEPHERD_CLINIC_ID"], }, json={"prescriptionIds": "7ad2...", "embed": "refillStatus"}, timeout=30,)resp.raise_for_status()for refill in resp.json()["item"]: print(refill["dateFilled"], refill["refillQuantity"])using System.Net.Http.Json;
using var http = new HttpClient();http.DefaultRequestHeaders.Add("X-Integration-Public-Key", publicKey);http.DefaultRequestHeaders.Add("X-Integration-Private-Key", privateKey);http.DefaultRequestHeaders.Add("X-Clinic-Id", clinicId);
var body = JsonContent.Create(new { prescriptionIds = "7ad2...", embed = "refillStatus",});var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-refills", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-refills');curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Integration-Public-Key: ' . getenv('SHEPHERD_PUBLIC_KEY'), 'X-Integration-Private-Key: ' . getenv('SHEPHERD_PRIVATE_KEY'), 'X-Clinic-Id: ' . getenv('SHEPHERD_CLINIC_ID'), ], CURLOPT_POSTFIELDS => json_encode([ 'prescriptionIds' => '7ad2...', 'embed' => 'refillStatus', ]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch('https://open-api.shepherd.vet/pav2/open-api-refills', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Integration-Public-Key': process.env.SHEPHERD_PUBLIC_KEY, 'X-Integration-Private-Key': process.env.SHEPHERD_PRIVATE_KEY, 'X-Clinic-Id': process.env.SHEPHERD_CLINIC_ID, }, body: JSON.stringify({ prescriptionIds: '7ad2...', embed: 'refillStatus' }),});if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);const page = await resp.json();for (const refill of page.item) { console.log(refill.dateFilled, refill.refillQuantity);}Response
Section titled “Response”{ "item": [ { "id": "e7d8...", "prescriptionId": "7ad2...", "name": "Amoxicillin 250 mg", "prescribingDoctorId": "bb55...", "refillQuantity": 1, "refillPrn": false, "isInitial": false, "dateFilled": "2026-05-06T15:38:33Z", "expirationDate": "2026-10-21T00:00:00Z", "refillStatusId": "d6c5...", "refillStatus": { "abrv": "completed", "name": "Completed", "id": "d6c5..." }, "requestedById": "9c0d...", "dateCreated": "2026-05-06T15:38:28Z", "dateUpdated": "2026-05-06T15:38:35Z" } ], "totalRecords": 3, "page": 1, "recordsPerPage": 10, "sort": null, "searchQuery": null, "embed": "refillStatus", "links": []}See also
Section titled “See also”- Conventions for pagination, embedding, sorting, and date filters.
- Errors for the two JSON error body shapes.
- Products for the catalog products prescriptions reference.
- SOAP records for the visit records prescriptions can be created against.
- Providers for the clinicians prescribing medications.