Clients & Patients

This guide explains how to work with client (owner) and patient (animal) data through the Vetera REST API.

In Vetera, a client is the owner or guardian of one or more animals. A patient is the animal being treated. Clients and patients are separate resources: a client can have multiple patients, but each patient belongs to exactly one client. Both resources support full create, read, update, and archive operations via the REST API.

Fetching Clients

API endpoint: https://app.vetera.com.au/<vetera_id>/api/0.1/client/

Use query parameters to filter the client list:

Parameter

Example

Description

firstname__icontains

firstname__icontains=john

Case-insensitive partial match on first name

lastname__icontains

lastname__icontains=smith

Case-insensitive partial match on last name

organization_name__icontains

organization_name__icontains=farm

Partial match on company/organization name

email__is

email__is=john@example.com

Exact match on email address

phonenumbers__icontains

phonenumbers__icontains=+358

Partial match on any phone number

archived__is

archived__is=false

Exclude archived clients

has_alive_patients__is

has_alive_patients__is=true

Only clients with at least one living patient

modified__gte

modified__gte=2024-03-01T00:00:00

Records changed since this timestamp (use for delta sync)

Searching by name across individual and corporate clients:

The default behaviour combines filters with AND logic. To search across firstname, lastname, and organization_name simultaneously with OR logic — useful when you don’t know whether a client is a person or a company — add filter_type=or:

GET /api/0.1/client/?firstname__icontains=hill&filter_type=or

This returns any client whose first name, last name, or organisation name contains “hill”.

Creating a Client

API endpoint: POST https://app.vetera.com.au/<vetera_id>/api/0.1/client/

Request Body Example:

{
    "firstname": "John",
    "lastname": "Smith",
    "email": "john.smith@example.com",
    "country": "GB",
    "customer_type": 0
}

Customer type values:

Value

Description

0

Private person

1

Company

2

EU Company

3

Charitable organization

4

UK charity

Note

The country field uses ISO 3166-1 alpha-2 codes (e.g., FI, GB, US, NO).

Phone numbers are not part of the client record itself — they are created as separate records linked to the client. See the Phone Numbers section below.

Updating a Client

API endpoint: PATCH https://app.vetera.com.au/<vetera_id>/api/0.1/client/<id>/

Only include the fields you want to change. Example — updating the email address and disabling SMS:

{
    "email": "new.email@example.com",
    "no_sms": true
}

Setting no_sms=true or no_email=true prevents Vetera from sending automated messages to this client.

Fetching Patients

API endpoint: https://app.vetera.com.au/<vetera_id>/api/0.1/patient/

Commonly used filters:

Parameter

Example

Description

client__is

client__is=456

All patients belonging to a specific client

name__icontains

name__icontains=max

Case-insensitive partial match on patient name

microchip__is

microchip__is=900123456789012

Exact microchip number lookup

species__is

species__is=15461002

Filter by species code — numeric ID from GET /api/0.1/codelist/species/

archived__is

archived__is=false

Exclude archived patients

deceased__is_null

deceased__is_null=true

Only living (non-deceased) patients

date_of_birth__gte

date_of_birth__gte=2020-01-01

Patients born on or after this date

modified__gte

modified__gte=2024-03-01T00:00:00

Records changed since this timestamp

Example — fetch all living, non-archived patients for a specific client:

GET /api/0.1/patient/?client__is=456&archived__is=false&deceased__is_null=true

Creating a Patient

API endpoint: POST https://app.vetera.com.au/<vetera_id>/api/0.1/patient/

Request Body Example:

{
    "client": "https://app.vetera.com.au/<vetera_id>/api/0.1/client/456/",
    "name": "Max",
    "species": 15461002,
    "breed": 13689002,
    "gender": "Male",
    "date_of_birth": "2020-06-15"
}

Note

species and breed accept a numeric code — the id field from the codelist response. Retrieve the list of valid species codes from GET /api/0.1/codelist/species/ and valid breed codes from GET /api/0.1/codelist/breeds/. Use the id field from each result as the value. Codes are installation-specific and may differ between Vetera environments.

The species field in the response returns the human-readable display name (e.g. "Dog (Canine - Domestic)"); to get the numeric code back, read the species_code field instead.

