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. 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 separate Payment Profile.

A key structural fact that the back-office reflects: a single Payment 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)

Creating a Payment Profile requires picking an in-person payment provider, and the choice cannot be changed afterwards. The dialog says so explicitly: "This choice is permanent. You won't be able to change the in-person provider after the profile is created."

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
Payment Profiles (Stripe + in-person provider)/settings/paymentssrc/plugins/1.router/additional-routes.ts:15-18
A single Payment Profile detail/settings/payments/profiles/:idsrc/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)/settings/billingsrc/plugins/1.router/additional-routes.ts:35-38
Billing subscriptions/settings/billing/subscriptions/:idsrc/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 Payment 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). 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, app/RawModels/PaymentProfile.php; use_destination_charges in config/services.php).
  • Handles the merchant's subscription billing to the Upvendo platform through a separate Billing Profile that stores a stripe_customer_id (app/RawModels/BillingProfile.php), managed at /settings/billing.

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 > Payments (/settings/payments).
  2. Create a Payment Profile via the New Profile dialog — the fields are name, country, and in-person payment provider (Viva Wallet or Stripe Terminal, rendered as selectable cards; this choice is permanent). Submit with Setup Profile. (src/views/settings/Payments/NewPaymentProfileDialog.vue:149-227.)
  3. Open the profile (/settings/payments/profiles/:id) and 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).
  • Deferred online methods also exist in the backend: Cash on Delivery (universal) and Invoice (Mplus-only) skip online payment collection entirely and settle POS-side (app/Enums/PaymentMethodOptions.php). There is no separate "Cash on Pickup" toggle in this code — the deferred cash method is CashOnDelivery.
  • The Cash on Delivery toggle is hidden in the production back office. src/views/online/online-ordering/forms/Checkout.vue:96-97 wraps it in v-if="!isProduction" ("hidden in production while the cod_available_for plumbing isn't fully wired"). In production, only Invoice appears under Online Ordering → Checkout → Payment methods, and only for Mplus tenants. Do not tell a production merchant to enable Cash on Delivery.

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.

How a merchant connects Viva Wallet

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

  1. Go to Settings > Payments (/settings/payments) and open (or create) a Payment Profile.
  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 separate Payment Profile is needed. When Square is connected, the Payment Profiles page (/settings/payments) hides the "new profile" button and shows a "Square is handling your payments" placeholder instead (src/views/settings/PaymentsComponent.vue:118-130 and the is_square_integrated template branch).
  • 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 Payment Profiles page hides profile creation and shows 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.

Choosing the right setup

Online ordering (Card + Bancontact)

Set up Stripe inside a Payment Profile at /settings/payments. Card and Bancontact are the supported online methods. On Mplus locations, Invoice can additionally be offered as a deferred method. (Cash on Delivery exists in the backend but its toggle is hidden in the production back office — see the Stripe notes above.)

Kiosk / in-store terminal (no Square)

Pick the profile's in-person provider when you create it at /settings/payments: Viva Wallet (separate in-person account) or Stripe (Stripe Terminal — one Stripe account for online and in-person). The choice is permanent, so decide before creating the profile. Then finish that provider's onboarding inside the 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 separate Payment Profile.

Both online and kiosk (no Square)

A single Payment 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. Choosing Stripe as the in-person provider means 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 Payment 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 Payment 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 Payment Profile's Stripe section is ready (/settings/payments).
  • Remember only Card and Bancontact are online card-style methods; Invoice (Mplus-only) is a deferred method that settles POS-side. Cash on Delivery is not selectable in the production back office.
  • For Square merchants: payment configuration is handled by the Square integration, not a Payment Profile — confirm the Square connection is active.