Webhook API

Reservation Import — ImportReservationAccountHook

Endpoint

POST /api/plugin/webhook/{companyPluginRegistrationId}?k={sharedSecret}
Parameter Location Type Required Description
companyPluginRegistrationId Path String Required The internal Scanfie ID of the CompanyPluginRegistration record for the integration.
k Query param String Required Shared secret key; must match the sharedSecret configured on the plugin registration.
request body Body JSON Required The full reservation payload – see Payload Formats below.

The endpoint accepts the raw JSON body as the pluginHookPayload. The hook determines the payload format by inspecting known top-level keys.

Supported Payload Formats

Reservation_extensive_data
✓ Parsed & consumed
Reservation data is imported and a CONSUME_RESERVATIONS action is triggered.
ERP_Info_To_CRM
ℹ Informational only
Logged as informational; not processed further.
anything else
— Silently ignored
Unrecognised top-level keys are silently ignored.

Payload Structure – Reservation_extensive_data

JSON{
  "Reservation_extensive_data": [
    { /* ReservationData – see below */ }
  ]
}

ReservationData #

One object per reservation. Maps directly to a GroupReservation in Scanfie.

📅
Note on dates: The API does not include a reservation date. The import always sets the reservation date to the start of the current day and the end date to the end of the current day.
JSON fieldTypeRequiredDescription
terminal_id String Optional ID of the target POS terminal in Scanfie. When present, the reservation and the automatically generated group session are routed to this terminal.
Reservation_number String Required External/ERP reservation number. Used as the externalId that uniquely identifies the reservation in Scanfie. A missing or empty value aborts the import of this entry.
Reservation_internal_number String Optional Internal ERP number stored as reservationNumber.
Reservation_payment_reference String Optional Payment reference stored on the reservation (e.g. for reconciliation).
check_in_code String Optional QR / check-in code stored as checkinCode on the reservation.
Reservation_name String Optional Human-readable name appended to the Reservation_number to form the reservation label shown in Scanfie (label = Reservation_number + " " + Reservation_name).
Reservation_persons String (numeric) Optional Number of persons in the reservation. Parsed as integer, defaults to 2 when absent or non-numeric.
Remarks String Optional Free-text remarks stored on the reservation.
Table_number String Optional Location/table number stored as locationNumber.
Total_amount Number (decimal) Optional Total gross reservation amount including VAT, stored as reservationAmountIncl.
Pre_paid_amount Number (decimal) Optional Already-paid amount stored as paidAmountIncl.
Including_VAT Boolean Optional When true (or absent/null, which defaults to true), all product prices in Product_items are treated as inclusive of VAT. Set to false to supply net (exclusive) prices.
Client_data Object Optional Guest/client profile. When present, a Profile is created or matched in Scanfie. See ClientData.
Product_items Array Optional Ordered products/activities on this reservation. See ReservationProductData.
Vouchers Array Optional Gift cards / vouchers associated with the reservation. See ReservationVoucherData.

ClientData — nested inside each reservation #

JSON fieldTypeRequiredDescription
Client_number String Optional ERP client number. Stored as externalId on the Scanfie Profile, prefixed with NS (e.g. NS12345).
Company String Optional Company name of the guest, stored as companyName on the profile.
Name String Optional Full name of the guest. Automatically split into firstName (first word) and lastName (remaining words) on the profile.
Email String Optional E-mail address. Used to match an existing Profile in Scanfie. System-generated @scanfie.nl addresses are ignored for matching.
Phone_number String Optional Landline phone number. Used as the profile phone number when Mobile_number is absent or 4 characters or fewer.
Mobile_number String Optional Mobile phone number. Takes precedence over Phone_number when present and longer than 4 characters.
Address Object Optional Postal address of the guest. See ReservationAddressData.

ReservationAddressData — nested inside Client_data #

JSON fieldTypeRequiredDescription
Street String Optional Street name.
Number String Optional House number and optional alphanumeric suffix (e.g. "12B"). Automatically split into houseNumber (integer) and houseNumberSuffix (String).
Zip_code String Optional Postal / ZIP code.
City String Optional City name.
Country String Optional Country name or ISO code.

ReservationProductData — entries in Product_items #

Each entry maps to a ReservationProduct and optionally to an ActivityProduct in Scanfie.