Gender values:

Value

Notes

Male

Female

Male, neutered

Female, neutered

Unknown

Gelding

Equine only

Mare

Equine only

Stallion

Equine only

Example response:

{
    "id": 2130,
    "url": "https://app.vetera.com.au/4/api/0.1/patient/2130/",
    "client": "https://app.vetera.com.au/4/api/0.1/client/218/",
    "name": "Fenton",
    "official_name": "",
    "species": "Dog (Canine - Domestic)",
    "breed": "None",
    "gender": "Female",
    "weight": null,
    "date_of_birth": null,
    "deceased": null,
    "microchip": null,
    "archived": false,
    "home_department": null,
    "created": "2021-11-10T15:45:50.179386+02:00",
    "modified": "2021-11-10T15:45:50.179414+02:00",
    "tags_rel": [],
    "fields_rel": []
}

Updating a Patient

API endpoint: PATCH https://app.vetera.com.au/<vetera_id>/api/0.1/patient/<id>/

Example — recording a microchip and current weight:

{
    "microchip": "900123456789012",
    "weight": "32.5"
}

To mark a patient as deceased, set the deceased field to a date:

{
    "deceased": "2024-03-20"
}

To reactivate a patient that was incorrectly marked as deceased, set deceased to null.

Custom Fields

Custom fields allow clinics to store additional data on clients and patients beyond the standard fields. The available fields differ between Vetera installations.

Discovering Available Fields

GET /api/0.1/custom_fields/

Returns all custom field definitions configured for this Vetera instance.

Key response fields:

Field

Description

id

The field ID — used when writing values

name

Human-readable label

field_type

Data type of the field, as an integer. See the table below.

content_type

Which model this field applies to: client, patient or consultation

owned

True when your application created this field, so may change or archive it

field_type values. All seven can appear when reading; only some can be created through the API:

Value

Type

Can be created through the API

Format of a value

1

Text

Yes

Any text

2

Number

Yes

A whole number. Store decimals in a text field.

3

Date

Yes

YYYY-MM-DD

4

Check box

Yes

True or False. A required check box must be True.

5

JSON

Yes

A JSON-encoded string

6

Select

No

A list of options, see the select example below

7

Multi-select

No

A list of options, see the select example below

Managing Field Definitions

An integration can create and manage its own custom field definitions, so a clinic does not have to add them by hand before your integration can store data.

POST /api/0.1/custom_fields/

{
    "name": "Loyalty scheme reference",
    "content_type": "client",
    "field_type": 1,
    "default_value": "Bronze"
}

content_type accepts client, patient or consultation. Creation supports the field types whose answer is a single value: text, number, date, check box and JSON. Select and multi-select fields carry their own options and can only be set up in Vetera; sending one returns 400.

default_value is optional. It is the value Vetera fills in when staff create a new record, and it is always sent and returned as a string:

Field type

Format

Example

Text

Any text

"Bronze"

Number

A whole number, up to 15 digits

"4"

Date

YYYY-MM-DD

"2026-10-01"

Check box

True or False

"True"

JSON fields cannot have a default. A value that does not fit the field type returns 400. An empty string means there is no default.

Note

Definition management requires an OAuth 2.0 access token. A legacy API key cannot create or change definitions, because every field records which application created it.

Creating, changing and archiving definitions also needs the “Custom field settings” write permission, in addition to “Patients and clients”. A field applies to every department, so this is the same permission the custom field settings page needs. The user the access token acts for must have both; with an authorization code token, that is the user who authorized your application. A request without them returns 403.

A legacy API key returns 401 on these requests. Permissions are checked first, though, so a legacy API key whose permission group lacks the permissions above returns 403 instead. Either way, use an OAuth 2.0 access token.

Your application may only change or archive the fields it created itself. Fields created by clinic staff, or by another integration, are readable but not writable, and return 403. The owned flag on each field tells you which are yours, so you do not have to attempt a write to find out.

PATCH /api/0.1/custom_fields/<id>/

name, default_value and archived can be changed. Send an empty default_value to remove the default. is_required is read-only: it is ignored when you create or change a field, and is set by the clinic in Vetera.

