Webhook API
Reservation Import — ImportReservationAccountHook
Endpoint
| 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
CONSUME_RESERVATIONS action is triggered.Payload Structure – Reservation_extensive_data
JSON{
"Reservation_extensive_data": [
{ /* ReservationData – see below */ }
]
}
ReservationData #
One object per reservation. Maps directly to a GroupReservation in Scanfie.
| JSON field | Type | Required | Description |
|---|---|---|---|
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 field | Type | Required | Description |
|---|---|---|---|
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 field | Type | Required | Description |
|---|---|---|---|
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 field | Type | Required | Description |
|---|---|---|---|
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 field | Type | Required | Description |
|---|---|---|---|
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 field | Type | Required | Description |
|---|---|---|---|
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": []
}
| Field | Type | Description |
|---|---|---|
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.
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.
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:
- Reservation upsert – The reservation is created or updated, matched on
Reservation_number(externalId). - Profile upsert – When
Client_datais supplied, a guestProfileis created or matched by e-mail address, then by phone number. - Reservation product sync – Products are upserted; products no longer present in the payload are soft-deleted.
- Activity schedule sync –
ReservationActivityScheduleentries are created or updated; unmatched ones are removed. - Gift card assignment – Vouchers are attached to the reservation as
CompanyGiftCardReservationrecords. - Automatic group session – When the company setting
automaticallyCreateGroupSessionOnReservationis enabled, a group session (order) is automatically created from the reservation, unless all reservation products belong to product groups withdisableAutomaticGroupImport = trueor the reservation status isCANCELLED.
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
}
]
}
]
}