Skip to content

Payment Provider Setup Guide ​

Overview ​

Upvendo integrates with exactly three payment providers in code: Stripe, Viva Wallet, and Square. There are no others (no Mollie, Adyen, or PayPal). The full list is defined in app/Enums/PaymentProviders.php:

text
viva  -> Viva Wallet
stripe -> Stripe
square -> Square

These three providers are not interchangeable alternatives for the same job. They each cover a different channel:

  • Stripe powers online-ordering payments (card and Bancontact), via a Stripe connected account that Upvendo onboards for the merchant on the business profile (called a payment profile in the API; the guided-setup step is Set up Business Profile). Stripe is also used for the merchant's own subscription billing to the Upvendo platform, and — as Stripe Terminal — it is one of the two in-person options (see below).
  • Viva Wallet powers kiosk / in-store terminal payments. It is the global kiosk default (config/upvendo.php kiosk_payment_provider defaults to viva) and one of the two in-person options.
  • Square is a full POS integration. When a merchant has connected Square, Square Terminal replaces the profile's in-person provider for kiosk payments (app/Services/Payment/PaymentService.php isSquareIntegrated() branch). Square also processes its own payments, so a merchant on Square does not configure a business profile.

A key structural fact that the back-office reflects: a single business profile holds BOTH the Stripe (online-ordering) configuration and the in-person configuration together. They are two sections of one profile, not two separate providers you pick between. See the per-profile status helpers (has_stripe, stripe_ready, has_viva_wallet, viva_wallet_verified) in src/views/settings/PaymentsComponent.vue:75-115.

In-person provider (a permanent choice) ​

Every business profile has an in-person payment provider, set when the profile is created, and it cannot be changed afterwards. The create dialog no longer asks for it: it asks only for Name and Country and sends in_person_provider: 'stripe' (NewPaymentProfileDialog.vue), so Viva Wallet is found only on profiles created with it earlier. Edit Location shows the provider read-only as In-Person Provider.

OptionStored valueWhat it means
Viva Walletviva_walletDedicated in-person account, independent from the Stripe online-ordering setup.
Stripe (Stripe Terminal)stripeOne Stripe account for online and in-person — one onboarding, one dashboard, one payout schedule.

The backend requires the field and accepts only those two values (app/Http/Requests/BackOffice/Settings/Payment/NewPaymentProfileRequest.php:47-54); the value is stored as the profile's processor and read back via getInPersonProvider() (app/RawModels/PaymentProfile.php:32,34,65-68).

At payment time PaymentService::processPaymentIntent() branches in this order (app/Services/Payment/PaymentService.php:211, branches at :233-249):

text
isSquareIntegrated()                      -> Square Terminal
transaction provider == 'stripe'          -> Stripe Terminal
otherwise                                 -> Viva Wallet

Online ordering is unaffected by this choice — non-kiosk channels always resolve to the platform online provider, Stripe (app/Services/Payment/TransactionService.php:856,865-876).

Where to set things up (real routes) ​

PageRouteSource
Settings → Business profile (list of business profiles)/settings/paymentssrc/plugins/1.router/additional-routes.ts:15-18
A single business profile — tabs Payments and Billing/settings/payments/profiles/:id (?tab=billing opens Billing)src/plugins/1.router/additional-routes.ts:20-23
Payouts for a profile/settings/payments/payouts/:idsrc/plugins/1.router/additional-routes.ts:25-28
Platform billing (subscription to Upvendo)the business profile's Billing tab. /settings/billing still resolves: it forwards to the Billing tab (one business profile) or the Business profile list (several); Square merchants and billing-only roles get the billing-profiles listsrc/views/settings/BillingComponent.vue, src/views/settings/PaymentsComponent.vue
Billing subscriptionsSubscriptions section of the Billing tab; /settings/billing/subscriptions/:id still exists for the subscription dialogssrc/plugins/1.router/additional-routes.ts:40-43

There is no /settings/payments/stripe, /settings/payments/viva-wallet, or /integrations/square route. Stripe and Viva Wallet are configured inside a business profile under /settings/payments. Square is connected from the "Add in-house channel" dialog (see the Square section below); its OAuth callback lands on /square, /square/success, or /square/error (typed-router.d.ts:125-127).

A note on prerequisites at integration connect time ​

When a merchant connects a third-party integration, the backend enforces only a default Branding profile for certain channels (Hendrickx, Vanhoutte, ShopCaisse, MplusKassa). Business (payment) and billing profiles are optional and can be set up later. This is explicit in app/Helpers/ThirdPartyIntegrationHelper.php:149-175 (comment at line 153):

// Payment and billing profiles are now optional - merchant can set them up later

