Skip to main content

Webhook Events

RxScale sends webhooks for the following event types:
Event TypeDescription
pharmacy_order_createdA new pharmacy order was created and assigned to your pharmacy
pharmacy_order_updatedAn existing pharmacy order’s status changed
pharmacy_sku_stock_updatedA pharmacy SKU’s stock level changed
patient_doctor_meeting_updatedA patient-doctor meeting changed lifecycle state

HTTP Headers

Every webhook request includes the following HTTP headers:
HeaderDescription
Content-TypeAlways application/json
X-Webhook-EventThe event type (e.g. pharmacy_order_created)
X-Webhook-SignatureHMAC-SHA256 signature of the request body (see Security)
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. Possible status values: init, waiting for pharmacy, pending review, in-progress, ready_for_pickup, completed

Payload Example

{
  "event_type": "pharmacy_order_created",
  "timestamp": 1711900000,
  "payload_version": "1",
  "data": {
    "uid": "po-abc123",
    "status": "init",
    "name": "#1001",
    "data": {},
    "external_status": "OPEN",
    "created_at": 1711899000,
    "updated_at": 1711899000,
    "deleted_at": null,
    "pharmacy": {
      "uid": "ph-xyz",
      "display_name": "City Pharmacy"
    },
    "order": {
      "uid": "ord-123",
      "delivery_address": {
        "first_name": "Max",
        "last_name": "Mustermann",
        "street": "Hauptstr.",
        "house_number": "1",
        "zip_code": "10115",
        "city": "Berlin",
        "country": "Germany",
        "additional_address": null
      },
      "invoice_address": {
        "first_name": "Max",
        "last_name": "Mustermann",
        "street": "Hauptstr.",
        "house_number": "1",
        "zip_code": "10115",
        "city": "Berlin",
        "country": "Germany",
        "additional_address": null
      },
      "shipping_costs_amount": 499,
      "shipping_costs_currency": "EUR",
      "priority": 5
    },
    "delivery_type": {
      "uid": "dt-001",
      "display_name": "Standard Shipping",
      "identifier": "standard"
    },
    "shop_shipping_methods": [
      {
        "uid": "ssm-001",
        "display_name": "DHL Standard",
        "external_id": "shopify-standard",
        "pharmacy_mapping": {
          "pharmacy_uid": "ph-xyz",
          "shipping_method_identifier_for_pharmacy": "DHL_STANDARD"
        }
      }
    ],
    "order_items": [
      {
        "uid": "oi-789",
        "amount": 1,
        "sku": {
          "uid": "sku-456",
          "display_name": "Medication X 100mg",
          "pzn": "12345678",
          "product_uid": "prod-789",
          "product_display_name": "Medication X",
          "standard_selling_unit": 1.0,
          "unit": "ml",
          "product_handle": "medication-x"
        },
        "pharmacy_sku": {
          "uid": "psku-456",
          "external_id": "EXT-001",
          "price": 1299,
          "stock": 50
        },
        "total_paid_amount": 1299
      }
    ],
    "patient_data": {
      "uid": "pat-123",
      "display_name": "Max Mustermann",
      "email": "max@example.com",
      "date_of_birth": "15.06.1990",
      "phone_number": "+49 170 1234567"
    },
    "doctor_data": {
      "uid": "doc-456",
      "display_name": "Dr. Schmidt"
    },
    "prescription_file": {
      "filename": "prescription_001.pdf",
      "content_base64": "JVBERi0xLjQK..."
    },
    "prepaid": 1
  }
}

Field Reference

