HTTP status codes
The API uses conventional HTTP response codes. 2xx means success, 4xx means the request was rejected (and the error explains why), and 5xx means something went wrong on our side.
| Code | Meaning |
|---|---|
200 OK | Request succeeded. |
201 Created | A resource was created. |
400 Bad Request | Missing or invalid parameters (unknown body fields are rejected). |
401 Unauthorized | No valid access token provided. |
403 Forbidden | The client lacks the scope for this resource. |
404 Not Found | The resource doesn’t exist (or isn’t in your clinic). |
409 Conflict | The request clashes with current state (e.g. a duplicate). |
429 Too Many Requests | Rate limit exceeded — back off and retry. |
The error object
Errors return a consistent JSON shape so you can handle them programmatically. code is stable; message is human-readable.
{
"error": {
"code": "BAD_REQUEST",
"message": "FirstName: Required"
}
}Response envelope
Single-resource responses wrap the object in data. List responses return data as an array plus a totalCount of all matching records (not just the current page).
{
"data": [ /* ...records... */ ],
"totalCount": 134,
"limit": 20,
"offset": 0
}Pagination
List endpoints page with limit (1–200, default 20) and offset. Most list endpoints also accept a search term.
curl "https://api.mananotes.co.nz/api/v1/patients?limit=50&offset=50&search=ngata" \
-H "Authorization: Bearer eyJhbGci..."IDs, dates & money
| Convention | Format |
|---|---|
| Resource IDs | MongoDB ObjectId strings, e.g. 65f0c2a1b3d4e5f6a7b8c9d0. Treat them as opaque. |
| Timestamps | ISO 8601 in UTC, e.g. 2026-06-20T21:30:00Z. Clinic-local time is Pacific/Auckland. Send times with Z or an offset; in a query string, encode + as %2B. |
| Calendar dates | Dates of birth and injury dates are days sent as ISO 8601 — send UTC midnight of the day, e.g. 1991-04-22T00:00:00Z. They are stored as that Pacific/Auckland calendar day, so read them back by their date part rather than converting to your local zone. |
| Money | Decimal NZD on UnitPrice (e.g. 45.00). |
Locations (multi-site clinics)
A clinic can run several physical sites. GET /locations lists them, and exactly one is the clinic’s default. Records created before a clinic adopted locations have no location id: they belong to the default site, so filtering by the default site’s id includes them.
Location ids are always optional. Single-site integrations can ignore them: leaving out locationIds, locationId, LocationId and HomeLocationId keeps clinic-wide behaviour everywhere.
| Where | Parameter | Effect |
|---|---|---|
| List appointments | locationIds | Only appointments at these sites. |
| List patients | locationIds | Only patients whose home site is one of these. |
| Availability | locationId | Slots inside one site’s working hours. |
| Book / update an appointment | LocationId | The site the appointment is at. |
| Create / update a patient | HomeLocationId | The patient’s home site. |
List filters that take several sites accept the parameter repeated or comma-separated. An empty value is the same as leaving it out:
# Either form works
curl "https://api.mananotes.co.nz/api/v1/appointments?from=2026-06-20T00:00:00Z&to=2026-06-21T00:00:00Z&locationIds=65f0f1...&locationIds=65f0f2..." \
-H "Authorization: Bearer eyJhbGci..."
curl "https://api.mananotes.co.nz/api/v1/patients?locationIds=65f0f1...,65f0f2..." \
-H "Authorization: Bearer eyJhbGci..."Rate limits
Requests are rate limited per client. Exceeding the limit returns 429 with a Retry-After header (seconds) — build in exponential backoff for resilience.