Payments
Payments are the money side of the invoice ledger: a payment applies a tender (cash, card, check, in-house credit) against one or more invoices for a client. The endpoints here cover three things most billing integrations need: listing payments that have already been recorded, listing the payment methods a clinic accepts, and reading client balances (current and aged).
If you’re trying to generate a charge, that’s invoicing; see Invoices. This page is about what happens after the invoice is finalized.
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 payment identifier. |
clientId | UUID | Client the payment applies to. |
clinicId | UUID | Clinic the payment was recorded at. |
paymentDate | ISO 8601 | When the payment was taken (UTC). |
amount | decimal | Tender amount. |
paymentMethodId | UUID | The tender type (cash, card brand, check, credit). See payment-methods endpoint below. |
paymentStatusId | UUID | Status (pending, approved, declined, voided, refunded). See Lookups. |
referenceNumber | string | Check number, terminal reference, or similar. |
authCode | string | Authorization code returned by the card processor, when applicable. |
cardType | string | Card brand (Visa, Mastercard, etc.), when applicable. |
lastDigits | string | Last four digits of the card, when applicable. |
transactionId | string | Processor transaction identifier, when applicable. |
payToCreditBalance | decimal | Portion of the payment applied to the client’s in-house credit, when applicable. |
clientBalanceAfterPayment | decimal | Client’s outstanding balance after this payment is applied (informational). |
refundedPaymentId | UUID | When this record represents a refund, the id of the original payment it refunds. |
processedByUserId | UUID | Staff user who processed the payment. |
note | string | Free-text note attached to the payment. |
isDeleted | boolean | Soft-delete flag. |
dateVoided | ISO 8601 | Set when the payment has been voided. |
dateCreated | ISO 8601 | Server-assigned creation timestamp (UTC). |
dateUpdated | ISO 8601 | Last server-side mutation (UTC). |
List payments
Section titled “List payments”/pav2/open-api-payments Returns payments recorded at the clinic identified by X-Clinic-Id. Filter by client, status, or date range as needed. For a group with sharing enabled, clinicIds widens the query to other clinics in the group.
Example
Section titled “Example”curl -X POST https://open-api.shepherd.vet/pav2/open-api-payments \ -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,"sort":"paymentDate|desc","clientIds":"<CLIENT_GUID>"}'import os, requests
resp = requests.post( "https://open-api.shepherd.vet/pav2/open-api-payments", 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, "sort": "paymentDate|desc", "clientIds": os.environ["SHEPHERD_CLIENT_ID"], }, timeout=30,)resp.raise_for_status()for p in resp.json()["item"]: print(p["paymentDate"], p["amount"], p["paymentMethodId"])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, sort = "paymentDate|desc", clientIds = clientId,});var resp = await http.PostAsync( "https://open-api.shepherd.vet/pav2/open-api-payments", body);resp.EnsureSuccessStatusCode();Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php$ch = curl_init('https://open-api.shepherd.vet/pav2/open-api-payments');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, 'sort' => 'paymentDate|desc', 'clientIds' => getenv('SHEPHERD_CLIENT_ID'), ]),]);$response = curl_exec($ch);curl_close($ch);echo $response;const resp = await fetch('https://open-api.shepherd.vet/pav2/open-api-payments', { 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, sort: 'paymentDate|desc', clientIds: process.env.SHEPHERD_CLIENT_ID, }),});if (!resp.ok) throw new Error(`Shepherd ${resp.status}: ${await resp.text()}`);const page = await resp.json();for (const p of page.item) console.log(p.paymentDate, p.amount, p.paymentMethodId);Response
Section titled “Response”{ "item": [ { "id": "c1d2e3f4-...", "clientId": "a1b2c3d4-...", "clinicId": "f2a4c6e8-...", "paymentDate": "2026-05-21T13:42:00Z", "amount": 128.5, "paymentMethodId": "5e6f7a8b-...", "paymentStatusId": "9c8d7e6f-...", "referenceNumber": null, "authCode": "0091AB", "cardType": "Visa", "lastDigits": "4242", "transactionId": "txn_8c2...", "payToCreditBalance": 0, "clientBalanceAfterPayment": 0, "refundedPaymentId": null, "processedByUserId": "bb551122-...", "note": null, "isDeleted": false, "dateVoided": null, "dateCreated": "2026-05-21T13:42:01Z", "dateUpdated": "2026-05-21T13:42:01Z" } ], "totalRecords": 1, "page": 1, "recordsPerPage": 100, "sort": "paymentDate|desc", "searchQuery": null, "embed": null, "links": []}Payment methods
Section titled “Payment methods”/pav2/open-api-payment-methods The list of tender types the clinic accepts (cash, card brands, check, in-house credit, gift card, etc.). Use this to populate a UI picker, or to translate the paymentMethodId on a payment record into a human-readable name.
curl -X POST https://open-api.shepherd.vet/pav2/open-api-payment-methods \ -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}'A parallel endpoint, /pav2/open-api-payment-statuses, returns the payment-status catalog (pending, approved, declined, voided, refunded). Both are also discoverable through Lookups.
Client balances
Section titled “Client balances”The open-api-client-balances controller exposes four aging cuts of client A/R. Each is a separate sub-route under the same prefix; pick the one that matches what you need to surface.
/pav2/open-api-client-balances/balances /pav2/open-api-client-balances/aging /pav2/open-api-client-balances/outstanding-balance-aging /pav2/open-api-client-balances/credit-balance-aging | Sub-route | What it returns |
|---|---|
balances | Current balance per client (net of credits). |
aging | Standard A/R aging buckets (0-30, 31-60, 61-90, 90+). |
outstanding-balance-aging | Aging of unpaid invoices only. |
credit-balance-aging | Aging of in-house credit on file. |
Example: aging summary
Section titled “Example: aging summary”curl -X POST https://open-api.shepherd.vet/pav2/open-api-client-balances/aging \ -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}'const resp = await fetch( 'https://open-api.shepherd.vet/pav2/open-api-client-balances/aging', { 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 row of page.item) console.log(row.clientId, row);See also
Section titled “See also”- Invoices for the upstream charges payments apply against.
- Clients for the client records balances roll up under.
- Conventions for pagination, sorting, and date filters.
- Errors for the two JSON error body shapes.