Webhook Events
RxScale sends webhooks for the following event types:| Event Type | Description |
|---|---|
pharmacy_order_created | A new pharmacy order was created and assigned to your pharmacy |
pharmacy_order_updated | An existing pharmacy order’s status changed |
pharmacy_sku_stock_updated | A pharmacy SKU’s stock level changed |
patient_doctor_meeting_updated | A patient-doctor meeting changed lifecycle state |
HTTP Headers
Every webhook request includes the following HTTP headers:| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Webhook-Event | The event type (e.g. pharmacy_order_created) |
X-Webhook-Signature | HMAC-SHA256 signature of the request body (see Security) |
pharmacy_order_created
Sent when a new pharmacy order is created and assigned to your pharmacy. Possiblestatus values: init, waiting for pharmacy, pending review, in-progress, ready_for_pickup, completed
Payload Example
Field Reference
| Field | Type | Description |
|---|---|---|
data.uid | string | Pharmacy order UID |
data.status | string | Current order status |
data.name | string or null | Human-readable order name (e.g. #1001) |
data.data | object | Custom data attached to the order |
data.external_status | string | External status identifier |
data.created_at | integer | Unix timestamp of creation |
data.updated_at | integer | Unix timestamp of last update |
data.deleted_at | integer or null | Unix timestamp of soft-deletion, or null |
data.pharmacy | object | Pharmacy summary with uid and display_name |
data.order | object | Parent order with uid, delivery_address, and invoice_address |
data.order.shipping_costs_amount | integer or null | Shipping costs in cents. null when no shipping costs are available. |
data.order.shipping_costs_currency | string or null | ISO 4217 currency code for shipping costs, such as EUR. |
data.order.priority | integer | Priority hint for handling order sooner. Higher = more urgent. 0 means no special priority. |
data.delivery_type | object or null | Delivery type with uid, display_name, and identifier |
data.shop_shipping_methods | array | Shop shipping methods attached to the connected shop order. Empty array when the order has no shop shipping methods. |
data.shop_shipping_methods[].uid | string | Shop shipping method UID |
data.shop_shipping_methods[].display_name | string | Shop shipping method display name as configured on the shop |
data.shop_shipping_methods[].external_id | string or null | Identifier of the shipping method on the connected shop (e.g. the Shopify shipping line code) |
data.shop_shipping_methods[].pharmacy_mapping | object or null | Per-pharmacy mapping configured in the RxScale pharmacy settings, or null when no mapping has been configured for the receiving pharmacy yet. Configure this in the pharmacy Settings → Shipping method mappings screen. |
data.shop_shipping_methods[].pharmacy_mapping.pharmacy_uid | string | UID of the receiving pharmacy this mapping applies to |
data.shop_shipping_methods[].pharmacy_mapping.shipping_method_identifier_for_pharmacy | string | Pharmacy-specific identifier the receiving pharmacy expects for this shipping method (e.g. DHL_STANDARD). Use this value when handing the order off to your downstream shipping/labelling system. |
data.order_items | array | Items in the order |
data.order_items[].sku | object | SKU info including pzn, product_uid, product_display_name, standard_selling_unit, unit, and product_handle |
data.order_items[].sku.standard_selling_unit | number or null | Standard selling unit for the SKU |
data.order_items[].sku.unit | string or null | Unit for the SKU, such as ml or g |
data.order_items[].pharmacy_sku | object or null | Pharmacy-specific SKU data with uid, external_id, price (cents), stock |
data.order_items[].total_paid_amount | integer or null | Amount the patient paid for this line item, in cents (gross). null when no payment information is available. |
data.patient_data | object or null | Patient info with uid, display_name, email, date_of_birth, phone_number |
data.doctor_data | object or null | Doctor who signed the prescription, with uid and display_name |
data.prescription_file | object or null | Signed prescription PDF with filename and content_base64 |
data.prepaid | integer | 1 if the order has a physical (prepaid) prescription, 0 otherwise |
pharmacy_order_updated
Sent when an existing pharmacy order’s status changes. The payload structure is identical topharmacy_order_created. The status field reflects the new status.
Payload Example
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.
| Field | Type | Description |
|---|---|---|
data.order_items[].sku.shop_variation_id | string or null | Shopify variant ID |
data.order_items[].sku.shop_product_external_id | string or null | Shopify product ID |
data.fulfillment.uid | string | Fulfillment order UID |
data.fulfillment.external_id | string or null | External identifier for the fulfillment order |
data.fulfillment.items[].order_item.sku.shop_variation_id | string or null | Shopify variant ID |
data.fulfillment.items[].order_item.sku.shop_product_external_id | string or null | Shopify product ID |
data.fulfillment.order.uid | string | Parent order UID |
data.fulfillment.order.shop_order.uid | string | Shop order UID |
data.fulfillment.order.shop_order.external_id | string or null | External shop order identifier |
data.fulfillment.order.shop_order.shop_identifier | string | Shop identifier |
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
| Field | Type | Description |
|---|---|---|
data.uid | string | Pharmacy SKU UID |
data.pharmacy_uid | string | Pharmacy UID |
data.sku_uid | string | SKU UID |
data.external_id | string or null | External identifier in your own system |
data.price | integer | Price in cents |
data.stock | integer | Current stock level |
data.reserved_amount | integer | Units reserved against this SKU — sum of order item amounts across all in-flight pharmacy orders (i.e. orders not yet completed or cancelled). Useful to derive available stock as stock - reserved_amount. |
data.markup | integer | Markup value |
data.priority | integer | Priority level |
data.type | string | Pharmacy SKU type |
data.created_at | integer | Unix timestamp of creation |
data.updated_at | integer | Unix timestamp of last update |
data.deleted_at | integer or null | Unix timestamp of soft-deletion, or null |
data.sku | object | Nested SKU and product information |
data.sku.uid | string | SKU UID |
data.sku.display_name | string | SKU display name |
data.sku.pzn | string | Pharmazentralnummer (PZN) |
data.sku.product_uid | string | Parent product UID |
data.sku.product_display_name | string or null | Display name of the parent product |
data.sku.standard_selling_unit | number or null | Standard selling unit for the SKU |
data.sku.unit | string or null | Unit for the SKU, such as ml or g |
data.sku.product_handle | string or null | URL handle/slug of the parent product |
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.
| Field | Type | Description |
|---|---|---|
data.shop_identifier | string or null | Shop identifier |
data.sku.shop_variation_id | string or null | Shopify variant ID |
data.sku.shop_product_external_id | string or null | Shopify product ID |
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.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:
| Value | When emitted |
|---|---|
held | A scheduled appointment was held (the meeting window opened) |
confirmed | A scheduled appointment was confirmed |
expired | A scheduled appointment expired without being joined |
cancelled | A meeting was cancelled |
rebooked | A meeting was rebooked (a new meeting replaced this one) |
completed | An on-demand meeting was completed |
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
| Field | Type | Description |
|---|---|---|
data.organisation_uid | string | UID of the organisation the meeting belongs to |
data.meeting_uid | string | Unique identifier for the meeting |
data.change | string | The lifecycle transition that triggered this event — see the table above |
data.status | string or null | Current status of the meeting. null for on-demand meetings; use change for logic instead |
data.meeting_type | string | Type of meeting (e.g. consultation) |
data.meeting_format | string | Format of the meeting (e.g. digital) |
data.start_date | integer or null | Unix timestamp of the scheduled start (scheduled appointments only) |
data.end_date | integer or null | Unix timestamp of the planned end for scheduled appointments. This is the originally scheduled end time, not the actual end |
data.estimated_duration_minutes | integer or null | Estimated duration in minutes |
data.confirmed_at | integer or null | Unix timestamp of when the meeting was confirmed, or null |
data.cancelled_at | integer or null | Unix timestamp of cancellation, or null |
data.cancellation_reason | string or null | Reason for cancellation, or null |
data.expires_at | integer or null | Unix timestamp after which the meeting link expires, or null |
data.previous_meeting_uid | string or null | UID of the meeting this one was rebooked from, or null. Set when change is rebooked |
data.appointment_type_uid | string or null | UID of the appointment type (scheduled appointments only) |
data.doctor_uid | string or null | UID of the assigned doctor |
data.patient_profile_uid | string | UID of the patient profile. This is the only patient identifier in the payload — no PII (name, date of birth, or contact details) is included |
Subscribing
Subscribe via the Management API to receive this event: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.