Treatments
A treatment is a line item on the Plan section of a SOAP record: a medication administered, a procedure performed, a lab run, or a supply dispensed during a visit. Treatments are where the medical record meets the invoice; each one documents what happened clinically and also produces the invoice line the client is charged for. That dual role is why a treatment carries two amount fields, dose and quantity, which answer different questions (see dose vs quantity below).
Treatments are read-only through the API: clinic staff create them in Shepherd as part of the SOAP workflow. Use them to reconstruct what was done during a visit, feed medical-records integrations, or reconcile clinical activity against invoices.
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. |
soapPlanId | UUID | The Plan section this treatment belongs to. |
name | string | Treatment name as it appears on the plan. |
productId | UUID | Catalog product or service behind the line item. |
productCategoryId | UUID | Catalog category lookup. |
dose | decimal | Clinical amount administered. Null or 0 when no dosage was calculated; see below. |
quantity | decimal | Billable units charged on the invoice. |
concentration | decimal | Concentration used by the dosage calculator, where applicable. |
price | decimal | Unit price. |
dispensingFee | decimal | Dispensing fee applied to the line item. |
invoiceItemId | UUID | Invoice line item this treatment produced. |
includedInMedicalRecord | boolean | Whether the treatment appears in the medical record. |
includedOnInvoice | boolean | Whether the treatment appears on the invoice. |
isControlled | boolean | Controlled-substance flag. |
isDeclined | boolean | True when the client declined the treatment (dateDeclined carries when). |
timeAdministered | ISO 8601 | When the treatment was administered. |
administeredById | UUID | Team member who administered it. |
additionalInstruction | string | Free-text instructions attached to the line item. |
lotNumber | string | Lot number, where tracked. |
dateCreated | ISO 8601 | Server-assigned creation timestamp (UTC). |
dateUpdated | ISO 8601 | Last server-side mutation (UTC). |
deleted | boolean | Soft-delete flag. |
List / search
Section titled “List / search”/pav2/open-api-soap-plan/treatment Standard collection envelope. Filter with comma-separated ID lists (patientIds, productIds, soapPlanIds, clientIds), or by the dateCreatedFrom / dateCreatedTo pair for time-series pulls; searchQuery matches on patient name. Page through results with page and rpp.
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-soap-plan/treatment \ -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-soap-plan/treatment", 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()for treatment in resp.json()["item"]: print(treatment["name"], treatment["dose"], treatment["quantity"])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-soap-plan/treatment", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-soap-plan/treatment');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-soap-plan/treatment', { 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 treatment of page.item) { console.log(treatment.name, treatment.dose, treatment.quantity);}Response
Section titled “Response”Note the two line items below: the injectable was run through the dosage calculator, so it carries a clinical dose alongside its billable quantity; the catheter placement is a procedure, so dose is null and only quantity is populated. Both shapes are normal.
{ "item": [ { "id": "13f7...", "soapPlanId": "ba0e...", "name": "Buprenorphine 0.3 mg/mL injectable", "productId": "98f4...", "productCategoryId": "45e7...", "dose": 0.6, "quantity": 1, "concentration": 0.3, "price": 42, "dispensingFee": 0, "invoiceItemId": "db24...", "includedInMedicalRecord": true, "includedOnInvoice": true, "isControlled": true, "isDeclined": false, "timeAdministered": "2026-06-12T10:25:45Z", "administeredById": "9baf...", "additionalInstruction": "", "lotNumber": null, "dateCreated": "2026-06-12T10:25:30Z", "dateUpdated": "2026-06-12T10:25:48Z", "deleted": false }, { "id": "20aa...", "soapPlanId": "ba0e...", "name": "IV catheter placement", "productId": "77cd...", "productCategoryId": "45e7...", "dose": null, "quantity": 1, "concentration": 0, "price": 68, "dispensingFee": 0, "invoiceItemId": "db31...", "includedInMedicalRecord": true, "includedOnInvoice": true, "isControlled": false, "isDeclined": false, "timeAdministered": "2026-06-12T10:12:02Z", "administeredById": "9baf...", "additionalInstruction": "", "lotNumber": null, "dateCreated": "2026-06-12T10:11:50Z", "dateUpdated": "2026-06-12T10:12:10Z", "deleted": false } ], "totalRecords": 2, "page": 1, "recordsPerPage": 50, "sort": "dateCreated|desc", "searchQuery": null, "embed": null, "links": []}dose vs quantity
Section titled “dose vs quantity”The two fields answer different questions:
doseis the clinical amount. The exact volume or count prescribed or administered to the patient (1.5 mL, 2 tablets, 50 mg). It is a purely medical metric and belongs in medical records and discharge instructions.quantityis the billable units. The inventory and financial units charged on the invoice. If a clinic dispenses an entire bottle or charges a flat rate for a service,quantityis 1 even when the clinical dose administered was a specific fluid volume.
quantity is the authoritative field for billing and invoicing: it is what lands on the invoice line and what is subtracted from stock, multiplied by the unit price.
When dose is null or 0
Section titled “When dose is null or 0”A null or 0 dose alongside a populated quantity is expected behavior, not missing data. It happens whenever the line item was never run through the clinical dosage calculator:
- Services and procedures. Catheter placements, lab tests, imaging: no chemical dose exists, but a
quantityof 1 is billed. - Flat-fee and pre-packaged medications. Euthanasia solutions, standard vaccines, or pre-filled syringes that the clinic inventories and bills as a single flat item rather than by measured volume.
- Medical supplies. Consumables like bandages, syringes, or disposal fees only ever populate
quantity. - Manual entry. A clinician added the product to the plan with a billing quantity but skipped the dosage calculator.
- Non-weight-dependent items. Anything not dosed against the patient’s weight is frequently tracked strictly by inventory count.
Which field to use
Section titled “Which field to use”| If you are building | Use |
|---|---|
| Medical records, discharge instructions, client-facing summaries | dose, with a fallback: when dose is null or 0, display quantity plus the product’s unit of measure so the user never sees a blank. |
| Billing, invoicing, or inventory reconciliation | quantity, always. |
Related endpoints
Section titled “Related endpoints”| Endpoint | Purpose |
|---|---|
/pav2/open-api-soap-plan/treatment-note | Notes attached to individual treatments; embed soapTreatment to inline the parent line item. |
/pav2/open-api-soap-plan/recommendation | Recommendations recorded on the plan. |
/pav2/open-api-soap-plan/note | Free-form notes on the plan section. |
See also
Section titled “See also”- SOAP records: the parent visit record and its other sub-resources.
- Products: the catalog items behind treatment line items, including units of measure.
- Invoices: where treatment
quantitylands as an invoice line. - Conventions: pagination, embed, sort, and date-range rules.
- Errors: HTTP status codes and the two JSON error shapes.