Webhook Events
RxScale sends webhooks for the following event types:HTTP Headers
Every webhook request includes the following HTTP headers:
If you configured a custom header when creating the subscription, it will also be included.
pharmacy_order_created
Sent when a new pharmacy order is created and assigned to your pharmacy.Pharmacy orders are created for over-the-counter (OTC) purchases too, not only for prescription-based orders — any fulfillment routed to your pharmacy triggers this event, whether or not it includes a prescription. For an OTC-only order,
data.doctor_data and data.prescription_file are null, and data.prepaid is 0.data.shipments is always present. On create it is an empty array — pharmacies have not shipped yet. After the pharmacy adds parcels (Pharmacy Portal, or complete_order with tracking_links), later pharmacy_order_updated deliveries include those shipments.status values: init, waiting for pharmacy, pending review, in-progress, ready_for_pickup, completed
Payload Example
Field Reference
shipping_costs_amount and unpaid_shipping_costs_amount are different fields — the 0-never-null guarantee applies only to the first.data.order.shipping_costs_amount is always an integer: 0 when no shipping is charged, never null.unpaid_shipping_costs_amount is a separate, internal shipping-cost override that is nullable and is not part of the documented webhook contract. If you see it in a payload, do not apply the shipping_costs_amount guarantee to it: it may be absent or null, and null there does not mean “no shipping costs”. Use shipping_costs_amount for shipping reconciliation, and handle unpaid_shipping_costs_amount as an optional, possibly-null value if you read it at all.pharmacy_order_updated
Sent when an existing pharmacy order changes. That includes:- Status transitions (for example
in-progress→completed, or a cancellation). - The pharmacy adding one or more shipments — from the Pharmacy Portal, or by completing the order through the External Pharmacy API with
tracking_links.
pharmacy_order_created. The status field reflects the current status, and data.shipments lists every shipment currently on the order (not only the one just added).
There is no separate pharmacy_order_shipment_created event. Subscribe to pharmacy_order_updated and read data.shipments.
Payload Example
Shipments
data.shipments is the list of parcels the pharmacy has recorded on this order. Use it to pick up tracking details when a pharmacy ships — including split shipments (more than one parcel).
When the array is filled
- Completing the order via
PATCH /v1/external_pharmacy_api/pharmacy_orders/{uid}/complete_orderwithtracking_linkscreates a shipment and then sendspharmacy_order_updated. - Adding a shipment in the Pharmacy Portal (manual tracking, or a booked carrier label that is followed by an order update) also leaves the shipment on the order. The next
pharmacy_order_updatedpayload includes all current shipments, ordered bysequence_number. pharmacy_order_createdalmost always has"shipments": []. Do not treat a missing tracking URL on create as an error.
- Treat
uidas the stable identity of a parcel. A laterpharmacy_order_updatedmay add further entries; existing UIDs stay the same. - Prefer
tracking_urlfor customer-facing tracking.tracking_numberandcarrier_nameare present when the pharmacy or carrier supplied them; either can benullon a newly created placeholder shipment. is_testistrueonly when the parcel was booked against a carrier sandbox (no real dispatch). Ignore test shipments for live fulfillment.return_tracking_numberandreturn_label_expiry(YYYY-MM-DD) are set only after a return label is issued; otherwise they arenull.
Internal label-file locations are not included in the webhook. Use
tracking_url / tracking_number for tracking, not storage paths.Organisation-Level Webhooks
When the webhook subscription was created via the Management API (organisation-level), order events include additional data:- The
skuobjects insideorder_itemsandfulfillment.itemsare enriched with Shopify identifiers (shop_variation_id,shop_product_external_id). - A
fulfillmentobject is added with fulfillment order details.
The
fulfillment field and the Shopify identifiers (shop_variation_id, shop_product_external_id) inside sku objects are only present in organisation-level webhook deliveries. Pharmacy-level webhooks do not include these fields.pharmacy_sku_stock_updated
Sent when a pharmacy SKU’s stock level changes. This includes:- Direct stock updates via the Pharmacy API (
PATCH /v1/.../pharmacy_skus/{uid}/stockor inventory endpoints). - Automatic stock reduction when a pharmacy order is completed. This fires for both manual completion (via the pharmacy UI / API) and automatic completion when RxScale detects the order has reached a shipped or completed state via its status-check integration with the pharmacy’s backend. One event is emitted per pharmacy SKU on the completed order.
Payload Example
Field Reference
Organisation-Level Webhooks
When the webhook subscription was created via the Management API (organisation-level), stock events include additional data:- The
skuobject is enriched with Shopify identifiers (shop_variation_id,shop_product_external_id). - A
shop_identifierfield is added at thedatalevel.
The
shop_identifier field and the Shopify identifiers (shop_variation_id, shop_product_external_id) inside the sku object are only present in organisation-level webhook deliveries. Pharmacy-level webhooks do not include these fields.appointment_reminder_due
Sent when a configured appointment reminder becomes due. This event is delivered to organisation-level webhook subscriptions only.Reminders can also carry direct action links for the patient (join, reschedule, cancel) via RxScale’s own email/SMS content. The
rebook_allowed and cancel_allowed fields below tell you whether those actions are currently available — they are only ever true when recipient_role is patient.Payload Example
Field Reference
patient_doctor_meeting_updated
Sent when a patient-doctor meeting changes lifecycle state. This event is delivered to organisation-level webhook subscriptions only (registered via the Management API). Possiblechange values:
Use
change as the authoritative indicator of what happened. status reflects the meeting’s current database status and is null for on-demand meetings.Payload Example
Field Reference
Subscribing
Subscribe via the Management API to receive this event:Email notifications
Separately from webhooks, an organisation can have RxScale email the patient, the doctor, and/or its admins when a meeting is confirmed, cancelled, or rescheduled. Admins configure that from the Notifications tab in the admin portal, and it is off by default.confirmed is subscribable
independently of the other two changes — enabling it does not require also enabling cancellation
or rescheduling emails.
This does not change webhook behaviour. The event still fires on every transition listed
above, with the same payload, whether or not any email subscription exists. The webhook payload
itself is unchanged by this feature.
One difference is worth planning for: a reschedule publishes two events — cancelled for the
old meeting and rebooked for the new one — but sends at most one email, the rescheduling
one. If you mirror this stream into your own patient messaging, apply the same rule, or the
patient hears “cancelled” and then “moved”. confirmed is not part of a reschedule and has no
such pairing: it publishes once, for a fresh booking, and sends at most one confirmation email.
Delivery and Idempotency
Webhooks are delivered at least once. Your endpoint should treat deliveries as idempotent using the combination ofdata.meeting_uid and data.change as the unique key — retried deliveries will carry the same values.