FieldTypeDescription
data.uidstringPharmacy order UID
data.statusstringCurrent order status
data.namestring or nullHuman-readable order name (e.g. #1001)
data.dataobjectCustom data attached to the order
data.external_statusstringExternal status identifier
data.created_atintegerUnix timestamp of creation
data.updated_atintegerUnix timestamp of last update
data.deleted_atinteger or nullUnix timestamp of soft-deletion, or null
data.pharmacyobjectPharmacy summary with uid and display_name
data.orderobjectParent order with uid, delivery_address, and invoice_address
data.order.shipping_costs_amountinteger or nullShipping costs in cents. null when no shipping costs are available.
data.order.shipping_costs_currencystring or nullISO 4217 currency code for shipping costs, such as EUR.
data.order.priorityintegerPriority hint for handling order sooner. Higher = more urgent. 0 means no special priority.
data.delivery_typeobject or nullDelivery type with uid, display_name, and identifier
data.shop_shipping_methodsarrayShop shipping methods attached to the connected shop order. Empty array when the order has no shop shipping methods.
data.shop_shipping_methods[].uidstringShop shipping method UID
data.shop_shipping_methods[].display_namestringShop shipping method display name as configured on the shop
data.shop_shipping_methods[].external_idstring or nullIdentifier of the shipping method on the connected shop (e.g. the Shopify shipping line code)
data.shop_shipping_methods[].pharmacy_mappingobject or nullPer-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_uidstringUID of the receiving pharmacy this mapping applies to
data.shop_shipping_methods[].pharmacy_mapping.shipping_method_identifier_for_pharmacystringPharmacy-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_itemsarrayItems in the order
data.order_items[].skuobjectSKU info including pzn, product_uid, product_display_name, standard_selling_unit, unit, and product_handle
data.order_items[].sku.standard_selling_unitnumber or nullStandard selling unit for the SKU
data.order_items[].sku.unitstring or nullUnit for the SKU, such as ml or g
data.order_items[].pharmacy_skuobject or nullPharmacy-specific SKU data with uid, external_id, price (cents), stock
data.order_items[].total_paid_amountinteger or nullAmount the patient paid for this line item, in cents (gross). null when no payment information is available.
data.patient_dataobject or nullPatient info with uid, display_name, email, date_of_birth, phone_number
data.doctor_dataobject or nullDoctor who signed the prescription, with uid and display_name
data.prescription_fileobject or nullSigned prescription PDF with filename and content_base64
data.prepaidinteger1 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 to pharmacy_order_created. The status field reflects the new status.

Payload Example

{
  "event_type": "pharmacy_order_updated",
  "timestamp": 1711910000,
  "payload_version": "1",
  "data": {
    "uid": "po-abc123",
    "status": "in-progress",
    "name": "#1001",
    "data": {},
    "external_status": "IN_PROGRESS",
    "created_at": 1711899000,
    "updated_at": 1711910000,
    "deleted_at": null,
    "pharmacy": {
      "uid": "ph-xyz",
      "display_name": "City Pharmacy"
    },
    "order": {
      "uid": "ord-123",
      "delivery_address": {
        "first_name": "Max",
        "last_name": "Mustermann",
        "street": "Hauptstr.",
        "house_number": "1",
        "zip_code": "10115",
        "city": "Berlin",
        "country": "Germany",
        "additional_address": null
      },
      "invoice_address": {
        "first_name": "Max",
        "last_name": "Mustermann",
        "street": "Hauptstr.",
        "house_number": "1",
        "zip_code": "10115",
        "city": "Berlin",
        "country": "Germany",
        "additional_address": null
      },
      "shipping_costs_amount": 499,
      "shipping_costs_currency": "EUR",
      "priority": 5
    },
    "delivery_type": {
      "uid": "dt-001",
      "display_name": "Standard Shipping",
      "identifier": "standard"
    },
    "shop_shipping_methods": [
      {
        "uid": "ssm-001",
        "display_name": "DHL Standard",
        "external_id": "shopify-standard",
        "pharmacy_mapping": {
          "pharmacy_uid": "ph-xyz",
          "shipping_method_identifier_for_pharmacy": "DHL_STANDARD"
        }
      }
    ],
    "order_items": [
      {
        "uid": "oi-789",
        "amount": 1,
        "sku": {
          "uid": "sku-456",
          "display_name": "Medication X 100mg",
          "pzn": "12345678",
          "product_uid": "prod-789",
          "product_display_name": "Medication X",
          "standard_selling_unit": 1.0,
          "unit": "ml",
          "product_handle": "medication-x"
        },
        "pharmacy_sku": {
          "uid": "psku-456",
          "external_id": "EXT-001",
          "price": 1299,
          "stock": 50
        },
        "total_paid_amount": 1299
      }
    ],
    "patient_data": {
      "uid": "pat-123",
      "display_name": "Max Mustermann",
      "email": "max@example.com",
      "date_of_birth": "15.06.1990",
      "phone_number": "+49 170 1234567"
    },
    "doctor_data": {
      "uid": "doc-456",
      "display_name": "Dr. Schmidt"
    },
    "prescription_file": {
      "filename": "prescription_001.pdf",
      "content_base64": "JVBERi0xLjQK..."
    },
    "prepaid": 1
  }
}

Organisation-Level Webhooks

When the webhook subscription was created via the Management API (organisation-level), order events include additional data:
  • The sku objects inside order_items and fulfillment.items are enriched with Shopify identifiers (shop_variation_id, shop_product_external_id).
  • A fulfillment object is added with fulfillment order details.
{
  "event_type": "pharmacy_order_updated",
  "timestamp": 1711910000,
  "payload_version": "1",
  "data": {
    "uid": "po-abc123",
    "status": "in-progress",
    "...": "... same fields as above ...",
    "order_items": [
      {
        "uid": "oi-789",
        "amount": 1,
        "sku": {
          "uid": "sku-456",
          "display_name": "Medication X 100mg",
          "pzn": "12345678",
          "product_uid": "prod-789",
          "product_display_name": "Medication X",
          "standard_selling_unit": 1.0,
          "unit": "ml",
          "product_handle": "medication-x",
          "shop_variation_id": "48372910234",
          "shop_product_external_id": "93847261045"
        },
        "pharmacy_sku": {
          "uid": "psku-456",
          "external_id": "EXT-001",
          "price": 1299,
          "stock": 50
        },
        "total_paid_amount": 1299
      }
    ],
    "fulfillment": {
      "uid": "fo-abc123",
      "external_id": "EXT-FO-001",
      "items": [
        {
          "uid": "foi-001",
          "amount": 1,
          "status": "init",
          "external_id": "EXT-FOI-001",
          "order_item": {
            "uid": "oi-789",
            "amount": 1,
            "sku": {
              "uid": "sku-456",
              "display_name": "Medication X 100mg",
              "pzn": "12345678",
              "product_uid": "prod-789",
              "product_display_name": "Medication X",
              "standard_selling_unit": 1.0,
              "unit": "ml",
              "product_handle": "medication-x",
              "shop_variation_id": "48372910234",
              "shop_product_external_id": "93847261045"
            }
          }
        }
      ],
      "order": {
        "uid": "ord-123",
        "shop_order": {
          "uid": "so-456",
          "external_id": "SHOP-789",
          "shop_identifier": "my-shopify-store"
        }
      }
    }
  }
}
FieldTypeDescription
data.order_items[].sku.shop_variation_idstring or nullShopify variant ID
data.order_items[].sku.shop_product_external_idstring or nullShopify product ID
data.fulfillment.uidstringFulfillment order UID
data.fulfillment.external_idstring or nullExternal identifier for the fulfillment order
data.fulfillment.items[].order_item.sku.shop_variation_idstring or nullShopify variant ID
data.fulfillment.items[].order_item.sku.shop_product_external_idstring or nullShopify product ID
data.fulfillment.order.uidstringParent order UID
data.fulfillment.order.shop_order.uidstringShop order UID
data.fulfillment.order.shop_order.external_idstring or nullExternal shop order identifier
data.fulfillment.order.shop_order.shop_identifierstringShop 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}/stock or 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