JSON fieldTypeRequiredDescription
Product_PLU String Required External PLU / article code of the product. Used as externalId. A missing or empty value aborts the import of this product.
Product_name String Optional Product name. Overridden by Product_location_name when that field is non-empty.
Product_color String Optional Counter display colour for the product (hex or CSS colour name), stored as productCounterColor.
Product_quantity Number (integer) Optional Ordered quantity. Defaults to 1.
Product_price Number (decimal) Optional Unit price per product (gross or net depending on Including_VAT). Used to calculate the unit price on the associated PluginProduct.
Product_total_price Number (decimal) Optional Total price for this line (gross or net depending on Including_VAT). Used to calculate totalPrice / totalNettPrice on the reservation product.
Product_total_excluding_discount Number (decimal) Optional Total price before any discount. Stored as totalPriceWithoutDiscount / totalNettPriceWithoutDiscount.
Product_tax_rate Number (integer, basis points) Optional VAT rate in basis points (e.g. 2100 = 21%). When absent, the tax rate from the first Product_parts entry is used as fallback. Required to calculate net/gross prices.
Product_location_name String Optional Display name of the activity location. When non-empty, takes precedence over Product_name as the product and activity name.
Product_start_time String (HH:mm / HH:mm:ss) Optional Start time of an activity. When present and a valid time string, a ReservationActivitySchedule is created for this product.
Product_planned_time String (HH:mm / HH:mm:ss) Optional Planned preparation/service time. When a valid time string, stored as dtOrderPlanned on today's date.
Product_duration String (e.g. "01:30") Optional Duration of the activity, parsed into minutes. Only used when Product_start_time is also present.
Product_from_unit String Optional Source location code of the activity (e.g. bowling lane ID), stored as reservationLocation on the activity schedule.
Product_tables Array of String Optional System table/lane codes assigned to the activity, stored as activityTableCodes on the activity schedule.
Cost_number String Optional Turnover group external ID used to link the product to a TurnoverGroup in Scanfie, stored as turnoverGroupExternalId.
Product_parts Array Optional Sub-items / arrangement parts. When the plugin setting splitPartsIntoOrderItems is enabled, the parent product is flagged as a combo and each part becomes a separate reservation product line. See ReservationProductPartData.

ReservationProductPartData — entries in Product_parts #

Used to define arrangement parts / combo sub-items. Each part can carry its own activity schedule.

JSON fieldTypeRequiredDescription
Arr_Item_PLU String Optional PLU of this specific arrangement item (arrangementPlu). Default PLU for the part product and the activity externalId. Overridden by Part_PLU when plugin setting usePartArrPLU is true.
Part_PLU String Optional PLU of the top-level arrangement (partPlu). When plugin setting usePartArrPLU is true and non-empty, overrides Arr_Item_PLU for the activity externalId and the part product externalId.
Part_name String Optional Display name of the part. Used as the activity name and the reservation product name.
Part_color String Optional Counter display colour for the part product. Only used when splitPartsIntoOrderItems is true.
Part_quantity Number (integer) Optional Quantity of this part. Falls back to the parent product's quantity when absent or less than 1.
Part_price Number (decimal) Optional Unit price per part entry (gross or net depending on Including_VAT). Used only when Part_total_price is absent. Multiplied by Part_quantity when quantity > 1.
Part_total_price Number (decimal) Optional Total price for this part (gross or net depending on Including_VAT). Takes precedence over Part_price × Part_quantity.
Part_total_excluding_discount Number (decimal) Optional Total price before discount for this part. Stored as totalPriceWithoutDiscount / totalNettPriceWithoutDiscount.
Part_tax_rate Number (integer, basis points) Optional VAT rate in basis points for this part. Falls back to the parent product's tax rate when absent.
Part_location_name String Optional Display name of the part's location / activity. Used as activity name when Part_name is absent or blank.
Part_start_time String (HH:mm / HH:mm:ss) Optional Start time of the part's activity. When a valid time string, a ReservationActivitySchedule is created (or reused when an identical one already exists).
Part_duration String (e.g. "01:30") Optional Duration of the part's activity, parsed into minutes. Only used when Part_start_time is also present.
Part_from_unit String Optional Source location code for the part's activity, stored as reservationLocation on the activity schedule.
Part_tables Array of String Optional System table/lane codes for the part's activity, stored as activityTableCodes on the activity schedule.
Part_cost_center Object Optional Cost centre for this part. Contains Cost_number (String) — used as turnoverGroupExternalId on the part product. Cost_description is present in the object but not interpreted.

ReservationVoucherData — entries in Vouchers #

JSON fieldTypeRequiredDescription
transactionId String Optional Transaction reference of the voucher / gift card. Stored as both giftcardId and transactionId on the CompanyGiftCardReservation.
amount Number (decimal) Optional Monetary value of the voucher, stored as giftcardAmount.

Response

The endpoint always returns 200 OK with a JSON response body. Inspect errors to detect failures; the HTTP status code alone is not sufficient.