field_type and content_type are fixed when the field is created, because changing either would leave values already recorded against the field with data that no longer matches it. Sending a different value returns 400; sending the current value is accepted, so echoing a whole record back is safe. There is no PUT on this endpoint for the same reason.

A name that is already taken for that content_type returns 400, including when the existing field is archived. When the existing field is one your application created, the error gives its id. If that field is one your integration archived earlier, restore it with PATCH and {"archived": false} instead of creating a new one.

DELETE /api/0.1/custom_fields/<id>/

Archives the definition. It is never deleted, and the values clinics have already recorded against it are preserved. Restore an archived field by sending PATCH with {"archived": false}; its values are still attached where they were.

Values recorded against an archived field can still be read and written through the API, although Vetera’s forms hide the field.

Warning

A field name must be unique for each content_type across the whole installation, and an archived field keeps its name reserved. If you archive “External ID” for clients you cannot create a new client field with that name until the archived one is restored. Names are also shared with the clinic’s own fields, so creating a field may return 400 if staff already added one with that name.

Note

Clinic staff can still rename or archive a field your application created, from the custom field settings page. Look up fields by id, not by name. POST /api/0.1/consultation/admit/ matches custom fields by name, so after a rename a request that still uses the old name returns 400.

A field archived by clinic staff stays owned by your application, so the API still lets you restore it. Restore only fields your integration archived itself; a field the clinic archived was archived on purpose.

Reading Custom Field Values

Custom field values are always included in the standard client and patient response as a fields_rel array. Each entry contains:

Field

Description

id

ID of this value record

field_id

ID of the custom field definition

label

Human-readable field name

value

The stored value

If fields_rel returns an empty list, it means either no custom fields have been configured on the instance, or no values have been set for that record yet.

You can also fetch custom field values from the dedicated nested endpoints:

GET /api/0.1/client/<id>/custom_field_values/

GET /api/0.1/patient/<id>/custom_field_values/

Writing Custom Field Values

Include the fields_rel array in a create or update request body:

{
    "firstname": "John",
    "lastname": "Smith",
    "fields_rel": [
        {
            "field_id": 42,
            "value": "Referred by Dr. Brown"
        }
    ]
}

For select or multi-select fields, pass value as a list of option objects:

{
    "fields_rel": [
        {
            "field_id": 55,
            "value": [
                {"id": 101, "name": "Option A"},
                {"id": 102, "name": "Option B"}
            ]
        }
    ]
}

You can also create or update values via the nested endpoint:

POST /api/0.1/client/<id>/custom_field_values/

For JSON fields, send value as a JSON-encoded string, for example "{\"ref\": 1}". The custom_field_values endpoints reject an object sent as value with 400.

Consultation fields

To write a value to a consultation field, use the flat endpoint with the consultation ID as object_id:

POST /api/0.1/custom_field_values/

{
    "field": 77,
    "object_id": 1234,
    "value": "Referred by Dr. Brown"
}

The value’s content_type comes from the field. If the record already has a value for that field, the existing value is updated.

Note

If a custom field value already exists for that field on that record, posting to the nested endpoint will update the existing value rather than returning a duplicate error.

Phone Numbers

Phone numbers are stored as separate records linked to a client, not as fields on the client record itself.

Add a phone number after creating the client:

API endpoint: POST https://app.vetera.com.au/<vetera_id>/api/0.1/phonenumber/

{
    "client": "https://app.vetera.com.au/<vetera_id>/api/0.1/client/456/",
    "phone_number": "+441234567890",
    "type_code": 1
}

Phone type values:

Value

Description

0

Landline

1

Mobile

To list all phone numbers for a client:

GET /api/0.1/phonenumber/?client__is=456

Bulk Patient Creation

To create multiple patients in a single request, use the bulk endpoint:

API endpoint: POST https://app.vetera.com.au/<vetera_id>/api/0.1/patient/bulk/

The request body is an array of patient objects using the same fields as the standard create endpoint.

Add ?force_push=true to enable partial success mode: patients that pass validation are created even if others in the batch fail.

Response status codes:

Status

Meaning

201

All patients created successfully

207

Partial success — check response for which records failed

400

All records failed validation