Skip to content

Lightspeed K-Series Onboarding Flow ​

Overview ​

Lightspeed Restaurant K-Series is a merchant-scoped POS integration that connects via OAuth 2.0. One OAuth authorization covers the whole Lightspeed account, but data is wired up per location: you create your Upvendo locations manually, then map each one to a Lightspeed business location.

Key points:

  • OAuth connection — you log in to your Lightspeed account to authorize Upvendo. There are no API keys to manage, and the integration does not use PKCE (CSRF protection comes from an HMAC-signed state parameter).

  • Locations are not auto-imported — you create locations in Upvendo manually and link each one to a Lightspeed business location ID in the integration's Locations tab.

  • Menu is pulled from Lightspeed, but items push back — Upvendo imports your menu, items, modifiers, categories, tax rates, allergens, and stock from Lightspeed K-Series, which is the source of truth for structure. It is not strictly one-way, though: an item created or edited in Upvendo on a K-Series-mapped location is pushed to Lightspeed (PushItemToLightspeedKSeriesJob, dispatched from ItemRepository). Categories are the exception — K-Series categories are its accounting groups, so they cannot be created or deleted from Upvendo (config/pos-providers.php sets category_create and category_delete to false).

  • Separate payment provider required — Lightspeed handles in-house POS payments only. Kiosk and Online Ordering still need Stripe or Viva Wallet for customer-facing payments.

  • Lightspeed K-Series only in development/testing — the production PRODUCTION_POS_PROVIDERS list is Upvendo POS, Hendrickx and Vanhoutte; Lightspeed K-Series is listed only in development/testing.

    POS_PROVIDERS / PRODUCTION_POS_PROVIDERS now begin with the first-party upvendo entry, but neither is a live provider list: they are read only by POSSelectionGrid.vue, which renders inside EmilyGuidedSetupDialog — a component imported and registered in App.vue but absent from its template and referenced nowhere else as a tag, so it never renders (Emily's modal registry maps guided-setup to a different component, emilyModalRegistry.ts:139). The list a merchant actually sees comes from GET /back-office/merchant/reseller-providers. The first-party provider is server-gated regardless: staged test_only (config/pos-providers.php:51-52), so in production only merchants flagged is_test are offered it.

For the full integration reference (OAuth internals, scopes, token lifecycle, webhooks, order flow), see the Lightspeed K-Series Integration doc.


Integration Type ​

  • Scope: Merchant-scoped (one OAuth connection for the entire account), wired per location via mappings
  • Menu Sync: Structure imported from Lightspeed; Upvendo-created items push back to K-Series (categories are pull-only)
  • Location Import: Manual — create locations in Upvendo, then map each to a Lightspeed business location
  • Order Flow: Completed Upvendo orders are pushed to Lightspeed K-Series via API. Prepaid orders arrive paid (the payment is embedded in the order payload); cash-on-delivery orders arrive unpaid and are paid at the till

Discovery Flow (JSON - for deterministic parsing) ​

How this is used: The Upvendo proxy parses the discovery_questions and setup_steps fenced blocks below verbatim and runs a deterministic discovery flow (no LLM involved). Question ids, abort_if/abort_message, the channels option labels, and the step ids are load-bearing — they must stay aligned with the proxy parser (upvendo-backend-proxy/src/emily/merchant/onboarding-state.js) and the frontend completion mapping (upvendo-backoffice/src/utils/emily/setupStepMappings.ts). The proxy keeps only each step's id, title, and route (and required: false when present) when it serves steps to the frontend; any note field is for documentation only and is not delivered to the UI.

discovery_questions
[
  {
    "id": "channels",
    "text": "Which channels do you want to set up with Lightspeed K-Series?",
    "text_i18n": {
      "nl": "Welke kanalen wil je instellen met Lightspeed K-Series?",
      "fr": "Quels canaux souhaitez-vous configurer avec Lightspeed K-Series ?",
      "de": "Welche Kanäle möchten Sie mit Lightspeed K-Series einrichten?",
      "es": "¿Qué canales quieres configurar con Lightspeed K-Series?",
      "it": "Quali canali vuoi configurare con Lightspeed K-Series?",
      "pt": "Que canais quer configurar com o Lightspeed K-Series?"
    },
    "options": [
      "Kiosk only",
      "Online ordering only",
      "Both"
    ],
    "labels": {
      "nl": {
        "Kiosk only": "Alleen kiosk",
        "Online ordering only": "Alleen online bestellen",
        "Both": "Beide"
      },
      "fr": {
        "Kiosk only": "Kiosque uniquement",
        "Online ordering only": "Commande en ligne uniquement",
        "Both": "Les deux"
      },
      "de": {
        "Kiosk only": "Nur Kiosk",
        "Online ordering only": "Nur Online-Bestellung",
        "Both": "Beides"
      },
      "es": {
        "Kiosk only": "Solo quiosco",
        "Online ordering only": "Solo pedidos en línea",
        "Both": "Ambos"
      },
      "it": {
        "Kiosk only": "Solo chiosco",
        "Online ordering only": "Solo ordini online",
        "Both": "Entrambi"
      },
      "pt": {
        "Kiosk only": "Apenas quiosque",
        "Online ordering only": "Apenas pedidos online",
        "Both": "Ambos"
      }
    }
  },
  {
    "id": "lightspeed_account",
    "text": "Do you have an active Lightspeed Restaurant K-Series account?",
    "text_i18n": {
      "nl": "Heb je een actief Lightspeed Restaurant K-Series-account?",
      "fr": "Avez-vous un compte Lightspeed Restaurant K-Series actif ?",
      "de": "Haben Sie ein aktives Lightspeed Restaurant K-Series-Konto?",
      "es": "¿Tienes una cuenta activa de Lightspeed Restaurant K-Series?",
      "it": "Hai un account Lightspeed Restaurant K-Series attivo?",
      "pt": "Tem uma conta ativa do Lightspeed Restaurant K-Series?"
    },
    "options": [
      "Yes, I have an account",
      "No, I need to set one up"
    ],
    "labels": {
      "nl": {
        "Yes, I have an account": "Ja, ik heb een account",
        "No, I need to set one up": "Nee, ik moet er een aanmaken"
      },
      "fr": {
        "Yes, I have an account": "Oui, j'ai un compte",
        "No, I need to set one up": "Non, je dois en créer un"
      },
      "de": {
        "Yes, I have an account": "Ja, ich habe ein Konto",
        "No, I need to set one up": "Nein, ich muss eines einrichten"
      },
      "es": {
        "Yes, I have an account": "Sí, tengo una cuenta",
        "No, I need to set one up": "No, necesito crear una"
      },
      "it": {
        "Yes, I have an account": "Sì, ho un account",
        "No, I need to set one up": "No, devo crearne uno"
      },
      "pt": {
        "Yes, I have an account": "Sim, tenho uma conta",
        "No, I need to set one up": "Não, preciso de criar uma"
      }
    },
    "abort_if": "No, I need to set one up",
    "abort_message": "You'll need an active Lightspeed Restaurant K-Series account before connecting. Please contact Lightspeed at lightspeedhq.com to get an account set up, then come back here to continue.",
    "abort_message_i18n": {
      "nl": "Je hebt een actief Lightspeed Restaurant K-Series-account nodig voordat je kunt verbinden. Neem contact op met Lightspeed via lightspeedhq.com om een account aan te maken en kom daarna terug om verder te gaan.",
      "fr": "Vous aurez besoin d'un compte Lightspeed Restaurant K-Series actif avant de vous connecter. Contactez Lightspeed sur lightspeedhq.com pour créer un compte, puis revenez ici pour continuer.",
      "de": "Sie benötigen ein aktives Lightspeed Restaurant K-Series-Konto, bevor Sie eine Verbindung herstellen können. Wenden Sie sich an Lightspeed unter lightspeedhq.com, um ein Konto einzurichten, und kehren Sie dann hierher zurück, um fortzufahren.",
      "es": "Necesitarás una cuenta activa de Lightspeed Restaurant K-Series antes de conectar. Ponte en contacto con Lightspeed en lightspeedhq.com para crear una cuenta y luego vuelve aquí para continuar.",
      "it": "Prima di collegarti ti serve un account Lightspeed Restaurant K-Series attivo. Contatta Lightspeed su lightspeedhq.com per creare un account, poi torna qui per continuare.",
      "pt": "Vai precisar de uma conta ativa do Lightspeed Restaurant K-Series antes de ligar. Contacte a Lightspeed em lightspeedhq.com para criar uma conta e depois volte aqui para continuar."
    }
  },
  {
    "id": "menu_ready",
    "text": "Do you already have your menu set up in Lightspeed K-Series?",
    "text_i18n": {
      "nl": "Heb je je menu al ingesteld in Lightspeed K-Series?",
      "fr": "Votre menu est-il déjà configuré dans Lightspeed K-Series ?",
      "de": "Ist Ihr Menü bereits in Lightspeed K-Series eingerichtet?",
      "es": "¿Ya tienes tu menú configurado en Lightspeed K-Series?",
      "it": "Hai già configurato il tuo menu in Lightspeed K-Series?",
      "pt": "Já tem o seu menu configurado no Lightspeed K-Series?"
    },
    "options": [
      "Yes, my menu is in Lightspeed",
      "No, I need to create it"
    ],
    "labels": {
      "nl": {
        "Yes, my menu is in Lightspeed": "Ja, mijn menu staat in Lightspeed",
        "No, I need to create it": "Nee, ik moet het nog aanmaken"
      },
      "fr": {
        "Yes, my menu is in Lightspeed": "Oui, mon menu est dans Lightspeed",
        "No, I need to create it": "Non, je dois le créer"
      },
      "de": {
        "Yes, my menu is in Lightspeed": "Ja, mein Menü ist in Lightspeed",
        "No, I need to create it": "Nein, ich muss es erst erstellen"
      },
      "es": {
        "Yes, my menu is in Lightspeed": "Sí, mi menú está en Lightspeed",
        "No, I need to create it": "No, necesito crearlo"
      },
      "it": {
        "Yes, my menu is in Lightspeed": "Sì, il mio menu è in Lightspeed",
        "No, I need to create it": "No, devo crearlo"
      },
      "pt": {
        "Yes, my menu is in Lightspeed": "Sim, o meu menu está no Lightspeed",
        "No, I need to create it": "Não, preciso de o criar"
      }
    },
    "abort_if": "No, I need to create it",
    "abort_message": "Lightspeed requires your menu to be set up in the POS first. Please create your menu items in Lightspeed K-Series, then come back to continue the setup.",
    "abort_message_i18n": {
      "nl": "Lightspeed vereist dat je menu eerst in de kassa staat. Maak je menu-items aan in Lightspeed K-Series en kom daarna terug om de installatie te voltooien.",
      "fr": "Lightspeed nécessite que votre menu soit d'abord configuré dans le système de caisse. Créez vos articles dans Lightspeed K-Series, puis revenez pour poursuivre la configuration.",
      "de": "Lightspeed erfordert, dass Ihr Menü zuerst im Kassensystem eingerichtet ist. Legen Sie Ihre Menüartikel in Lightspeed K-Series an und kehren Sie dann zurück, um die Einrichtung fortzusetzen.",
      "es": "Lightspeed requiere que tu menú esté configurado primero en el TPV. Crea tus artículos en Lightspeed K-Series y luego vuelve para continuar la configuración.",
      "it": "Lightspeed richiede che il menu sia prima configurato nel POS. Crea i tuoi articoli in Lightspeed K-Series e poi torna per continuare la configurazione.",
      "pt": "O Lightspeed exige que o seu menu esteja primeiro configurado no POS. Crie os seus artigos no Lightspeed K-Series e depois volte para continuar a configuração."
    }
  }
]
setup_steps
{
  "Kiosk only": [
    {
      "id": "branding_profile",
      "title": "Set up Store Branding",
      "route": "/settings/brand"
    },
    {
      "id": "create_location",
      "title": "Create Location",
      "route": "/settings/locations",
      "note": "Create your location manually. Lightspeed does not auto-import locations."
    },
    {
      "id": "connect_pos",
      "title": "Connect Lightspeed K-Series",
      "route": "/lightspeed",
      "note": "Click 'Connect with Lightspeed' on the Settings tab. You will be redirected to log in to your Lightspeed account and authorize Upvendo. After authorization you are returned to the Locations tab, where you map each Upvendo location to a Lightspeed business location. The step completes only once this location is mapped; until then, clicking it opens the Locations tab."
    },
    {
      "id": "menu_for_kiosk",
      "title": "Build Menu for Kiosk",
      "route": "/menus/menu-builder"
    },
    {
      "id": "in_house_settings",
      "title": "Set up In-House Settings",
      "route": "/in-house/settings"
    },
    {
      "id": "device_profile",
      "title": "Create Device Profile",
      "route": "/device-management/profiles"
    },
    {
      "id": "billing_details",
      "title": "Add Billing Details",
      "route": "/settings/payments?tab=billing"
    },
    {
      "id": "kiosk_device",
      "title": "Set up Kiosk & Activate Payment",
      "route": "/device-management/devices"
    },
    {
      "id": "lightspeed_order_profiles",
      "title": "Set up Order Profiles & Tax",
      "route": "/lightspeed",
      "action": "order_profiles_guidance",
      "note": "Create the dedicated take-away / delivery order profiles in the Lightspeed Back Office (name/code are your choice — e.g. upvtakeout / upvdelivery; what matters is Takeaway mode = Pick up / Delivery and Order completion = Complete manually in POS), map them on the Locations tab via the mapping's Order profiles dialog, and attach the tax rules. US & Canada: tax is calculated automatically from the store address, so the new profiles bill correctly with no per-profile setup — a live account already has this configured with Lightspeed. Only Lightspeed can change tax rates. (The tax method — exclusive vs inclusive — imports automatically; there is no dine-in vs take-away rate split.) EU: send Lightspeed support a one-time request to attach the reduced-rate VAT rule (template in the 'Order profiles & VAT setup' section). The built-in dine-in / take-away profiles already bill the correct tax, so custom profiles are mainly needed to keep prepaid orders on the Orders screen. Auto-completes once the profiles are mapped in Upvendo.",
      "optional_for_go_live": true
    },
    {
      "id": "business_profile",
      "title": "Set up Business Profile",
      "route": "/settings/payments",
      "optional_for_go_live": true
    },
    {
      "id": "test_kiosk",
      "title": "Activate Kiosk & Test Order",
      "route": "/device-management/devices",
      "optional_for_go_live": true
    }
  ],
  "Online ordering only": [
    {
      "id": "branding_profile",
      "title": "Set up Store Branding",
      "route": "/settings/brand"
    },
    {
      "id": "create_location",
      "title": "Create Location",
      "route": "/settings/locations",
      "note": "Create your location manually. Lightspeed does not auto-import locations."
    },
    {
      "id": "connect_pos",
      "title": "Connect Lightspeed K-Series",
      "route": "/lightspeed",
      "note": "Click 'Connect with Lightspeed' on the Settings tab. You will be redirected to log in to your Lightspeed account and authorize Upvendo. After authorization you are returned to the Locations tab, where you map each Upvendo location to a Lightspeed business location. The step completes only once this location is mapped; until then, clicking it opens the Locations tab."
    },
    {
      "id": "menu_for_online_ordering",
      "title": "Build Menu for Online Ordering",
      "route": "/menus/menu-builder"
    },
    {
      "id": "online_settings",
      "title": "Set up Online Settings",
      "route": "/online-settings"
    },
    {
      "id": "configure_online_ordering",
      "title": "Set up Online Ordering",
      "route": "/online/online-ordering"
    },
    {
      "id": "lightspeed_order_profiles",
      "title": "Set up Order Profiles & Tax",
      "route": "/lightspeed",
      "action": "order_profiles_guidance",
      "note": "Create the dedicated take-away / delivery order profiles in the Lightspeed Back Office (name/code are your choice — e.g. upvtakeout / upvdelivery; what matters is Takeaway mode = Pick up / Delivery and Order completion = Complete manually in POS), map them on the Locations tab via the mapping's Order profiles dialog, and attach the tax rules. US & Canada: tax is calculated automatically from the store address, so the new profiles bill correctly with no per-profile setup — a live account already has this configured with Lightspeed. Only Lightspeed can change tax rates. (The tax method — exclusive vs inclusive — imports automatically; there is no dine-in vs take-away rate split.) EU: send Lightspeed support a one-time request to attach the reduced-rate VAT rule (template in the 'Order profiles & VAT setup' section). The built-in dine-in / take-away profiles already bill the correct tax, so custom profiles are mainly needed to keep prepaid orders on the Orders screen. Auto-completes once the profiles are mapped in Upvendo.",
      "optional_for_go_live": true
    },
    {
      "id": "business_profile",
      "title": "Set up Business Profile",
      "route": "/settings/payments",
      "optional_for_go_live": true
    },
    {
      "id": "test_online_ordering",
      "title": "Open Online Ordering URL & Test Order",
      "route": "/online/online-ordering",
      "optional_for_go_live": true
    }
  ],
  "Both": [
    {
      "id": "branding_profile",
      "title": "Set up Store Branding",
      "route": "/settings/brand"
    },
    {
      "id": "create_location",
      "title": "Create Location",
      "route": "/settings/locations",
      "note": "Create your location manually. Lightspeed does not auto-import locations."
    },
    {
      "id": "connect_pos",
      "title": "Connect Lightspeed K-Series",
      "route": "/lightspeed",
      "note": "Click 'Connect with Lightspeed' on the Settings tab. You will be redirected to log in to your Lightspeed account and authorize Upvendo. After authorization you are returned to the Locations tab, where you map each Upvendo location to a Lightspeed business location. The step completes only once this location is mapped; until then, clicking it opens the Locations tab."
    },
    {
      "id": "menu_for_kiosk",
      "title": "Build Menu for Kiosk",
      "route": "/menus/menu-builder"
    },
    {
      "id": "menu_for_online_ordering",
      "title": "Build Menu for Online Ordering",
      "route": "/menus/menu-builder"
    },
    {
      "id": "in_house_settings",
      "title": "Set up In-House Settings",
      "route": "/in-house/settings"
    },
    {
      "id": "device_profile",
      "title": "Create Device Profile",
      "route": "/device-management/profiles"
    },
    {
      "id": "billing_details",
      "title": "Add Billing Details",
      "route": "/settings/payments?tab=billing"
    },
    {
      "id": "kiosk_device",
      "title": "Set up Kiosk & Activate Payment",
      "route": "/device-management/devices"
    },
    {
      "id": "online_settings",
      "title": "Set up Online Settings",
      "route": "/online-settings"
    },
    {
      "id": "configure_online_ordering",
      "title": "Set up Online Ordering",
      "route": "/online/online-ordering"
    },
    {
      "id": "lightspeed_order_profiles",
      "title": "Set up Order Profiles & Tax",
      "route": "/lightspeed",
      "action": "order_profiles_guidance",
      "note": "Create the dedicated take-away / delivery order profiles in the Lightspeed Back Office (name/code are your choice — e.g. upvtakeout / upvdelivery; what matters is Takeaway mode = Pick up / Delivery and Order completion = Complete manually in POS), map them on the Locations tab via the mapping's Order profiles dialog, and attach the tax rules. US & Canada: tax is calculated automatically from the store address, so the new profiles bill correctly with no per-profile setup — a live account already has this configured with Lightspeed. Only Lightspeed can change tax rates. (The tax method — exclusive vs inclusive — imports automatically; there is no dine-in vs take-away rate split.) EU: send Lightspeed support a one-time request to attach the reduced-rate VAT rule (template in the 'Order profiles & VAT setup' section). The built-in dine-in / take-away profiles already bill the correct tax, so custom profiles are mainly needed to keep prepaid orders on the Orders screen. Auto-completes once the profiles are mapped in Upvendo.",
      "optional_for_go_live": true
    },
    {
      "id": "business_profile",
      "title": "Set up Business Profile",
      "route": "/settings/payments",
      "optional_for_go_live": true
    },
    {
      "id": "test_kiosk",
      "title": "Activate Kiosk & Test Order",
      "route": "/device-management/devices",
      "optional_for_go_live": true
    },
    {
      "id": "test_online_ordering",
      "title": "Open Online Ordering URL & Test Order",
      "route": "/online/online-ordering",
      "optional_for_go_live": true
    }
  ]
}

Step IDs and completion detection: Each step's completion is auto-detected by the backoffice from the GET /api/back-office/setup-status endpoint. The step ids above map to status flags in setupStepMappings.ts — for example connect_pos is marked complete only when both pos_connected and has_integration_test are true and, for Lightspeed K-Series, the selected location is also mapped to a K-Series business location (has_pos_location_mapping). The first two become true the moment you finish the OAuth connect: the callback fetches your business from /o/op/data/businesses, and that successful authenticated call is itself recorded as the integration test, so there is no "Test Connection" button to click for this step (the same applies to a re-auth). If the businesses fetch fails, no test is recorded and the step stays open. OAuth alone does not complete it, though: K-Series does not import locations, and nothing (webhook, menu sync) is wired until the location is mapped on the Locations tab — so the step stays open, and clicking it opens /lightspeed?tab=locations, until a mapping exists. That keeps the menu steps locked until your Lightspeed menu can actually arrive, instead of sending you to an empty menu builder. (Verified: upvendo-backend/app/Services/SetupStatusService.php checkPosLocationMapping; upvendo-backoffice/src/utils/emily/setupStepMappings.ts isUnmappedLightspeed.) (Verified: upvendo-backend/app/Services/BackOffice/LightspeedKSeriesIntegrationService.php lines 336-354 and 414-421; upvendo-backoffice/src/utils/emily/setupStepMappings.ts line 53.) create_location maps to has_location; menu_for_kiosk/menu_for_online_ordering to has_menu_for_kiosk/has_menu_for_online_ordering; in_house_settings, device_profile, kiosk_device, online_settings, configure_online_ordering, test_kiosk, and test_online_ordering to their respective flags. There is no separate "Select Location from Topbar" or "Sync Menu" step in the Lightspeed flow (the frontend fallback BASE_SETUP_STEPS.lightspeed omits both, and the menu is imported per mapping rather than synced via a dedicated step).


Conditional Logic ​

If lightspeed_account = "No, I need to set one up" ​

The discovery flow aborts with the abort_message:

"You'll need an active Lightspeed Restaurant K-Series account before connecting. Please contact Lightspeed at lightspeedhq.com to get an account set up, then come back here to continue." Onboarding pauses here until the merchant confirms they have an account.

If menu_ready = "No, I need to create it" ​

The discovery flow aborts with the abort_message:

"Lightspeed requires your menu to be set up in the POS first. Please create your menu items in Lightspeed K-Series, then come back to continue the setup."

Lightspeed-side menu creation and obtaining a Lightspeed account are out of scope for Upvendo and are not verified here — they happen in the Lightspeed back office.


Connecting (OAuth) ​

Route: /lightspeed → Settings tab

  1. Create your Upvendo location(s) first at /settings/locations — Lightspeed does not auto-import locations.
  2. On the Settings tab, click Connect with Lightspeed.
  3. You are redirected to the Lightspeed (Keycloak) login. Log in with a Lightspeed Restaurant K-Series account that has sufficient permissions, and authorize Upvendo.
  4. Lightspeed redirects back to the callback (/api/oauth/lightspeed/callback, also aliased at /api/lightspeed/callback). Upvendo verifies the HMAC-signed state, exchanges the code for tokens, fetches your business from /o/op/data/businesses, and stores the access token, refresh token, and business ID/name. That successful business fetch also counts as your connection test — you do not need to click Test Connection. The Connect Lightspeed K-Series & Link Location onboarding step ticks once you have also mapped your location (next step). (Verified: upvendo-backend/app/Services/BackOffice/LightspeedKSeriesIntegrationService.php lines 336-354 and 414-421.)
  5. You land on the Locations tab (/lightspeed?tab=locations).
  6. Map each Upvendo location to one Lightspeed business location. Creating a mapping links the webhook for that business location and starts the initial menu sync.

Order profiles & VAT setup ​

Why this matters: the K-Series order profile on each pushed order controls which POS tab the order appears in (Dine-in vs Pickup/Delivery) and, together with the payment state, whether the order stays visible on the POS Orders screen for the kitchen (or completes straight to Receipts); the VAT rule attached to the profile controls which VAT rate is billed. Important: with Upvendo's standard full-payment push, a fully-paid order closes straight to Receipts in K-Series regardless of the profile's completion setting. Keeping prepaid take-away/delivery orders on the Orders/production queue would need Upvendo's "create unpaid + settle later" option, which is off by default and not offered to merchants yet — there is no setting for it in the back office (see below). Even without that, the order still reaches the kitchen as a production ticket and bills the correct VAT. This is a one-time setup of roughly 15 minutes (plus a short wait on Lightspeed for the tax step in the EU).

Step 1 — Create the order profiles in Lightspeed (± 5 min) ​

In the Lightspeed Back Office → Order profiles → Add order profile, create profiles like the ones below. The name and code are your choice — the upv… codes are just an example convention, not required Upvendo values. What Upvendo actually needs is a take-away profile with Takeaway mode = Pick up and a delivery profile with Takeaway mode = Delivery, both set to Order completion = Complete manually in POS, and with a reduced-rate VAT rule attached (Step 3). The built-in dine-in / take-away profiles already bill the correct VAT, so a custom dine-in profile is optional — its main value is keeping prepaid take-away/delivery orders on the Orders screen.

Name (example)Code (example)Takeaway modeOrder completion
Upvendo Dine-inupvdineinOffComplete manually in POS
Upvendo TakeoutupvtakeoutPick upComplete manually in POS
Upvendo DeliveryupvdeliveryDeliveryComplete manually in POS

Two settings are load-bearing — double-check them:

  • Takeaway mode decides which POS tab the order lands in (Pick up / Delivery → the Pickup/Delivery tab; Off → Dine-in).
  • Order completion = "Complete manually in POS" is what allows a take-away/delivery order to stay open on the Orders screen until staff complete it — but this only takes effect when the order reaches K-Series unpaid. With Upvendo's standard full-payment push, a fully-paid order closes straight to Receipts in K-Series regardless of this setting. Keeping prepaid take-away/delivery orders on the Orders screen would need the "create unpaid + settle later" option (Upvendo pushes the order unpaid and records the payment afterwards). That option is off by default and not offered to merchants yet, so plan on paid orders going to Receipts. (Known K-Series behaviour: fully-paid dine-in orders complete to Receipts regardless — the kitchen still receives the production ticket when the order is created.)

Step 2 — Map the profiles in Upvendo (± 2 min) ​

In the Upvendo back office: Lightspeed → Locations tab → your location's ⋯ menu → Order profiles → select Dine-in = Upvendo Dine-in, Takeout = Upvendo Takeout, Delivery = Upvendo Delivery → Save. From that moment every pushed order carries the matching profile. (Any order type left empty falls back to the K-Series built-in profile.)

Step 3 — Have the VAT rules attached to the new profiles ​

New custom profiles bill the standard rate until tax rules are attached to them. Who does that depends on your region:

  • EU (Belgium, Netherlands, Germany, France, …): tax rules cannot be edited by merchants in the K-Series Back Office — Lightspeed configures them. Send Lightspeed support a short request (template below). It is a one-time change per location.
  • US & Canada (tax-exclusive): tax is computed automatically from the store address (destination-based), so the new Upvendo order profiles inherit the correct rate with no per-profile assignment — and for a live account this is already configured with Lightspeed. Only Lightspeed staff can change tax rates. The tax method is imported automatically (taxIncluded = false → tax-exclusive), and there is no dine-in vs take-away rate split.

Copy-paste email to Lightspeed support (k-series.support@lightspeedhq.com, or your Lightspeed contact) — fill in the bracketed parts, and confirm the exact rates with your accountant first, since reduced take-away rates differ per country:

Subject: Tax rules for custom order profiles — [Business name] (Business ID [xxxxx])

Hi K-Series Support,

We use the Upvendo integration for online ordering / kiosk and have created dedicated order profiles for it in our Back Office. Could you please attach the correct tax rules to these profiles, the same way our built-in "Take away" profile is configured?

  • Business: [Business name] — Business ID [xxxxx]
  • Business Location ID: [xxxxxxxxxxxx]
  • upvtakeout (Pick up) and upvdelivery (Delivery): please apply our country's reduced take-away rates (same rules as the built-in Take away profile — e.g. food [x]%, non-alcoholic drinks [x]%).
  • upvdinein (eat-in): the standard on-site rates.

Thank you!

Belgium reference (verified in production use): take-away/delivery bill 6% on food and non-alcoholic drinks and 21% on alcohol; dine-in bills 12% food / 21% drinks / 21% alcohol. Other countries follow the same mechanism with their own rates — always confirm the target rates with your accountant before sending the email.

Step 4 — Verify before going live (± 5 min) ​

  1. Place one small take-away test order through your ordering channel.
  2. Check the receipt (POS, or Lightspeed Back Office reports): the food line must show the reduced rate. If it shows the standard rate, the tax rules from Step 3 are not attached yet — wait for Lightspeed's confirmation and re-test.
  3. With the standard full-payment push, a fully-paid order closes to Receipts — that is expected; the kitchen still receives the production ticket. (The "create unpaid + settle later" option that would keep it on the Orders screen is not offered yet.)

Skipping Steps 3–4 does not block ordering — orders still flow and totals are correct — but take-away/delivery would be billed at the standard rate instead of the reduced one until the rules are attached.


Cash on delivery: allow zero covers ​

If you offer cash on delivery (pay in person) on online orders, those orders reach Lightspeed unpaid and staff take the payment at the till. Pickup and delivery orders arrive with 0 covers — Lightspeed's take-away/delivery order API has no covers field, so Upvendo cannot send one. With default settings the till then refuses the payment with "The number of covers cannot be zero!".

Fix it once (± 1 min): Lightspeed Back Office → POS → Configurations → click your configuration → Order Management → enable Allow orders with zero covers → Save. Repeat for each POS configuration your tills use. (Lightspeed only shows this toggle when the order mode is With table service.)

  • Until then, staff can tap the covers badge on the order, enter a number (e.g. 1), and then take the payment.
  • Prepaid orders (Bancontact, card, …) are not affected — they arrive already paid.
  • After the payment is taken at the till, Upvendo checks Lightspeed about every 15 minutes and marks the order as collected at the till on its own. The order's Payment Details then read Paid in person · {time} · Lightspeed POS. Need it sooner? Use Mark as collected on the order. Only orders from the last two days are checked automatically; mark older ones by hand.
  • Seen live on a K-Series till (2026-10-01): a €3.50 cash-on-delivery order paid in cash was marked collected at the till, source Lightspeed POS, by the 15-minute check.

The Back Office path comes from Lightspeed's help article "Managing and understanding POS configurations"; it was not clicked through in a live Lightspeed Back Office. The covers error and the badge workaround were seen on a live K-Series till (2026-10-01).


When an order cannot be sent to Lightspeed ​

Every item and priced option needs a Lightspeed SKU ​

Upvendo sends each order line to Lightspeed by its SKU. If an order contains an item, or an option with a price, that has no Lightspeed SKU, Upvendo refuses to send the whole order. It no longer sends the order with that line silently missing.

What you see:

  • The location shows its POS connection as disconnected, with a message naming the item, e.g. Order … cannot be sent to Lightspeed: item "…" has no Lightspeed SKU. Give it a SKU in Lightspeed and re-sync the menu.
  • After a few automatic retries the order lands on the Stuck POS tab under Transactions.

What to do:

  1. In the Lightspeed Back Office, give the item (or the priced option) a SKU.
  2. In Upvendo, go to Lightspeed → Locations and click Sync now on that location.
  3. Upvendo keeps retrying the order on its own and sends it once the SKU is there. Or open it on the Stuck POS tab and click Retry POS Sync.

A free option (no price) without a SKU does not block the order — it is simply left off the ticket, so the kitchen will not see it. Give free options a SKU too if the kitchen needs them.

To avoid all of this: make sure every item and every priced option you sell through Upvendo has a K-Series SKU before you go live.

Verified in the backend code; not yet seen live on a till. A refused order is retried like any POS error, so one item without a SKU makes the whole location show as disconnected until it is fixed.

Orders voided, refunded or rejected on the POS are not sent again ​

Upvendo never sends an order to Lightspeed a second time once the POS has finished with it:

  • Voided or refunded at the till. The order is set to Cancelled in Upvendo and appears on the Stuck POS tab. Its activity line reads "voided on the POS, not re-sent: refund the customer by hand if they paid".
  • Permanently rejected by Lightspeed. Examples: an overpayment, an item without an accounting group, a location that isn't set up for online orders, or no till online to receive it for about half an hour (Lightspeed gives up after 5 delivery attempts). The order appears on the Stuck POS tab with Lightspeed's reason, and its activity line reads "not retried: enter it on the POS by hand or refund the customer".

Retry POS Sync will not resend these orders. It answers: "This order was cancelled or rejected by the POS and cannot be re-sent. Enter it on the POS by hand or refund the customer."

What to do: enter the order on the till by hand, or refund the customer. Upvendo does not refund automatically, for a voided order or a rejected one.

Seen live on a K-Series till (2026-09-30 / 10-01): a refund of a closed order on the till was not re-sent; an order placed while no till was online was retried 5 times, then showed Paid | POS FAILED on the Stuck POS tab, and both Retry POS Sync and the admin replay refused it. Tip: on the till, the refund action is only available after the order is closed.


Reconnecting / Token Expiry ​

Access tokens are refreshed automatically (proactively within a 5-minute buffer, plus a one-shot reactive refresh on a 401). If the refresh token is revoked or expires, the integration is flagged needs_reauth and a Reconnect banner appears.

To reconnect:

  1. Go to Lightspeed (/lightspeed) → Settings tab (a warning banner also appears when needs_reauth).
  2. Click Reconnect — this re-runs the full OAuth flow.
  3. Existing location mappings are preserved and the webhook is healed/re-linked automatically. A successful re-auth clears the needs_reauth status.

Troubleshooting ​

"I was redirected back but it shows an error" ​

  • The authorization may have been denied — try connecting again and confirm the authorization screen.
  • Ensure you are logged in to the correct Lightspeed account (a Restaurant K-Series account). L-Series and R-Series are not compatible.

"Connection test fails after connecting" ​

  • Go to the Status tab and click Test Connection (it calls /o/op/data/businesses).
  • If you see a needs_reauth banner, click Reconnect on the Settings tab to re-authorize.
  • Check the Lightspeed account is active and not suspended.

"Where do I find my business location ID?" ​

  • After a successful connection, the business ID is shown on the Status tab.
  • Your Lightspeed business locations are listed in the Locations tab, where you map each one to an Upvendo location.

"My location shows a 'Degraded' badge after syncing" ​

  • The menu did sync — the item count in the message is real. What did not happen is the modifier refresh: Lightspeed returned incomplete modifier / production-instruction data, so Upvendo left those groups alone rather than refreshing or deleting them. Nothing was lost. (Verified: upvendo-backend/app/Services/BackOffice/LightspeedKSeriesIntegrationService.php lines 4417-4433, 4452-4457, and 5778-5794.)
  • Click Sync now on that location's row in the Locations tab. The cause is usually transient and the next run clears the badge.
  • Full explanation, triggers, and escalation path: Lightspeed K-Series Integration → Troubleshooting.

"An order never reached the till" ​

  • Check the Stuck POS tab under Transactions. The row shows Lightspeed's reason.
  • "… has no Lightspeed SKU": give the item or priced option a SKU in Lightspeed, click Sync now, then Retry POS Sync (see When an order cannot be sent to Lightspeed).
  • "cannot be re-sent" when you click Retry POS Sync: the POS voided or permanently rejected the order. Enter it on the till by hand or refund the customer.
  • Orders only reach Lightspeed while a till is online for that business location. With no till online, Lightspeed gives up after about 5 minutes and Upvendo tries again, up to 5 times.

"The Connect Lightspeed K-Series step won't tick" ​

  • This step does not need a Test Connection click — it completes automatically when the OAuth connect succeeds. If it stays open, the business fetch after authorization failed.
  • Reconnect from /lightspeed → Settings tab, then check the Status tab and the integration logs for the error.