Zum Hauptinhalt springen

Webhook-Ereignisse

RxScale sendet Webhooks für die folgenden Ereignistypen:
EreignistypBeschreibung
pharmacy_order_createdEine neue Apothekenbestellung wurde erstellt und Ihrer Apotheke zugewiesen
pharmacy_order_updatedDer Status einer bestehenden Apothekenbestellung hat sich geändert
pharmacy_sku_stock_updatedDer Lagerbestand einer Apotheken-SKU hat sich geändert
patient_doctor_meeting_updatedEine Patient-Arzt-Besprechung hat ihren Lebenszyklus-Status geändert

HTTP-Header

Jede Webhook-Anfrage enthält die folgenden HTTP-Header:
HeaderBeschreibung
Content-TypeImmer application/json
X-Webhook-EventDer Ereignistyp (z.B. pharmacy_order_created)
X-Webhook-SignatureHMAC-SHA256-Signatur des Anfrageinhalts (siehe Sicherheit)
Falls Sie beim Erstellen des Abonnements einen benutzerdefinierten Header konfiguriert haben, wird dieser ebenfalls mitgesendet.

pharmacy_order_created

Wird gesendet, wenn eine neue Apothekenbestellung erstellt und Ihrer Apotheke zugewiesen wird. Mögliche status-Werte: init, waiting for pharmacy, pending review, in-progress, ready_for_pickup, completed

Payload-Beispiel

{
  "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
  }
}

Feldreferenz

FeldTypBeschreibung
data.uidstringUID der Apothekenbestellung
data.statusstringAktueller Bestellstatus
data.namestring oder nullLesbarer Bestellname (z.B. #1001)
data.dataobjectBenutzerdefinierte Daten der Bestellung
data.external_statusstringExterner Status-Bezeichner
data.created_atintegerUnix-Zeitstempel der Erstellung
data.updated_atintegerUnix-Zeitstempel der letzten Aktualisierung
data.deleted_atinteger oder nullUnix-Zeitstempel der Löschung oder null
data.pharmacyobjectApothekenzusammenfassung mit uid und display_name
data.orderobjectÜbergeordnete Bestellung mit uid, delivery_address und invoice_address
data.order.shipping_costs_amountinteger oder nullVersandkosten in Cent. null, wenn keine Versandkosten verfügbar sind.
data.order.shipping_costs_currencystring oder nullISO-4217-Währungscode der Versandkosten, z.B. EUR.
data.order.priorityintegerPrioritätshinweis für die bevorzugte Bearbeitung. Höher = dringender. 0 bedeutet keine besondere Priorität.
data.delivery_typeobject oder nullVersandart mit uid, display_name und identifier
data.shop_shipping_methodsarrayVersandmethoden des verbundenen Shop-Bestellauftrags. Leeres Array, wenn keine Shop-Versandmethoden vorliegen.
data.shop_shipping_methods[].uidstringUID der Shop-Versandmethode
data.shop_shipping_methods[].display_namestringAnzeigename der Versandmethode aus dem Shop
data.shop_shipping_methods[].external_idstring oder nullBezeichner der Versandmethode im verbundenen Shop (z.B. der Shopify-Shipping-Line-Code)
data.shop_shipping_methods[].pharmacy_mappingobject oder nullApothekenspezifisches Mapping aus den RxScale-Apothekeneinstellungen, oder null, wenn für die empfangende Apotheke noch kein Mapping konfiguriert wurde. Konfiguriert wird dies im Apotheken-Bildschirm Einstellungen → Versandarten-Zuordnung.
data.shop_shipping_methods[].pharmacy_mapping.pharmacy_uidstringUID der empfangenden Apotheke, für die dieses Mapping gilt
data.shop_shipping_methods[].pharmacy_mapping.shipping_method_identifier_for_pharmacystringApothekenspezifischer Bezeichner, den die empfangende Apotheke für diese Versandmethode erwartet (z.B. DHL_STANDARD). Verwenden Sie diesen Wert, wenn Sie die Bestellung an Ihr nachgelagertes Versand-/Label-System übergeben.
data.order_itemsarrayArtikel der Bestellung
data.order_items[].skuobjectSKU-Informationen inkl. pzn, product_uid, product_display_name, standard_selling_unit, unit und product_handle
data.order_items[].sku.standard_selling_unitnumber oder nullStandard-Verkaufseinheit der SKU
data.order_items[].sku.unitstring oder nullEinheit der SKU, z.B. ml oder g
data.order_items[].pharmacy_skuobject oder nullApothekenspezifische SKU-Daten mit uid, external_id, price (Cent), stock
data.order_items[].total_paid_amountinteger oder nullVom Patienten gezahlter Betrag für diese Position in Cent (brutto). null, wenn keine Zahlungsinformationen verfügbar sind.
data.patient_dataobject oder nullPatienteninformationen mit uid, display_name, email, date_of_birth, phone_number
data.doctor_dataobject oder nullArzt, der das Rezept signiert hat, mit uid und display_name
data.prescription_fileobject oder nullSigniertes Rezept-PDF mit filename und content_base64
data.prepaidinteger1 wenn die Bestellung ein physisches (vorausbezahltes) Rezept hat, sonst 0

pharmacy_order_updated

Wird gesendet, wenn sich der Status einer bestehenden Apothekenbestellung ändert. Die Payload-Struktur ist identisch mit pharmacy_order_created. Das Feld status enthält den neuen Status.

Payload-Beispiel

{
  "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
  }
}

