> ## Documentation Index
> Fetch the complete documentation index at: https://build.practicehub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Dates, timezones and currency

> Every date/time format the API uses, whose clock it's on, and how money is represented

<Note>
  Every date and time value says which clock it is on by its shape. A **UTC stamp ends in `Z`** (`2026-09-01T14:31:00Z`). **Clinic wall-clock time has no zone at all** (`2026-09-01T09:00:00`). A **calendar day is a plain date** (`2026-09-01`). `GET /schema/{resource}` says the same per attribute: a `timezone` of `utc` or `account`.
</Note>

## Formats

The API uses exactly three date/time shapes, all ISO 8601:

| Shape | Used for | Example |
| - | - | - |
| `YYYY-MM-DDTHH:MM:SSZ` | Server stamps — when a record changed: `created_at`, `updated_at`, `deleted_at`, `cancelled_at`, `reactivated_at`, the patient-app stamps `app_signup` / `app_last_accessed`, and webhook `occurred_at` | `2026-09-01T14:31:00Z` |
| `YYYY-MM-DDTHH:MM:SS` | Moments in the clinic's day — `appointments.starts_at` / `ends_at` | `2026-09-01T09:00:00` |
| `YYYY-MM-DD` | Calendar days — `patients.dob`, `invoices.invoice_date`, `payments.payment_date`, `payment_allocations.allocation_date`, care plan `start_date`s | `2026-09-01` |

That is the same convention as the PracticeHub web app's own data: a `Z` means UTC, no `Z` means the account's clock.

**On input** send the same shape you read. A UTC stamp may also carry an offset (`2026-09-01T15:31:00+01:00`) and is converted. Clinic wall time may carry **no** zone: `starts_at: "2026-09-01T09:00:00Z"` is a `422`, because the value would then mean a different moment from the one the clinic reads. Seconds are required; fractional seconds are accepted and dropped. `GET /schema/{resource}` names the rule per attribute (`date_format:Y-m-d\TH:i:s\Z`, `date_format:Y-m-d\TH:i:s` or `date_format:Y-m-d`), and a value in the wrong shape is a `422` naming the field.

## Whose clock

Every **domain** date/time — the ones that mean something in the clinic's day, like `appointments.starts_at`/`ends_at`, `payment_date` and `invoice_date` — is the **clinic's local wall-clock time**, not UTC and not the caller's timezone. `2026-09-01T09:00:00` on `appointments.starts_at` means 9am as the clinic's front desk would say it, however many timezones away your server sits. There's no offset in the value because none is needed: the account has exactly one timezone, and every domain date/time on it is already in that timezone.

The server-managed record stamps are different: **`created_at`, `updated_at` and the other `*_at` stamps are UTC and end in `Z`.** They tell you when a row changed, not when something happened in the clinic's day — use them for incremental sync cursors, where a single monotonic clock is exactly what you want, and use the domain fields for anything a person would read as a date.

Call `GET /me` to find out which zone the account is on — `account.timezone`, an IANA name (`Europe/London`, `America/New_York`, …):

```bash theme={null}
curl -s $BASE/me -H "Authorization: Bearer $KEY"
```

```json theme={null}
{
  "data": {
    "type": "ApiApplication",
    "id": 12,
    "name": "Booking widget",
    "scopes": ["read", "write"],
    "account": { "id": 3295, "name": "Riverside Clinic", "timezone": "Europe/London", "currency": "GBP" }
  }
}
```

Do this once when you connect an integration and cache it — an account's timezone and currency don't change often, but they're not something to hardcode per clinic. If your system works in UTC or another timezone internally, convert at the boundary: localise before you send a write, and interpret every zone-less date/time you read as being in `account.timezone`, not your server's zone.

<Note>
  Filters follow the same rule. `starts_at=gte:2026-09-01T00:00:00` in [Querying](/guides/querying#filters) means midnight in the clinic's timezone; `updated_at=gte:2026-09-01T00:00:00Z` is UTC midnight.
</Note>

## Currency

`account.currency` from `GET /me` is the account's single operating currency (an ISO 4217 code, `GBP` in the example above) — every amount on every resource (`payments.amount`, `invoices.total` / `balance` / `subtotal`, `line_items.price`, …) is in that currency. There's no per-record or per-line currency field to check: PracticeHub accounts don't mix currencies.

Amounts are decimal strings or numbers with **at most two decimal places** — `"45.00"`, not `45` or `"45.0000"`. A third decimal place is rejected as invalid input rather than silently rounded, so a value like `19.999` never becomes `20.00` or `19.99` without you knowing.

| Limit | Value |
| - | - |
| Decimal places | 2 |
| Maximum magnitude | ±99,999,999.99 |
| Sign | Amounts you send are non-negative, with one exception: `price` on a discount line. A payment you record is money received (`0.01` or more); a refund (`POST /refunds` takes a positive `amount`) reads back as a negative `amount` — see [Billing](/resources-guide/billing#refunds) |

An amount outside the range is `422 amount_out_of_range`; a `line_items.quantity` outside `1`–`2147483647` (a whole number) is `422 quantity_out_of_range`.

```bash theme={null}
curl -X POST $BASE/payments \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{ "patient_id": 340, "amount": "45.00", "payment_method_id": 3, "location_id": 1, "payment_date": "2026-09-01" }'
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.