Skip to content

How we verify this reference

We publish the Swagger UI, and it is generated from the API’s own code, so it is the authority on the shape of every request and response: routes, fields, and types. What a schema cannot tell you is how the API behaves at the edges. Which values are rejected and which are quietly adjusted, which filters an endpoint actually applies, what a mistake costs, and which failures are worth retrying.

That behavior is what breaks integrations in production, so we don’t document it from the schema alone. We test it against the real API and write down what we observe.

We built a test harness, written in Python, that exercises the Shepherd API the way real integrations do, including the ways they commonly go wrong. It runs against the live production API, inside a dedicated test clinic that holds no real client or patient data.

Each run:

  • Calls every public read endpoint with a minimal valid request and records the shape of the response.
  • Probes the edges of every request convention. Page sizes and page numbers at and past their limits, sort fields and directions that don’t exist, date windows that are malformed or run backwards, unknown fields and embeds, and request bodies that are empty, null, or not valid JSON.
  • Tests authentication and clinic scoping. Missing, wrong, and swapped keys; missing, malformed, and unlinked clinic ids; and whether any request can return records from a clinic other than the one it names.
  • Creates and updates clearly marked test records through the write endpoints that are safe to exercise, then reads each record back. Writes that could reach a real person, such as messages or appointment notifications, are never sent.
  • Watches its own impact. Requests are spaced out and stay far below the rate limit, and the run stops itself at the first sign of strain on the API.

The harness records only the shape of each response (status, timing, size, field names and types), never the field values, so results can be kept and compared from one API release to the next.

Every claim on these pages, and every rule in the AI agent skill, is checked against those results and against the API’s source code.

The September 2026 runs covered API version 2.246.0.33 with about 4,500 requests. Where the results disagreed with what we had written, we corrected the pages:

  • rpp and page below 1 are rejected with a 400, as is a date window that ends before it starts. We had said they were not rejected.
  • A clinic your keys are not linked to returns 401 (Integration not enabled for the provided clinic), not 403. A 403 means the key’s permissions don’t cover that endpoint or record. See Errors.
  • An unsupported sort is usually ignored, not rejected. Most endpoints return 200 in their default order; only a few return 400, and two return 501. See Sorting.
  • Some endpoints accept filters they never apply. For example, the inventory transaction journal filters on dateFrom / dateTo and ignores the standard dateCreated pair. See Fields an endpoint does not apply.
  • A 500 is almost always caused by the request, typically an empty or null body or a malformed id. We now advise against retrying it at all.
  • A few endpoints return very large records, so we now recommend pages of 100 or less on them.
  • The unfiltered breed list is far larger than a lookup should be, so always filter it to the clinic. See Lookups.

The runs also confirmed much of what these pages already said: unknown fields and embeds are ignored rather than rejected, an rpp above 1000 is reduced to 1000, rejected requests count against your rate limit while the usage endpoint does not, a malformed clinic id fails with a 500, and no request returned another clinic’s records.

We run the harness after API releases and before we publish changes to the API reference or the agent skill. Findings that are defects in the API, rather than in these pages, go to the engineering team; until a fix ships, these pages describe the API as it behaves today.

If you see the API behave differently from what these pages say, tell us. Include the endpoint, the request body with credentials and clinic data removed, the status you got, and the time in UTC.