Webhooks auf Organisationsebene

Wenn das Webhook-Abonnement über die Management API (auf Organisationsebene) erstellt wurde, enthalten Bestellereignisse zusätzliche Daten:
  • Die sku-Objekte in order_items und fulfillment.items werden um Shopify-Bezeichner (shop_variation_id, shop_product_external_id) erweitert.
  • Ein fulfillment-Objekt mit Details zur Fulfillment-Bestellung wird hinzugefügt.
{
  "event_type": "pharmacy_order_updated",
  "timestamp": 1711910000,
  "payload_version": "1",
  "data": {
    "uid": "po-abc123",
    "status": "in-progress",
    "...": "... gleiche Felder wie oben ...",
    "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"
        }
      }
    }
  }
}
FeldTypBeschreibung
data.order_items[].sku.shop_variation_idstring oder nullShopify-Varianten-ID
data.order_items[].sku.shop_product_external_idstring oder nullShopify-Produkt-ID
data.fulfillment.uidstringUID der Fulfillment-Bestellung
data.fulfillment.external_idstring oder nullExterner Bezeichner der Fulfillment-Bestellung
data.fulfillment.items[].order_item.sku.shop_variation_idstring oder nullShopify-Varianten-ID
data.fulfillment.items[].order_item.sku.shop_product_external_idstring oder nullShopify-Produkt-ID
data.fulfillment.order.uidstringUID der übergeordneten Bestellung
data.fulfillment.order.shop_order.uidstringUID der Shop-Bestellung
data.fulfillment.order.shop_order.external_idstring oder nullExterner Bezeichner der Shop-Bestellung
data.fulfillment.order.shop_order.shop_identifierstringShop-Bezeichner
Das fulfillment-Feld und die Shopify-Bezeichner (shop_variation_id, shop_product_external_id) in sku-Objekten sind nur in Webhook-Zustellungen auf Organisationsebene enthalten. Webhooks auf Apothekenebene enthalten diese Felder nicht.

pharmacy_sku_stock_updated

Wird gesendet, wenn sich der Lagerbestand einer Apotheken-SKU ändert. Dies umfasst:
  • Direkte Bestandsaktualisierungen über die Pharmacy-API (PATCH /v1/.../pharmacy_skus/{uid}/stock oder Inventar-Endpunkte).
  • Automatische Bestandsreduzierung bei Abschluss einer Apothekenbestellung. Dies wird sowohl beim manuellen Abschluss (über die Apotheken-Oberfläche / API) als auch beim automatischen Abschluss ausgelöst, wenn RxScale über die Statusabfrage-Integration mit dem Backend der Apotheke erkennt, dass die Bestellung versendet oder abgeschlossen wurde. Pro Apotheken-SKU der abgeschlossenen Bestellung wird ein Event emittiert.

Payload-Beispiel

{
  "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"
    }
  }
}

Feldreferenz

FeldTypBeschreibung
data.uidstringUID der Apotheken-SKU
data.pharmacy_uidstringUID der Apotheke
data.sku_uidstringUID der SKU
data.external_idstring oder nullExterner Bezeichner in Ihrem eigenen System
data.priceintegerPreis in Cent
data.stockintegerAktueller Lagerbestand
data.reserved_amountintegerFür diese SKU reservierte Einheiten — Summe der Bestellpositionsmengen aller in Bearbeitung befindlichen Apothekenbestellungen (also Bestellungen, die weder abgeschlossen noch storniert sind). Verfügbarer Bestand kann als stock - reserved_amount berechnet werden.
data.markupintegerAufschlagswert
data.priorityintegerPrioritätsstufe
data.typestringTyp der Apotheken-SKU
data.created_atintegerUnix-Zeitstempel der Erstellung
data.updated_atintegerUnix-Zeitstempel der letzten Aktualisierung
data.deleted_atinteger oder nullUnix-Zeitstempel der Löschung oder null
data.skuobjectVerschachtelte SKU- und Produktinformationen
data.sku.uidstringUID der SKU
data.sku.display_namestringAnzeigename der SKU
data.sku.pznstringPharmazentralnummer (PZN)
data.sku.product_uidstringUID des übergeordneten Produkts
data.sku.product_display_namestring oder nullAnzeigename des übergeordneten Produkts
data.sku.standard_selling_unitnumber oder nullStandard-Verkaufseinheit der SKU
data.sku.unitstring oder nullEinheit der SKU, z.B. ml oder g
data.sku.product_handlestring oder nullURL-Handle/Slug des übergeordneten Produkts

