Skip to main content

Professional API: Webhooks

Have your own systems told when something happens in your practice, instead of polling for it.

How Webhooks Work Here

A signed POST to an endpoint you register.

The Shape of a Delivery

You register an HTTPS endpoint in the Developer section of your professional dashboard and choose which events it should receive. When one of those events occurs, Orchard72 sends a JSON POST to your endpoint, signed with a secret unique to that endpoint.

Anything other than a 2xx response counts as a failure and is retried. A delivery attempt is abandoned if your endpoint has not responded within ten seconds.

Note

Webhook access is an entitlement on your plan, separate from API access. If your endpoint never fires, check that your plan includes webhooks before debugging your own receiver.

The Professional Events

The sixteen events a professional endpoint can subscribe to.

Event Slugs

  • appointment.created: a new appointment has been booked with your practice
  • appointment.rescheduled: an existing appointment has moved
  • appointment.cancelled: an appointment has been cancelled
  • engagement_letter.signed: a client has signed an engagement letter
  • approach.received: someone has approached your practice through the platform
  • message.received: a new message has arrived in a conversation
  • referral.will_started: someone who arrived through your white-label partner page has started a will
  • referral.will_completed: a will started through your partner page has been signed and completed
  • client.created: a new client has been added to your practice
  • client.withdrawn: a client has withdrawn from your practice
  • will.status_changed: a client’s will has moved to a new status
  • will_review.requested: a client has asked for their will to be reviewed
  • invoice.issued: an invoice has been issued to a client
  • invoice.paid: an invoice has been paid
  • complaint.opened: a client has opened a complaint
  • task.due: a matter task that is not yet done falls due today

Tip

Subscribe only to the events you act on. Clearing an endpoint’s event list is also how you pause it without deleting it. Deleting the endpoint destroys its signing secret, which cannot be shown to you again.

Payloads

Identifiers and status, and nothing else.

What Is in the Body

A professional webhook payload carries the event slug, the identifier of the object that changed, named for it (for example appointment_id, client_id or invoice_id), and, where the object has one, its status. A few events add the identifier of the parent record as well: message.received carries conversation_id, task.due carries matter_id and will_review.requested carries will_id.

Client names, contact details, matter content and message bodies are never in the payload. That is deliberate: a webhook travels to an endpoint we do not control, so it carries only enough to tell you which record changed. Your receiver then fetches whatever detail it needs over the Professional API, authenticated as you and subject to the same consent rules.

Note

This means a webhook alone is never enough to act on. Treat it as a signal to fetch, not as the data itself.

Headers on Every Delivery

  • X-Webhook-Signature: the HMAC signature described below
  • X-Webhook-Event: the event slug, so you can route without parsing the body
  • X-Webhook-ID: a fresh identifier per delivery attempt, so it differs on every retry
  • X-Webhook-Timestamp: the delivery time in Unix seconds
  • webhook-id: a msg_-prefixed identifier for the event itself, which stays the same on every retry of it (Standard Webhooks)
  • Content-Type: application/json

Verifying the Signature

Prove the delivery came from us before you act on it.

How to Verify

  1. Take the raw request body bytes, exactly as received. Do not parse and re-serialise the JSON first, because any reordering or whitespace change breaks the signature
  2. Compute an HMAC-SHA256 of those bytes using your endpoint’s signing secret as the key, and render it as a lower-case hex digest
  3. Compare it with the X-Webhook-Signature header using a constant-time comparison, not ==
  4. Reject the delivery if they differ, and only then parse the body

Important

Only the body is signed. The timestamp header is not part of the signed string, so it cannot by itself prove freshness. If you need replay protection, record the webhook-id values you have already processed and ignore repeats. Do not key on X-Webhook-ID: it is new on every attempt, so a retry would never match it.

Retries and Failures

What happens when your endpoint is down.

The Backoff Schedule

A failed delivery is retried on a widening schedule: immediately, then after one minute, five minutes, thirty minutes, two hours, and thereafter once a day.

After ten consecutive failures the endpoint is deactivated and the account owner is emailed. Reactivate it from the Developer section once your receiver is healthy again.

Note

Retries replay the original body byte for byte, so the signature stays valid across attempts. It also means your receiver must be idempotent: the same event can legitimately arrive more than once.

Building a Reliable Receiver

  • Verify the signature, then acknowledge with a 2xx quickly and do the real work afterwards, because slow handlers time out and get retried
  • De-duplicate on webhook-id, which repeats on a retry, never on X-Webhook-ID, which does not
  • Fetch the detail you need from the Professional API rather than waiting for a richer payload
  • Monitor your endpoint, because ten consecutive failures will switch it off

Related Topics

Can’t find what you’re looking for?

Our support team is here to help. Contact us and we’ll get back to you as soon as possible.

Contact Support

We use cookies to improve your experience. See our Cookie Policy (opens in a new tab) for details.