{
  "event_type": "pharmacy_sku_stock_updated",
  "timestamp": 1711900000,
  "payload_version": "1",
  "data": {
    "uid": "psku-abc123",
    "pharmacy_uid": "ph-xyz",
    "sku_uid": "sku-456",
    "external_id": "EXT-001",
    "price": 1299,
    "stock": 45,
    "reserved_amount": 7,
    "markup": 0,
    "priority": 0,
    "type": "default",
    "created_at": 1711800000,
    "updated_at": 1711900000,
    "deleted_at": null,
    "sku": {
      "uid": "sku-456",
      "display_name": "Medication X 100mg",
      "pzn": "12345678",
      "product_uid": "prod-789",
      "product_display_name": "Medication X",
      "standard_selling_unit": 1.0,
      "unit": "ml",
      "product_handle": "medication-x"
    }
  }
}

Field Reference

FieldTypeDescription
data.uidstringPharmacy SKU UID
data.pharmacy_uidstringPharmacy UID
data.sku_uidstringSKU UID
data.external_idstring or nullExternal identifier in your own system
data.priceintegerPrice in cents
data.stockintegerCurrent stock level
data.reserved_amountintegerUnits 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.markupintegerMarkup value
data.priorityintegerPriority level
data.typestringPharmacy SKU type
data.created_atintegerUnix timestamp of creation
data.updated_atintegerUnix timestamp of last update
data.deleted_atinteger or nullUnix timestamp of soft-deletion, or null
data.skuobjectNested SKU and product information
data.sku.uidstringSKU UID
data.sku.display_namestringSKU display name
data.sku.pznstringPharmazentralnummer (PZN)
data.sku.product_uidstringParent product UID
data.sku.product_display_namestring or nullDisplay name of the parent product
data.sku.standard_selling_unitnumber or nullStandard selling unit for the SKU
data.sku.unitstring or nullUnit for the SKU, such as ml or g
data.sku.product_handlestring or nullURL 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 sku object is enriched with Shopify identifiers (shop_variation_id, shop_product_external_id).
  • A shop_identifier field is added at the data level.
{
  "event_type": "pharmacy_sku_stock_updated",
  "timestamp": 1711900000,
  "payload_version": "1",
  "data": {
    "uid": "psku-abc123",
    "pharmacy_uid": "ph-xyz",
    "sku_uid": "sku-456",
    "external_id": "EXT-001",
    "price": 1299,
    "stock": 45,
    "reserved_amount": 7,
    "markup": 0,
    "priority": 0,
    "type": "default",
    "created_at": 1711800000,
    "updated_at": 1711900000,
    "deleted_at": null,
    "shop_identifier": "my-shopify-store",
    "sku": {
      "uid": "sku-456",
      "display_name": "Medication X 100mg",
      "pzn": "12345678",
      "product_uid": "prod-789",
      "product_display_name": "Medication X",
      "standard_selling_unit": 1.0,
      "unit": "ml",
      "product_handle": "medication-x",
      "shop_variation_id": "48372910234",
      "shop_product_external_id": "93847261045"
    }
  }
}
FieldTypeDescription
data.shop_identifierstring or nullShop identifier
data.sku.shop_variation_idstring or nullShopify variant ID
data.sku.shop_product_external_idstring or nullShopify 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). Possible change values:
ValueWhen emitted
heldA scheduled appointment was held (the meeting window opened)
confirmedA scheduled appointment was confirmed
expiredA scheduled appointment expired without being joined
cancelledA meeting was cancelled
rebookedA meeting was rebooked (a new meeting replaced this one)
completedAn 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