Webhooks auf Organisationsebene

Wenn das Webhook-Abonnement über die Management API (auf Organisationsebene) erstellt wurde, enthalten Lagerbestandsereignisse zusätzliche Daten:
  • Das sku-Objekt wird um Shopify-Bezeichner (shop_variation_id, shop_product_external_id) erweitert.
  • Ein shop_identifier-Feld wird auf der data-Ebene hinzugefügt.
{
  "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"
    }
  }
}
FeldTypBeschreibung
data.shop_identifierstring oder nullShop-Bezeichner
data.sku.shop_variation_idstring oder nullShopify-Varianten-ID
data.sku.shop_product_external_idstring oder nullShopify-Produkt-ID
Das shop_identifier-Feld und die Shopify-Bezeichner (shop_variation_id, shop_product_external_id) im sku-Objekt sind nur in Webhook-Zustellungen auf Organisationsebene enthalten. Webhooks auf Apothekenebene enthalten diese Felder nicht.

patient_doctor_meeting_updated

Wird gesendet, wenn eine Patient-Arzt-Besprechung ihren Lebenszyklus-Status ändert. Dieses Ereignis wird ausschließlich an Webhook-Abonnements auf Organisationsebene geliefert (registriert über die Management API). Mögliche change-Werte:
WertWann ausgelöst
heldEin geplanter Termin wurde gehalten (das Besprechungsfenster öffnete sich)
confirmedEin geplanter Termin wurde bestätigt
expiredEin geplanter Termin ist abgelaufen, ohne beigetreten zu sein
cancelledEine Besprechung wurde storniert
rebookedEine Besprechung wurde umgebucht (eine neue Besprechung hat diese ersetzt)
completedEine On-Demand-Besprechung wurde abgeschlossen
Verwenden Sie change als maßgeblichen Indikator für das eingetretene Ereignis. status spiegelt den aktuellen Datenbankstatus der Besprechung wider und ist bei On-Demand-Besprechungen null.

Payload-Beispiel

{
  "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"
  }
}

Feldreferenz

FeldTypBeschreibung
data.organisation_uidstringUID der Organisation, zu der die Besprechung gehört
data.meeting_uidstringEindeutiger Bezeichner der Besprechung
data.changestringDer Lebenszyklus-Übergang, der dieses Ereignis ausgelöst hat — siehe Tabelle oben
data.statusstring oder nullAktueller Status der Besprechung. null bei On-Demand-Besprechungen; verwenden Sie stattdessen change für die Logik
data.meeting_typestringArt der Besprechung (z.B. consultation)
data.meeting_formatstringFormat der Besprechung (z.B. digital)
data.start_dateinteger oder nullUnix-Zeitstempel des geplanten Starts (nur bei geplanten Terminen)
data.end_dateinteger oder nullUnix-Zeitstempel des geplanten Endes bei geplanten Terminen. Dies ist der ursprünglich geplante Endzeitpunkt, nicht das tatsächliche Ende
data.estimated_duration_minutesinteger oder nullGeschätzte Dauer in Minuten
data.confirmed_atinteger oder nullUnix-Zeitstempel der Bestätigung oder null
data.cancelled_atinteger oder nullUnix-Zeitstempel der Stornierung oder null
data.cancellation_reasonstring oder nullGrund für die Stornierung oder null
data.expires_atinteger oder nullUnix-Zeitstempel, nach dem der Besprechungslink abläuft, oder null
data.previous_meeting_uidstring oder nullUID der Besprechung, aus der diese umgebucht wurde, oder null. Gesetzt wenn change den Wert rebooked hat
data.appointment_type_uidstring oder nullUID des Termintyps (nur bei geplanten Terminen)
data.doctor_uidstring oder nullUID des zugeordneten Arztes
data.patient_profile_uidstringUID des Patientenprofils. Dies ist der einzige Patientenbezeichner im Payload — es werden keine personenbezogenen Daten (Name, Geburtsdatum oder Kontaktdaten) übermittelt

Abonnieren

Abonnieren Sie über die Management API, um dieses Ereignis zu empfangen:
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"
  }'

Zustellung und Idempotenz

Webhooks werden mindestens einmal zugestellt. Ihr Endpunkt sollte Zustellungen als idempotent behandeln und die Kombination aus data.meeting_uid und data.change als eindeutigen Schlüssel verwenden — erneut zugestellte Events tragen dieselben Werte.