JSON{
  "errors": []
}
FieldTypeDescription
errors Array of objects List of processing errors/warnings. An empty array indicates success. Each object contains errorMessage and severity (INFO, WARNING, ERROR).

Plugin Settings Affecting Import Behaviour

The following settings are configured on the CompanyPluginRegistration and control how the payload is processed.

splitPartsIntoOrderItems
Boolean  ·  default: false

When true, each Product_parts entry is imported as a separate child ReservationProduct with the parent flagged as a combo. When false, parts only generate activity schedules on the parent product.

usePartArrPLU
Boolean  ·  default: false

Controls which PLU is used for the activity externalId and part product externalId. When false (default), Arr_Item_PLU is used. When true, Part_PLU overrides Arr_Item_PLU when non-empty.

Core Behaviour after Import

After the plugin parses the payload into the internal reservation model, the Scanfie core (ConsumePluginReservationsAction) performs the following steps:

  1. Reservation upsert – The reservation is created or updated, matched on Reservation_number (externalId).
  2. Profile upsert – When Client_data is supplied, a guest Profile is created or matched by e-mail address, then by phone number.
  3. Reservation product sync – Products are upserted; products no longer present in the payload are soft-deleted.
  4. Activity schedule syncReservationActivitySchedule entries are created or updated; unmatched ones are removed.
  5. Gift card assignment – Vouchers are attached to the reservation as CompanyGiftCardReservation records.
  6. Automatic group session – When the company setting automaticallyCreateGroupSessionOnReservation is enabled, a group session (order) is automatically created from the reservation, unless all reservation products belong to product groups with disableAutomaticGroupImport = true or the reservation status is CANCELLED.

Example Payload

JSON{
  "Reservation_extensive_data": [
    {
      "terminal_id": "terminal-abc-123",
      "Reservation_number": "RES-2026-001",
      "Reservation_internal_number": "INT-001",
      "Reservation_payment_reference": "PAY-REF-001",
      "check_in_code": "CHECKIN-QR-001",
      "Reservation_name": "Jansen",
      "Reservation_persons": "4",
      "Remarks": "Allergie: noten",
      "Table_number": "12",
      "Total_amount": 120.00,
      "Pre_paid_amount": 40.00,
      "Including_VAT": true,
      "Client_data": {
        "Client_number": "C001",
        "Name": "Jan Jansen",
        "Company": "Jansen B.V.",
        "Email": "jan.jansen@example.com",
        "Mobile_number": "+31612345678",
        "Phone_number": "+31201234567",
        "Address": {
          "Street": "Hoofdstraat",
          "Number": "10A",
          "Zip_code": "1234AB",
          "City": "Amsterdam",
          "Country": "NL"
        }
      },
      "Product_items": [
        {
          "Product_PLU": "BOW-60",
          "Product_name": "Bowlingbaan 1 uur",
          "Product_color": "#FF5733",
          "Product_quantity": 1,
          "Product_price": 30.00,
          "Product_total_price": 30.00,
          "Product_tax_rate": 2100,
          "Product_start_time": "14:00",
          "Product_duration": "01:00",
          "Product_from_unit": "LANE-1",
          "Product_tables": ["LANE-1"],
          "Cost_number": "LEISURE"
        },
        {
          "Product_PLU": "ARRANGEMENT-PARTY",
          "Product_name": "Feestpakket",
          "Product_quantity": 2,
          "Product_total_price": 90.00,
          "Product_tax_rate": 2100,
          "Cost_number": "FOOD",
          "Product_parts": [
            {
              "Arr_Item_PLU": "FOOD-SNACK",
              "Part_PLU": "ARRANGEMENT-PARTY",
              "Part_name": "Snackplank",
              "Part_color": "#33FF57",
              "Part_quantity": 2,
              "Part_total_price": 30.00,
              "Part_tax_rate": 900,
              "Part_start_time": "15:00",
              "Part_duration": "00:30",
              "Part_from_unit": "KITCHEN",
              "Part_tables": ["TABLE-5"],
              "Part_cost_center": { "Cost_number": "FOOD" }
            },
            {
              "Arr_Item_PLU": "DRINKS-PACKAGE",
              "Part_PLU": "ARRANGEMENT-PARTY",
              "Part_name": "Drankenpakket",
              "Part_quantity": 2,
              "Part_total_price": 60.00,
              "Part_tax_rate": 2100
            }
          ]
        }
      ],
      "Vouchers": [
        {
          "transactionId": "GC-XYZ-9876",
          "amount": 25.00
        }
      ]
    }
  ]
}