Inventory
Inventory in the Shepherd API is split across several related endpoints rather than a single resource. The top-level model is: a clinic has one or more inventory locations (a treatment room cabinet, the main pharmacy, etc.); each location holds product records with on-hand quantities, reorder thresholds, and per-location settings; products themselves have vendor associations, units of measure, and a status flag indicating whether they are active. Every movement (receive, dispense, transfer, adjustment) is recorded in the transaction journal.
Most integrations only need a subset: pharmacy partners read product settings and the journal; an ordering integration reads vendors, products, and locations; a clinic-wide dashboard reads location-product stock levels.
Endpoints
Section titled “Endpoints”| Endpoint | Purpose |
|---|---|
POST /pav2/open-api-inventory-locations | List inventory locations defined for a clinic. |
POST /pav2/open-api-inventory-product-location-products | List products with stock levels at a given location. |
POST /pav2/open-api-inventory-product-settings | Per-product inventory configuration (reorder points, etc.). |
POST /pav2/open-api-inventory-vendors | Vendors a clinic purchases inventory from. |
POST /pav2/open-api-uom-units | Units of measure (each, ml, tablet, gram, etc.). |
POST /pav2/open-api-inventory-status | Status values used to flag inventory items (active, archived). |
POST /pav2/open-api-inventory/transaction-journals | Audit trail of every inventory movement. |
All of the above follow the standard request shape: POST, JSON body, the three auth headers, and the same pagination, sort, and date-filter conventions documented in Conventions.
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. |
clinicId | UUID | Clinic that owns the location. |
name | string | Human-readable name (e.g. “Treatment Room”). |
abrv | string | Short code for the location. |
description | string | Free-text description. |
isActive | boolean | Whether the location is in use. |
dateCreated | ISO 8601 | Server-assigned creation timestamp (UTC). |
dateUpdated | ISO 8601 | Last server-side mutation (UTC). |
isDeleted | boolean | Soft-delete flag. Note this is isDeleted. |
List inventory locations
Section titled “List inventory locations”/pav2/open-api-inventory-locations Returns the inventory locations configured for the clinic identified by X-Clinic-Id. Most clinics have a handful of locations; this list changes rarely, so most integrations cache it client-side.
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-inventory-locations \ -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 '{"page":1,"rpp":100}'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-inventory-locations", 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={"page": 1, "rpp": 100}, timeout=30,)resp.raise_for_status()for loc in resp.json()["item"]: print(loc["name"], loc["id"])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 { page = 1, rpp = 100 });var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-inventory-locations", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-inventory-locations');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(['page' => 1, 'rpp' => 100]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch( 'https://open-api.shepherd.vet/pav2/open-api-inventory-locations', { 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({ page: 1, rpp: 100 }), },);if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);const page = await resp.json();for (const loc of page.item) console.log(loc.name, loc.id);Response
Section titled “Response”{ "item": [ { "id": "5fc11c2e-18b4-4a91-a5c9-abc123456789", "clinicId": "9890662f-52db-4a41-a5c1-b2e300d400b4", "name": "Main Pharmacy", "abrv": "PHARM", "description": "Main dispensing pharmacy", "isActive": true, "dateCreated": "2025-08-14T09:02:11Z", "dateUpdated": "2025-12-01T11:18:44Z", "isDeleted": false } ], "totalRecords": 4, "page": 1, "recordsPerPage": 100, "sort": null, "searchQuery": null, "embed": null, "links": []}Other inventory endpoints
Section titled “Other inventory endpoints”All of these follow the same request shape as the locations example above. Send a JSON body with page, rpp, and any filters you need, plus the three auth headers.
Stock by location
Section titled “Stock by location”POST /pav2/open-api-inventory-product-location-products returns per-location product records carrying on-hand quantity, reorder thresholds, and pricing overrides. Filter by location id to fetch the inventory snapshot for a single cabinet or fridge.
Product settings
Section titled “Product settings”POST /pav2/open-api-inventory-product-settings exposes the inventory-specific configuration attached to a catalog product: minimum/maximum thresholds, default vendor, default unit of measure, and reorder behaviour.
Vendors
Section titled “Vendors”POST /pav2/open-api-inventory-vendors lists vendors the clinic purchases inventory from. Use this to populate vendor pickers in ordering integrations.
Units of measure
Section titled “Units of measure”POST /pav2/open-api-uom-units returns the units of measure available in the clinic (each, ml, tablet, gram, lb, etc.). Like the lookups endpoints, the response is small and stable; cache it client-side.
Status values
Section titled “Status values”POST /pav2/open-api-inventory-status lists the status codes used to flag inventory records (active, archived, discontinued, etc.). Use this to render status filters or surface meaningful labels.
Transaction journal
Section titled “Transaction journal”POST /pav2/open-api-inventory/transaction-journals is the append-only audit trail of every inventory movement: receive, dispense, transfer, count adjustment. Filter by dateCreatedFrom and dateCreatedTo to pull the day’s activity for reconciliation.
See also
Section titled “See also”- Conventions for pagination, embedding, sorting, and date filters.
- Products for the underlying catalog that inventory tracks stock against.
- Errors for the two JSON error body shapes.