So do not tell a merchant they must finish payment setup before connecting an integration — only Branding is required for the listed POS channels.


Stripe (online ordering + platform billing) ​

What it does ​

  • Processes online-ordering payments. The supported online payment methods are Card and Bancontact (app/Enums/PaymentMethodOptions.php). Card payments go through createZestidooPaymentOrder(); Bancontact goes through a dedicated Stripe PaymentIntent or Checkout Session (app/Services/Orchestrators/OnlineOrderingOrchestrator.php:556-582).
  • Routes funds to the merchant via a Stripe connected account using destination charges (stripe_account_id on the payment profile record, app/RawModels/PaymentProfile.php; use_destination_charges in config/services.php).
  • Handles the merchant's subscription billing to the Upvendo platform through a billing profile that stores a stripe_customer_id (app/RawModels/BillingProfile.php), managed on the business profile's Billing tab.

iDEAL is not an online-ordering payment method in Upvendo. The only Stripe online payment methods in code are Card and Bancontact (app/Enums/PaymentMethodOptions.php). The string "iDEAL" only appears inside the Viva Wallet kiosk fee/transaction code (app/Services/Common/VivaWalletService.php:319,527), not in the online checkout path.

How a merchant connects Stripe ​

Stripe uses Stripe Connect onboarding (Upvendo creates and onboards a connected account for the merchant), not a "connect your existing Stripe account" OAuth login. In the back-office:

  1. Go to Settings > Business profile (/settings/payments).
  2. Click New Profile — the New Payment Profile dialog asks only for Name and Country; Stripe is set as the in-person provider for you. Submit with Setup Profile. (src/views/settings/Payments/NewPaymentProfileDialog.vue.)
  3. Open the business profile (/settings/payments/profiles/:id) and, on its Payments tab, start Stripe onboarding (the embedded Stripe onboarding flow — src/views/settings/Payments/PaymentProfileDetail.vue:335,494-495).
  4. Complete Stripe's hosted verification (business details, bank account for payouts) inside the onboarding flow.
  5. The profile shows a Stripe status: not configured / setup incomplete / action required / ready (src/views/settings/PaymentsComponent.vue:93-115).

Online-ordering payment flow ​

text
Customer places an online order
    |
    v
Order channel resolves payment_provider = stripe (config/upvendo.php zestidoo_payment_provider, default "stripe")
    |
    v
Customer selects a payment method
    |
    +---> Card:       Stripe payment order created (createZestidooPaymentOrder)
    +---> Bancontact: Stripe PaymentIntent or Checkout Session (createStripeBancontact*)
    |
    v
Stripe webhook confirms the payment (StripeWebhookOrchestrator)
    |
    v
Order marked paid; pushed to kitchen/POS

Important notes ​

  • Stripe is the default online-ordering payment provider (config/upvendo.php zestidoo_payment_provider defaults to stripe).
  • Funds settle to the merchant's connected Stripe account; the Upvendo platform takes its margin via destination charges (config/services.php).
  • Two deferred methods sit alongside the online ones: Cash on delivery and Invoice (Mplus locations only). Both skip online payment collection entirely — the order reaches the POS open/unpaid and is settled there. There is no separate "Cash on Pickup" option; pickup and delivery both use Cash on delivery.
  • Cash on delivery is available to merchants, under Online Ordering → Checkout → Payment methods. It is off by default, and the toggle is hidden on locations whose POS cannot accept an unpaid order — see below.

Viva Wallet / Stripe Terminal (in-person payments) ​

What it does ​

  • Processes kiosk / in-store terminal payments. Which one runs is the profile's in-person provider (see above); Viva Wallet is also the global fallback default (config/upvendo.php kiosk_payment_provider defaults to viva).
  • Viva Wallet drives a physical Viva terminal through the Viva Terminal API (app/Services/Payment/PaymentService.php processVivaWalletPayment() / initiateTerminalSale(); the integration is configured as a Viva ISV/OAuth setup in config/services.php).
  • Stripe Terminal drives a Stripe reader through processStripeTerminalPayment() on the same service, using the merchant's existing Stripe connected account on the business profile.

How a merchant connects Viva Wallet ​

Viva Wallet is configured inside a business profile at /settings/payments — it is not a separate top-level page:

  1. Go to Settings > Business profile (/settings/payments) and open a business profile whose in-person provider is Viva Wallet (new profiles are created with Stripe).
  2. Set up the Viva Wallet account through the in-profile dialogs (src/views/settings/Payments/EditVivaWalletAccountDialog.vue, src/views/settings/Payments/VivaAccountIdDialog.vue). These walk the merchant to their Viva Wallet account to retrieve the required account identifier.
  3. The profile shows a kiosk status: not configured / setup incomplete / ready (src/views/settings/PaymentsComponent.vue:75-91).
  4. The physical terminal is assigned per device. Unverified (kiosk-app side): the exact terminal-pairing UX on the kiosk device is outside these two repos.

