Tenancy and data residency
- One database per account. Each clinic account is a tenant with its own database. The API resolves the account from the request host (
{clinic}.{region}.practicehub.io— the practice’s own login host, in its region) before routing, so a credential is bound to the database of the account it was issued on and is refused elsewhere. - Five regions. Accounts are hosted in London, Frankfurt, Ohio, Singapore or Sydney, and the API for an account is served from that account’s region. Webhook events (record ids only — see below) are delivered through a regional Svix environment: EU for London and Frankfurt accounts, US for Ohio, Singapore and Sydney.
- Credentials are account-bound. API keys belong to an integration record on the account; OAuth connector tokens belong to a team member on the account. Neither authenticates against another account.
Authentication and credentials
API keys
API keys
- Format
phk_…; the prefix lets secret scanners recognise a leaked key. - Only a SHA-256 hash is stored; the plain key is shown once at creation and cannot be retrieved afterwards.
- Scoped: read & write, or read-only. A read-only key is refused on every write path (REST and MCP alike) — enforced once, in the write service, not per endpoint.
- Optional expiry (90 days / 1 year) and rotation with a 24-hour grace period for the old key. Revocation is immediate.
- Created, rotated and revoked only by signed-in team members with the developer permission, from Developers → API Keys; every one of those actions is written to the account’s activity log.
OAuth connectors (Claude, ChatGPT and other MCP clients)
OAuth connectors (Claude, ChatGPT and other MCP clients)
- OAuth 2.1 with PKCE, dynamic client registration with an allow-list of redirect hosts, and per-account consent screens shown to the signed-in team member.
- Access tokens live 1 hour; refresh tokens 30 days and rotate on use.
- Opt-in per role: a team member can only connect an AI app if their role has Connect AI apps enabled by an administrator.
- Acts as the person, with their role: a connector can only read, write or delete what the team member’s PracticeHub role allows, including own-patients / own-calendar ringfencing.
- Cut-off on every call: a deactivated team member, or one whose role loses the permission, is refused on the next request — not at the next token refresh.
- Connections are visible and revocable in-app (Developers → API Keys → Connected AI apps); each authorisation and revocation is in the activity log.
Transport and abuse controls
- HTTPS is required for every API call and every webhook endpoint.
- Rate limits per credential (currently 600 requests/minute per key), with
X-RateLimit-*headers andRetry-Afteron429, so one integration cannot exhaust another’s allowance on the same account. - Every response carries an
X-Request-Id; quote it to support and it can be traced end to end. Idempotency-KeyonPOSTguarantees a retried create is not applied twice.
Logging and what is stored about your calls
- The account’s Developers → API Logs page is a filterable report of every API request: time, calling key or connector user, method, path, resource and record id, query-parameter names, status, the API’s error code and message, latency, response size, idempotent-replay flag, IP and user agent, request id — with usage, error and latency summaries and CSV export.
- Those log rows are PHI-free by construction: no request or response bodies are stored, query-parameter values are never stored, and the only free text kept is the API’s own error message (generic wording that never echoes submitted values).
- Log rows are retained for 90 days, then pruned automatically.
- Data changes made through the API are attributed in the record’s own history to the integration or team member that made them (for example an appointment log entry “Created via API: Booking widget”).
Webhooks (coming soon)
Not yet switched on for any account; the following describes the design that will ship.- Payloads are thin: event type, event id, timestamp, and the entity type + record id — no field values, so no PHI transits the delivery provider. Consumers fetch the record over the authenticated API.
- Every delivery is signed (Standard Webhooks); endpoints, signing secrets, delivery attempts and replays are managed by the account in its own portal.
- Use HTTPS endpoints.
Files
Files uploaded through the API are stored in PracticeHub’s object storage and served only via short-lived signed URLs to authenticated callers.Change management
- Additive only within the current version: new resources, attributes, event types and optional inputs may appear; nothing is renamed, removed or made required. Anything else ships as a new version with a published deprecation window.
- The OpenAPI document is generated from the running code and checked in CI for freshness and for breaking changes on every change.
- Every contract change is dated in the changelog.
- The legacy
/apicarriesDeprecationandSunsetheaders ahead of its retirement.
Your responsibilities
- Treat API keys as secrets: server-side only, never in client-side code, rotate on staff change, use read-only keys where writes aren’t needed.
- Verify webhook signatures before acting on a delivery.
- Use the least scope and the shortest key expiry that fits the integration.
- Data you fetch is your account’s patient data; handle and retain it under your own obligations to the clinic.
Certifications, penetration-test summaries, sub-processor lists and data-processing agreements are provided on request as part of contracting — support@practicehub.io.