Appearance
Vanhoutte Integration Setup
Looking for guided setup? Start Emily in the backoffice for step-by-step guided setup.
Purpose
The Vanhoutte integration connects Upvendo to Vanhoutte POS registers via the Kassanet protocol -- the same protocol used by Hendrickx. It enables restaurants and hospitality businesses (primarily in Belgium) to accept orders through Upvendo channels (Kiosk, Online Ordering, Table QR) and have them appear directly on the Vanhoutte POS register for kitchen preparation and fulfillment. The integration also pulls the full product catalog from Vanhoutte so merchants do not need to re-enter their menu in Upvendo.
Key Concepts
Kassanet Protocol (Shared with Hendrickx)
Vanhoutte and Hendrickx both use the Kassanet communication protocol. They are handled by the same backend code: VanhoutteService and HendrickxService each extend the shared AbstractKassanetService, and VanhoutteIntegration extends the shared KassanetIntegration model -- the only difference between them is the provider identifier (vanhoutte vs hendrickx). All API calls follow the same pattern:
- The request body is serialized to JSON
- If encryption is enabled, the JSON is encrypted with Blowfish CBC using the merchant's encryption token and a null IV (8 zero bytes), then base64-encoded
- An HMAC-SHA256 signature (base64-encoded) is computed over the ISO 8601 date string concatenated with the (possibly encrypted) body, using the merchant's signature key
- The request is sent with headers:
Date,Signature,Content-Type, and a uniquerequest-id
Location-Specific Scope
Each Vanhoutte connection is tied to a single location. If a merchant has multiple locations each with its own Vanhoutte register, each location must be connected separately with its own set of credentials (Connection URL, Signature Key, Encryption Token).
One-Way Menu Sync (Vanhoutte to Upvendo)
Menu items must exist in Vanhoutte POS before connecting. Upvendo cannot create items in Vanhoutte -- it only reads the existing catalog. The sync imports:
- Categories and subcategories from Vanhoutte product groups
- Products with names, prices, and PLU codes
- Modifier groups and modifiers (product variants/selections)
- Display groups that control how items are organized in the Upvendo menu
- Table numbers from the POS for table management
Order Forwarding (Upvendo to Vanhoutte)
After payment is confirmed, Upvendo sends orders to Vanhoutte using the CreateOrder endpoint. The order includes the table number, item article IDs, quantities, modifiers, and an optional pickup time. After order creation, Upvendo retrieves the bill (GetBill) and then marks the bill as paid (PayBill) using the configured webshop payment type.
Table Number Management
Vanhoutte supports two table assignment modes:
- Non-physical tables -- Upvendo calls
GetFreeTableNumberto get an available virtual table from the POS. - Physical tables -- Upvendo allocates a table from a configured table section, checking each table's bill status (via
GetBill) to ensure it is free. Used table numbers are tracked per month (insettings.tables_usage, reset at the start of each month) to avoid collisions.
Both modes use distributed locking (MongoDB-based) to prevent race conditions when multiple orders arrive simultaneously. Table-allocation locks expire after 5 minutes.
Stock Tracking
After menu sync, Upvendo pulls stock levels from Vanhoutte using the GetCountdownPluState endpoint. Items with countdown PLUs have their inventory updated in Upvendo, enabling out-of-stock indicators on Kiosk and Online Ordering. An optional threshold parameter can be set to only return items below a certain stock level.
Available Kassanet API Endpoints
The following Kassanet endpoints are used by the Vanhoutte integration:
| Endpoint | Method | Purpose |
|---|---|---|
test | GET | Test connection and retrieve system info (including tipping settings) |
GetAllProducts | GET | Fetch the complete product catalog (categories, products, modifiers) |
GetProductSelection | GET | Fetch product selections / display groups |
TableNumbers | GET | Fetch all configured table numbers |
GetFreeTableNumber | GET | Get the next available virtual table number |
GetBill?tableNumber=N | GET | Retrieve the current bill for a table |
GetPaymentTypes | GET | Fetch available payment types on the POS |
CreateOrder | POST | Send an order to the POS register |
PayBill | POST | Mark a bill as paid with a specified payment type |
PostDeposit | POST | Post a deposit payment to a table |
GetCountdownPluState | GET | Fetch stock levels for countdown PLU items |
Connection Status and Auto-Reconnection
The integration tracks connection status per location. If an API call fails due to a timeout or server error, the location is marked as disconnected. The scheduled command kassanet:check-and-requeue (runs every 5 minutes) re-tests all disconnected locations and restores them when the POS comes back online. Reconnecting (via the periodic test or a manual Test Connection) triggers queued orders flagged need_requeue to be dispatched again.
Actions
Connect Vanhoutte
Route: /vanhoutte
- Complete all prerequisites (see checklist below)
- Select the target location from the topbar
- Click Connect or Add Channel and select Vanhoutte (opens the
VanHoutteChannelDialog) - Enter credentials:
- Connection URL (
base_url) -- The Vanhoutte Kassanet API base URL (provided by Vanhoutte) - Signature Key (
signature_key) -- The HMAC signing key for API authentication - Encryption Token (
encryption_token) -- The Blowfish encryption key for payload encryption
- Connection URL (
- Save the credentials -- the first menu import starts automatically; you do not have to click Sync Now for it. Use Sync Now for later manual re-imports.
- Verify sync results in the Vanhoutte Logs
Connecting calls POST /api/back-office/kassanet/vanhoutte/{locationId} (the initiate action). Re-submitting on an existing integration updates the saved credentials and settings in place -- it does not create a duplicate. Prerequisites are validated at connect time: the merchant must have a branding profile, and the location must not already have another in-house POS connected. Payment and billing profiles are not enforced at connect time. Reconnecting on a location where a Vanhoutte integration was previously removed restores the stored per-table usage history (settings.tables_usage) from the old record.
Sync Menu
Route: /vanhoutte
Click Sync Now to manually trigger a full menu import (POST /api/back-office/kassanet/vanhoutte/{locationId}/sync-menu). The sync runs as a background job chain:
ImportKassanetMenuJob-- chain entrypoint; dispatches the next jobImportKassanetCategoriesJob-- fetchesGetAllProducts, processes categories and subcategoriesImportKassanetProductsJob-- processes products and modifiers from the same dataImportKassanetDisplayGroupsJob-- merges modifier groups, processes display groups (which also fetchesTableNumbersand stores them insettings.tables), syncs stock levels, cleans up placeholder items, and fires aReloadMenuevent
Each job retries up to 3 times with a 30-second backoff. The timeout is 300 seconds (5 minutes) per job, except ImportKassanetProductsJob, which has a 600-second (10-minute) timeout.
Configure Auto Sync
Set a daily sync time (e.g., 05:00) to automatically re-import menu changes from Vanhoutte. The time you enter in the UI is your location's local time and is stored verbatim as that local wall-clock (settings.sync_time), not converted to UTC, alongside the resolved IANA zone in settings.sync_timezone; next_run_time is reset so the scheduler recalculates the absolute instant. Because the stored value is local, the sync stays at the same local time across daylight-saving changes. The settings form snaps the chosen time to the nearest hour or half-hour (:00 or :30) and shows the resolved zone as a caption under the field. Disable auto-sync by clearing the sync time field.
Auto-sync is driven by the in-house:auto-sync command, which runs every 30 minutes and triggers a full menu sync for each integration when its scheduled time arrives -- so each integration syncs at most once per day.
Test Connection
Click Test Connection (GET /api/back-office/kassanet/vanhoutte/{locationId}/test) to verify the Kassanet API is reachable. The test calls the test endpoint, checks the IsSuccessStatusCode response field, and updates the connection status. If the POS was previously disconnected, a successful test reconnects the location and requeues any orders flagged for requeue.
View Logs
Route: /vanhoutte
The Vanhoutte Logs panel shows recent sync and order events. Each log entry includes:
- Timestamp -- when the event occurred (ISO 8601 format)
- Type -- e.g.
success,error,warning, orinfo - Message -- a description of what happened
The logs view supports search, type filtering, date-range filtering, refresh, and export (CSV/JSON/TXT). Logs are capped at 1000 entries per location, newest first. Log entries marked for deduplication collapse consecutive duplicates by updating the timestamp and incrementing an occurrences counter.
Delete / Disconnect (Disabled)
Disconnecting a Vanhoutte integration through the API is currently disabled. The delete endpoint returns an error ("Disconnecting Vanhoutte integration is disabled. Please contact administrator."). To remove or change a Vanhoutte connection, contact an administrator.
Business Rules
- Menu items must exist in Vanhoutte POS before they can appear in Upvendo. There is no push from Upvendo to Vanhoutte for menu data.
- Orders are only forwarded to Vanhoutte after payment is confirmed (Viva Wallet for Kiosk, Stripe for Online Ordering).
- If the Vanhoutte register is offline when an order is placed, the order is flagged with
need_requeue = true. When the POS comes back online (detected via the periodickassanet:check-and-requeuecommand or a manual test), flagged orders are automatically requeued. - Each API request includes a unique
request-idheader (generated withuniqid) for traceability. - API requests time out after 15 seconds (with a 10-second connection timeout). The main request path does not retry by default; only the
PayBill/PostDeposit"bill locked" path retries (up to 3 attempts, ~250ms/750ms/1500ms backoff). Errors classified as retryable are timeouts, connection failures, and HTTP 408/500/502/503/504. - Table-allocation locks expire after 5 minutes to prevent permanent table lockout if a process fails.
- The integration logs up to 1000 recent entries per location, with the newest first. Entries marked for deduplication collapse consecutive duplicates by updating the timestamp and bumping an occurrences count.
- If a bill total from Vanhoutte does not match the Upvendo transaction total, a mismatch is logged but the order still proceeds. (Exception: if the POS returns a zero bill total while the Upvendo total is non-zero, the order is marked unrecoverable.)
- Vanhoutte is an in-house POS and is mutually exclusive with other in-house POS providers (Hendrickx, Vanhoutte, ShopCaisse) on the same location -- once one is active for a location, the others are unavailable there.
- When encryption is enabled on the integration, the URL path includes a
SEC1segment between the base URL and the endpoint name ({base_url}/SEC1/{endpoint}). This signals the Kassanet server to expect encrypted payloads. - The sync cleans up placeholder items after import. Items with a kitchen name of
zz, matching the pattern* pager *, or where the kitchen name equals a numeric product name are automatically removed.
Prerequisites Checklist
Before integrating with Vanhoutte, complete these steps in order:
Only the branding profile (and having no other in-house POS on the location) is enforced when you connect. Payment and billing profiles are optional at connect time and can be set up later -- but you need a payment provider before you can take a paid order.
1. Payment Profile Setup (Recommended)
- Go to Settings -> Payments (
/settings/payments) - Set up your payment providers:
- Viva Wallet for Kiosk payments (terminal-based)
- Stripe for Online Ordering payments
- Configure payment methods (Card, Bancontact, etc.)
2. Billing Profile Setup (Recommended)
- Go to Settings -> Billing (
/settings/billing) - Complete your billing information
3. Branding Profile Setup (Required)
- Go to Settings -> Brand (
/settings/brand) - Configure your store's branding (logo, colors, etc.)
4. Location Creation (Required)
- Go to Settings -> Locations (
/settings/locations) - Create your location with:
- Business name and address
- Business hours
- Contact information
- Select this location from the topbar before connecting Vanhoutte
Order Flow
Orders are created in Upvendo (via Kiosk, Online Ordering, or Table QR) and pushed to Vanhoutte after payment is confirmed.
Three-Step POS Flow
text
1. CreateOrder -> Sends items + table number to Vanhoutte POS
|
2. GetBill -> Retrieves the bill total for the table
|
3. PayBill -> Marks the bill as paid with the webshop payment typeKiosk Flow
text
Customer submits order on Kiosk
|
Viva Wallet terminal prompts for payment
|
Customer pays the prompted amount
|
Upvendo receives successful payment webhook
|
CreateOrder is dispatched to Vanhoutte
|
GetKassanetBillJob retrieves the bill
|
PayKassanetBillJob marks the bill as paidOnline Ordering Flow
text
Customer submits order online
|
Payment processed via Stripe (e.g. card or Bancontact redirect)
|
Customer pays the prompted amount
|
Upvendo receives successful payment webhook
|
CreateOrder is dispatched to Vanhoutte
|
GetKassanetBillJob retrieves the bill
|
PayKassanetBillJob marks the bill as paidGetKassanetBillJob and PayKassanetBillJob both run on the payments-medium queue.
Order Payload Structure
Each order sent to Vanhoutte includes (among other fields):
TableNumber-- the assigned table (physical or virtual)OperatorId-- the POS operator identifierTableText-- a multi-line block built from order channel, order number, queue number, pager ID (if any), section name, customer first name, customer phone (online ordering only), customer note, and any loyalty receipt note. (Note: it uses the customer's first name and does not include an email field.)Items[]-- begins with an order-type PLU marker, then each item hasArticleId,Text,Quantity, optionalInfoText(per-item notes), and nestedVariants[]for modifiersPickupTime-- for non-dine-in, non-Kiosk orders, formatted asH:iin the location's timezone
FAQs
Q: What is the difference between Vanhoutte and Hendrickx? A: Both use the same Kassanet protocol and share the same backend service code (AbstractKassanetService) and integration model (KassanetIntegration). The only difference is the provider identifier and the specific POS hardware/software. If you have a Vanhoutte POS, use this integration; if you have a Hendrickx POS, use the Hendrickx integration.
Q: Can I create menu items in Upvendo and push them to Vanhoutte? A: No. The Vanhoutte integration is one-way for menu data. Items must be created in the Vanhoutte POS first, then synced to Upvendo via the Sync Now button or auto-sync schedule.
Q: What happens if the Vanhoutte POS is turned off when an order comes in? A: The order is saved with a need_requeue flag. The kassanet:check-and-requeue command (every 5 minutes) re-tests disconnected locations and requeues flagged orders when the POS comes back online. You can also manually click Test Connection to trigger a reconnect and requeue.
Q: Can I connect multiple Vanhoutte registers to one Upvendo location? A: No. Each location supports one Vanhoutte integration. If you have multiple registers, they should share the same Kassanet connection endpoint.
Q: Does the integration support tipping? A: Yes. If the Vanhoutte system has the tip calculator activated (SystemInfo.tipCalculatorActivated in the test response), tipping is enabled in Upvendo.
Q: How often does auto-sync run? A: The in-house:auto-sync scheduler runs every 30 minutes and triggers each integration's full menu sync when its configured time arrives, so each integration syncs at most once per day. The time you set in the UI is your location's local time and is stored as such, so it keeps firing at the same local time across daylight-saving changes. If no sync time is set, auto-sync is disabled.
Q: Can I switch from Hendrickx to Vanhoutte on the same location? A: Only an in-house POS is allowed per location at a time, and disconnecting an existing integration through the app is currently disabled. To switch providers, contact an administrator.
Q: What is a PLU code? A: PLU stands for Price Look-Up. It is a unique identifier assigned to each product in the Vanhoutte POS. Upvendo uses PLU codes (stored as ArticleId) to reference items when creating orders and tracking stock levels.
Q: Does the integration support order notes or special instructions? A: Yes. Per-item notes are sent as InfoText in the order payload. These appear on the kitchen display or receipt in the Vanhoutte POS.
Troubleshooting
Orders not syncing to Vanhoutte
- Verify the Vanhoutte register is powered on and connected to the internet
- Go to
/vanhoutteand click Test Connection to check the current status - Check Vanhoutte Logs for specific error messages
- If the connection status shows "disconnected", the POS may be offline. Orders will automatically requeue when the connection is restored
"Connection test failed" error
- Double-check the Connection URL -- it should be the full Kassanet API base URL without a trailing slash
- Verify the Signature Key is correct -- an incorrect key produces HMAC signature mismatches
- Verify the Encryption Token is correct -- an incorrect token causes a Blowfish decryption error or an unreadable (non-JSON) response
- Ensure the Vanhoutte register's firewall allows incoming connections from Upvendo's servers
"No free table numbers available" error
- This means all virtual or physical tables are occupied or locked
- Check if there are stale table locks (table-allocation locks auto-expire after 5 minutes)
- For physical tables, verify the table section is properly configured and has enough tables
- Check if the table number range in the Vanhoutte POS matches the Upvendo configuration
Menu sync shows 0 products
- Verify the Vanhoutte POS has products configured
- Check if the API returns data by clicking Test Connection first
- Review the Vanhoutte Logs for errors during the import job steps
- If the sync was interrupted, try clicking Sync Now again -- each job retries up to 3 times
Bill total mismatch warning in logs
- This occurs when the bill total from Vanhoutte does not match the Upvendo transaction total
- Common causes: price differences between Upvendo and Vanhoutte (menu not recently synced), rounding differences, or modifier pricing discrepancies
- Run a menu sync to ensure prices are up to date
- The order still proceeds despite the mismatch, but the warning should be investigated (a zero bill total against a non-zero Upvendo total is treated as unrecoverable)
Orders stuck in "error" status
- Check the order's transaction
external_datafor the Vanhoutte error message - Common causes: POS was offline during order creation, invalid article IDs (item removed from POS but still in Upvendo menu), or table assignment failure
- If the POS is now online, click Test Connection to trigger a reconnect and automatic requeue
Encryption-related errors
- A Blowfish decryption error usually means the encryption token is incorrect. Re-enter the correct token from your Vanhoutte provider
- An invalid/undecryptable response can mean encryption settings differ between Upvendo and the POS. Check that encryption is enabled on both sides
- If you recently changed the encryption token in Vanhoutte, update it in Upvendo as well (contact an administrator to update credentials if the connection cannot be re-initiated)
Related Documentation
- Kassanet Integration (shared backend engine)
- Hendrickx Integration (uses same Kassanet system)
- Payment Profiles
- Locations
- Stripe
- Viva Wallet
Note: Deep sync internals (exact field-level mapping during import, modifier-group merge logic) and customer-facing storefront/Kiosk behavior are not verified in this document and may differ in detail.