Kiosk payment flow ​

text
Kiosk submits an order for payment
    |
    v
Channel = Kiosk -> payment_provider = the location profile's in-person provider
                   ('stripe'), else config('upvendo.kiosk_payment_provider') (default "viva")
    |
    v
PaymentService.processPaymentIntent:
    if isSquareIntegrated()          -> Square Terminal
    elif provider == 'stripe'        -> Stripe Terminal
    else                             -> Viva Wallet terminal
    |
    v
Terminal prompts "tap/insert card"
    |
    v
Terminal session status polled; payment confirmed
    |
    v
Order completed and synced to the POS/KDS

Important notes ​

  • Viva Wallet is for terminal payments, not online checkout. Stripe Terminal is likewise in-person only — online ordering always goes through the Stripe online path.
  • When the merchant has connected Square, kiosk payments route to Square Terminal regardless of the profile's in-person provider (app/Services/Payment/PaymentService.php isSquareIntegrated() branch).
  • Unverified (kiosk-app side): "tips on terminal", receipt printing, and firmware details are kiosk/terminal concerns and are not defined in the back-office or backend repos.

Square (full POS integration with built-in payments) ​

What it does ​

  • A full in-house POS integration: catalog/menu sync with Square plus payment processing.
  • Square processes its own payments, so no business profile is needed. When Square is connected, the Business profile page (/settings/payments) hides the New Profile button and shows the billing-profiles list (for roles that can view billing profiles) or else a "Square is handling your payments" placeholder (src/views/settings/PaymentsComponent.vue:118-130 and the is_square_integrated template branch). A Square merchant's location keeps a plain Billing Profile picker, since there is no business profile to derive billing from.
  • For kiosk payments, Square Terminal replaces Viva Wallet (app/Services/Payment/PaymentService.php isSquareIntegrated() -> processSquarePayment()).

How a merchant connects Square ​

Square is connected via OAuth from the "Add in-house channel" dialog (the same place merchants connect Hendrickx, MplusKassa, Lightspeed K-Series, etc.), not from a dedicated /integrations/square route:

  1. Open the "Add in-house channel" flow and choose Square (src/components/dialogs/channels/SquareChannelDialog.vue).
  2. Authorize. The back-office calls the backend, which builds a Square OAuth authorization URL (app/Http/Controllers/Api/BackOffice/SquareIntegrationController.php:45-133, initiateOAuth()).
  3. Complete Square's OAuth consent. The callback returns to the back-office at /square / /square/success / /square/error (typed-router.d.ts:125-127).
  4. After connecting, Square catalog data syncs into Upvendo. (Sync direction and timing are managed by the Square integration service — startSync/updateSyncTime in SquareIntegrationController.)

The Square OAuth dialog notes that a default Billing profile is recommended (channels.add_inhouse_channel.square.no_default_billing_profile in src/components/dialogs/channels/SquareChannelDialog.vue), but per ThirdPartyIntegrationHelper::checkRequiredProfiles() only a Branding profile is enforced — billing remains optional at connect time.

Square flow ​

text
Square connected via OAuth (SquareIntegrationController.initiateOAuth)
    |
    v
Square catalog synced into Upvendo (Square integration service)
    |
    v
Kiosk payments route to Square Terminal (PaymentService.isSquareIntegrated -> processSquarePayment)
    |
    v
Square settles payouts to the merchant's bank account

Important notes ​

  • When Square is connected, the back-office treats Square as the payment handler: the Business profile page hides profile creation and shows the billing-profiles list or the Square placeholder (src/views/settings/PaymentsComponent.vue).
  • For kiosk payments specifically, the isSquareIntegrated() check in PaymentService routes the terminal payment through Square instead of Viva Wallet (app/Services/Payment/PaymentService.php).
  • Unverified (storefront side): exactly how online-ordering checkout renders for a Square merchant (e.g. Square Web Payments SDK) is a storefront concern not present in these two repos. Do not assert it as fact.

Deferred methods (Cash on delivery and Invoice) ​

What they do ​

A deferred method collects no money online. The customer confirms the order, it is sent to the POS open and unpaid, and the money is taken in person — cash (or whatever the cashier accepts) at the counter or at the door. Nothing passes through Upvendo or a payment provider, so there is no online charge to refund and no provider dashboard entry for the payment.

There are two, and they are configured in the same place: Online Ordering → Checkout → Payment methods, per location.

