Skip to main content
Limited rollout. Webhook delivery is live for a deliberately limited event set while it beds in: six events — patients.created/updated/deleted and appointments.created/updated/deleted. Payload shape, signing and delivery behaviour below apply to every event. Further resources’ events are announced in the changelog as the rollout expands; until a resource emits events, poll it with updated_at filters and deleted_entities (see Querying).
Instead of polling, subscribe an HTTPS endpoint and PracticeHub will call it when records change on the account. Events fire for changes made through the API, in the PracticeHub app by staff, and by background jobs alike. Bulk operations are the exception: CSV imports (and their reversal) and bulk tag or status changes do not emit an event per record — reconcile after one with updated_at filters.
Webhooks are available on accounts created on PracticeHub 2.0. Existing accounts get them when they complete their move to 2.0 — until then, poll deleted_entities and updated_at filters as before.
Accounts still using PracticeHub Classic alongside PracticeHub 2.0. Webhooks and deleted_entities tombstones are produced by PracticeHub 2.0. A change made in PracticeHub Classic — a patient edited, an appointment cancelled, a tag added there — produces no event and no tombstone. If the account works in both, poll updated_at for incremental syncs rather than relying on events alone.

Setting up an endpoint

1

Open the portal

In PracticeHub go to Developers → Webhooks. The page is the account’s webhook portal. Nothing is sent for an account until someone opens this page for the first time — that is what switches delivery on.
2

Add your endpoint

Enter your HTTPS URL, choose which event types it should receive (or all), and save. The portal shows the endpoint’s signing secret — copy it into your service.
3

Watch it work

The portal lists every delivery attempt with the response your endpoint returned, lets you replay any message, and can send a test event.

What you receive

Payloads are deliberately thin — the event type and the record’s id, never the record itself — so no clinical or personal data leaves PracticeHub through a webhook. Fetch the record from the API with your own key:
id is unique per event — use it to de-duplicate, since a delivery may be retried after a timeout. Events for one record are not guaranteed to arrive in order; the record you fetch is always current.

Event types

The current event set covers patients and appointments: A few cases worth knowing:
  • Creating a record sends one event. PracticeHub’s own follow-up writes while it creates a patient or an appointment are part of the create — you get .created, not .created then .updated.
  • Merging two patients sends patients.deleted for the record that was merged away and patients.updated for the one that was kept.
  • Restoring a deleted patient sends patients.updated, not patients.created — the id is the one you already know.
Several saves to one record within a single operation are reported once, and a change that merely fans out from another change (a group move updating every attendee, say) is reported for the record you changed, not for every row it touched. Events for further resources are announced in the changelog as the rollout expands — the list you can subscribe to is always current in the portal under Developers → Webhooks.

Verifying signatures

Every delivery is signed. Verify it before trusting it — the signature scheme is Standard Webhooks, so use the library for your language with the endpoint’s signing secret from the portal:
Rotate the secret from the portal at any time.

Delivery and retries

Respond with any 2xx within a few seconds — do the work afterwards. Non-2xx responses and timeouts are retried with exponential backoff over roughly a day; an endpoint that keeps failing is disabled and you are notified in the portal, where you can re-enable it and replay what was missed.