Skip to main content
The PracticeHub API was built alongside PracticeHub 2.0 with one goal: an integration you can build quickly, trust in production, and hand to an AI assistant without special-casing anything. This page walks through the decisions that make that true, so you know what you can rely on before you write a line of code.
Short version: one base URL, one auth header, one response shape, one error shape; writes that behave exactly like the PracticeHub app; a contract you can read by machine; and AI-native access through the MCP server.

One consistent surface

Every resource works the same way: GET to list and read, POST to create, PATCH to update, DELETE returning 204. Lists come back as { data, links, meta }, single records as { data }, and a create or update returns the full record — defaults, computed fields and metadata included — so you never need a second request to see what was actually stored. Types mean what they say: ids and integers are JSON numbers, booleans are booleans, empty is null. Money is a fixed two-decimal string ("45.00") so no client accidentally rounds a balance as a float — deliberate, and documented in Dates, timezones and currency.

Errors you can branch on

One error shape everywhere: { message, code, errors? }. code is a stable, documented, snake_case identifier (patient_not_found, group_full, idempotency_key_reused, rate_limited, …); errors is keyed by attribute for input problems; status codes are used properly (401 credentials, 403 permission, 404 missing, 409 business rule, 422 input, 429 rate limit). You branch on code; message is for showing to a human. See Errors.

Writes behave like the app

A write through the API is subject to exactly the rules a staff member’s click is: a booking checks the patient is active and the room is at that location, a payment updates the balance, voiding an invoice releases its allocations, and everything lands on the account’s audit trail. There is no separate, looser “API path” into clinical or financial records — which means a record created by your integration is indistinguishable from one created at the front desk, and a rule change in the practice’s settings applies to both at once. See Writing.

A contract you can read by machine

GET /schema/{resource} returns the live contract: every attribute, whether it’s filterable and sortable, which write operations exist, and the exact validation rules per attribute per operation. The OpenAPI reference and Postman collection come from the same source as the running API and are verified against it on every change — if they and the API ever disagreed, that would be a bug, not documentation lag. This is also what makes the API a good target for code generators and AI coding assistants.

Querying that scales

Filters (?status=eq:pending, ?updated_at=gte:2026-08-01), multi-attribute sorting, and cursor pagination: an opaque token resumes a list exactly where you left off, every page costs the same however deep you walk, and rows created or deleted elsewhere can’t shift or duplicate what you’ve already read. Unknown or unfilterable attributes are refused with a 422 instead of silently ignored. See Querying.

Safe retries

Send an Idempotency-Key with any POST and a retry within 24 hours replays the original response (Idempotent-Replayed: true) instead of creating a duplicate; the same key with a different body is refused. Timeouts stop being scary. See Writing → Retrying safely.

Your ids, on our records

Every record carries a metadata object you own — up to 50 string keys, merged on update, filterable on every resource: GET /patients?metadata[crm_id]=eq:hs-778, or metadata[crm_id]=null for “everything I haven’t synced yet”. No more mapping tables on your side. See Metadata.

Push, not poll

Subscribe an HTTPS endpoint and receive events when records change — whether the change came through the API, from staff in the app, or from a background job. Payloads are thin (event type + record id) so no clinical data transits the delivery network; deliveries are signed (Standard Webhooks); retries, replay, delivery logs and secret rotation are self-serve under Developers → Webhooks. Webhooks are in a limited rollout — patient and appointment events first, further resources announced in the changelog. See Webhooks.

Built for AI assistants

The MCP server sits on the same base URL, backed by the same resources and the same rules. A team member connects Claude or ChatGPT with OAuth and the assistant acts as them — their permissions, their name on the audit trail. For unattended agents, an API key against the REST API does the same job, attributed to the integration. Nothing about the API needs to be “adapted” for assistants: typed data, discoverable schema and clear refusals are what they need, and what every other client gets too.

Security posture

Every clinic account is an isolated tenant with its own subdomain; a credential only ever reaches the account it was created on. API keys carry read/write scopes, optional expiry, one-click rotation with a 24-hour grace window, and instant revocation; every request lands in Developers → API Logs. The whole posture is on Security.
Ready to try it? The Quickstart gets you from zero to a booked appointment in a few minutes.