Cash on deliveryInvoice
Customer sees"Pay on pickup" or "Pay on delivery", depending on the order type"Invoice"
DefaultOffOff
Who can use itAny customerBusiness (B2B) customers on Mplus locations
Available onMost POS setups — see belowMplus locations only
How it settlesCash taken at the tillBilled afterwards from the Invoice Collection page

Where Cash on delivery is not available ​

The toggle does not appear for locations connected to ShopCaisse or Square. Those two cannot take an order that has not already been paid — ShopCaisse would book it as paid online, leaving the till short at the end of the day, and Square would never receive the order at all. Mplus, Kassanet (Hendrickx / Vanhoutte), Lightspeed K-Series and locations with no POS integration all accept an unpaid order and show the toggle normally.

The same rule is enforced when the order is placed, not just in the back office, so a customer cannot reach Cash on delivery on one of those POS setups even if the setting was turned on earlier.

Turning Cash on delivery on ​

  1. Go to Online Ordering → Checkout for the location.
  2. Under Payment methods, switch on Cash on delivery.
  3. Save.

It applies to both pickup and delivery. There is currently no way to offer it for only one of the two.

After the order is placed ​

A Cash on delivery order is a normal order: it goes to the kitchen and to the POS like any other, and it appears in the back office straight away. What differs is the money.

  • Its payment status reads Pay in person until the cash is confirmed collected, then Paid at till.
  • It is not counted in Total Collected, because that figure is money that arrived through Upvendo and this money never did. It sits in Total Pending until it is settled, then moves to Collected at till.
  • On Mplus locations, Upvendo reads settlement back from the POS automatically, so an order paid at the till clears on its own within about fifteen minutes. On every other POS, and for anything the POS did not attribute to the order, use Mark as collected on the order.
  • Orders nobody came to pay for show up under the Uncollected tab on Transactions — see Transactions.

Choosing the right setup ​

Online ordering (Card + Bancontact) ​

Set up Stripe inside a business profile at Settings → Business profile (/settings/payments). Card and Bancontact are the supported online methods. Two deferred methods can be offered alongside them from Online Ordering → Checkout → Payment methods: Cash on delivery (on most POS setups) and Invoice (Mplus locations only). Both are off until the merchant turns them on — see Deferred methods.

Kiosk / in-store terminal (no Square) ​

Create a business profile at Settings → Business profile (/settings/payments); new profiles use Stripe as their in-person provider (Stripe Terminal — one Stripe account for online and in-person), and a profile created earlier with Viva Wallet keeps it, since the provider cannot be changed. Then finish that provider's onboarding inside the profile and link the location to it (Edit Location → Business Profile).

POS + payments in one (Square) ​

Connect Square from the "Add in-house channel" flow. Square then handles both its catalog sync and payments (kiosk terminal payments route to Square Terminal), and you do not create a business profile.

Both online and kiosk (no Square) ​

A single business profile covers both: Stripe for online ordering plus the profile's in-person provider (Viva Wallet or Stripe Terminal) for the kiosk terminal. They are two sections of the same profile, configured at /settings/payments. With Stripe as the in-person provider (every new profile) there is one Stripe account, one dashboard and one payout schedule for everything.


Common Issues ​

"Payment could not be processed" ​

  • Confirm the relevant provider is set up in the business profile (Stripe section ready for online; Viva Wallet section verified for kiosk) at /settings/payments.
  • Verify the order's payment method is one of the supported methods (Card, Bancontact, or Invoice for Mplus).
  • Check the provider dashboard (Stripe / Viva Wallet / Square) for declined transactions. Unverified (external dashboards): behavior in those external dashboards is outside Upvendo's codebase.

Kiosk terminal not responding ​

  • Confirm the kiosk's payment provider: the business profile's in-person provider (Viva Wallet or Stripe Terminal), or Square Terminal if the merchant is on Square.
  • Verify the terminal is powered on and online, and assigned to the device.
  • Unverified (kiosk-app side): terminal pairing, re-pairing, and firmware steps are kiosk/terminal concerns not defined in these repos.

Missing online payment methods at checkout ​

  • Verify the business profile's Stripe section is ready (/settings/payments).
  • Remember only Card and Bancontact are online card-style methods. Cash on delivery and Invoice (Mplus-only) are deferred methods that settle POS-side, and each has its own toggle under Online Ordering → Checkout → Payment methods — a customer will not see either until that toggle is on.
  • If the Cash on delivery toggle is missing from that page entirely, the location's POS cannot accept an unpaid order — see Deferred methods.
  • For Square merchants: payment configuration is handled by the Square integration, not a business profile — confirm the Square connection is active.