{
  "event_type": "patient_doctor_meeting_updated",
  "timestamp": 1893456000,
  "payload_version": "1",
  "data": {
    "organisation_uid": "org-abc123",
    "meeting_uid": "m-e2e-1",
    "change": "confirmed",
    "status": "confirmed",
    "meeting_type": "consultation",
    "meeting_format": "digital",
    "start_date": 1893456000,
    "end_date": 1893456900,
    "estimated_duration_minutes": 15,
    "confirmed_at": 1893450000,
    "cancelled_at": null,
    "cancellation_reason": null,
    "expires_at": null,
    "previous_meeting_uid": null,
    "appointment_type_uid": "at-1",
    "doctor_uid": "doc-1",
    "patient_profile_uid": "pat-1"
  }
}

Field Reference

FieldTypeDescription
data.organisation_uidstringUID of the organisation the meeting belongs to
data.meeting_uidstringUnique identifier for the meeting
data.changestringThe lifecycle transition that triggered this event — see the table above
data.statusstring or nullCurrent status of the meeting. null for on-demand meetings; use change for logic instead
data.meeting_typestringType of meeting (e.g. consultation)
data.meeting_formatstringFormat of the meeting (e.g. digital)
data.start_dateinteger or nullUnix timestamp of the scheduled start (scheduled appointments only)
data.end_dateinteger or nullUnix timestamp of the planned end for scheduled appointments. This is the originally scheduled end time, not the actual end
data.estimated_duration_minutesinteger or nullEstimated duration in minutes
data.confirmed_atinteger or nullUnix timestamp of when the meeting was confirmed, or null
data.cancelled_atinteger or nullUnix timestamp of cancellation, or null
data.cancellation_reasonstring or nullReason for cancellation, or null
data.expires_atinteger or nullUnix timestamp after which the meeting link expires, or null
data.previous_meeting_uidstring or nullUID of the meeting this one was rebooked from, or null. Set when change is rebooked
data.appointment_type_uidstring or nullUID of the appointment type (scheduled appointments only)
data.doctor_uidstring or nullUID of the assigned doctor
data.patient_profile_uidstringUID 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:
curl -X POST "https://api.rxscale.com/v1/management/notification-subscriptions/" \
  -H "X-API-Key: your-api-key-here" \
  -H "Content-Type: application/json" \
  -d '{
    "notification_type": "patient_doctor_meeting_updated",
    "target": "https://your-system.com/webhooks/rxscale"
  }'

Delivery and Idempotency

Webhooks are delivered at least once. Your endpoint should treat deliveries as idempotent using the combination of data.meeting_uid and data.change as the unique key — retried deliveries will carry the same values.