Skip to content

Authentication

The Shepherd API uses two API keys plus a clinic identifier, all sent as request headers. There is no OAuth flow, no Bearer token, and no token-refresh dance for the primary integration path.

Every request includes the following headers:

HeaderRequiredPurpose
X-Integration-Public-KeyYesIdentifies your integration.
X-Integration-Private-KeyYesProves ownership of the integration. Treat this like a password.
X-Clinic-IdOn every endpoint except open-api-clinicsThe clinic UUID this request operates against.

Both keys must be sent on every call. The public key is not a “client ID”; both values are secret, and the private key in particular must never be embedded in mobile apps, browser code, or anywhere a third party can read it. Send each key exactly as issued: the public key is a lowercase UUID and the comparison is case-sensitive, so an upper-cased key is rejected as Incorrect API keys provided. Send each header once.

How you get keys depends on who you are.

Clinic accounts building on their own data. If your Shepherd account has the open API feature enabled, you can generate and manage integration keys yourself from inside Shepherd (Admin → Integrations). These are self-service. You’ll normally build against your live clinic; ask your account manager if you’d like a separate sandbox first.

Integration partners building for other clinics. The Shepherd product team issues your keys as part of integration onboarding:

  1. You’ll get sandbox credentials first, scoped to a demo clinic, so you can build and test against https://demo-open-api.shepherd.vet/pav2/.
  2. Production credentials are issued once your integration is reviewed and the partner clinic agrees to enable it.

Either way, read the keys from environment variables or a secrets manager; never hard-code them.

Rotate the private key any time you suspect exposure. Because both keys are checked on every request, the safest pattern is:

  1. Request a second active key from the Shepherd team.
  2. Deploy the new key alongside the old one (most clients can hot-swap an environment variable).
  3. Confirm traffic is flowing under the new key.
  4. Ask the Shepherd team to revoke the old key.

Build your integration so the keys are read from environment variables or a secrets manager, never hard-coded.

The Shepherd API is multi-tenant. A single integration key can be granted access to one clinic or many, but every request operates against exactly one clinic at a time, named by X-Clinic-Id. There is no single call that returns data across every clinic at once. To cover a clinic group, change X-Clinic-Id between requests; or, where the relevant data is shared across the group, scope a query with a clinicIds filter. See Groups and multi-site for how that works, and the Clinics endpoint for discovering the clinic UUIDs your keys can reach.

The clinic id must be a UUID your keys are linked to. A malformed value fails with a 500 on every endpoint. A well-formed id your keys are not linked to (a typo, or an id from the other environment) returns 401 Integration not enabled for the provided clinic, the same response as a clinic that has not yet enabled your integration, so check the id against the clinic lookup before you look anywhere else.

The shortest end-to-end check is to fetch one clinic record. If the credentials are valid for at least one clinic, this returns a collection envelope with a single item. If the keys are wrong, you’ll get an HTTP 401 whose body is a JSON string explaining why.

This is the one call where X-Clinic-Id is optional. The samples send it because every later call needs it; if you don’t have a clinic id yet, leave that header out entirely rather than sending an empty or placeholder value, and read the id of each returned clinic.

Terminal window
curl -X POST https://open-api.shepherd.vet/pav2/open-api-clinics \
-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":1}'

If that returns 200 OK with a JSON body, you are authenticated. From here, read Conventions to learn pagination, embedding, and date filtering, then jump into the resource pages.