Skip to content

Viva Wallet Integration

Overview

Viva Wallet is Upvendo's kiosk / in-person card-terminal payment provider. Online ordering always uses Stripe (and when Square POS is connected, Square handles everything). A merchant's Viva Wallet connection lives on a payment profile: you set it up once on the profile detail page, which creates a Viva Wallet connected account through Upvendo's ISV (Independent Software Vendor) integration. The merchant then completes onboarding on Viva Wallet's own dashboard.

There are no merchant-entered Viva credentials in the back office (no API key, API secret, merchant ID, or source-code fields). Authentication is handled at the platform level using Upvendo's ISV OAuth credentials; the back office only shows read-only Viva account details once the account is created.

Key purpose: Process card payments on physical Viva terminals at kiosks / point of sale.

Note: When Square POS is connected, Square Payments is used instead of Viva Wallet for kiosk/in-person payments.

Purpose

This page (the payment profile detail page) lets you set up a Viva Wallet connected account for kiosk/in-person card payments and view its read-only account details. Terminals themselves are assigned per device in Device Management, not here.

Key Concepts

  • ISV model (config-level OAuth): Upvendo connects to Viva Wallet as an ISV partner ("Upvendo"). All Viva API calls authenticate with platform-level ISV/reseller credentials (services.viva.{eu|us}.client_id / secret_key / reseller_id / reseller_secret) selected by country (US vs EU). There is no per-profile API key.
  • Connected account: Setting up Viva on a payment profile calls Viva's ISV "create account" endpoint, stores the result under external_data.viva_wallet, and returns a redirect URL where the merchant finishes onboarding on Viva's dashboard.
  • Account ID / Merchant ID: viva_wallet.accountId is the ISV connected-account identifier; viva_wallet.merchantId scopes payment/terminal API calls to that merchant. Both are displayed read-only in the back office.
  • Terminal sale (Cloud ECR API): A kiosk payment creates a terminal session identified by an idempotency key (used as the sessionId), sent to the assigned physical terminal via Viva's Cloud ECR API; the session status is then polled until the customer taps/inserts their card.
  • Source codes (deprecated): Per-location Viva online/physical source codes are no longer generated. Existing values are preserved; new locations use the source code 'Default'.
  • Pre-authorization / capture: Some flows create a pre-auth and capture later. Whether a transaction is a pre-auth is read from the transaction's payment_snapshot['preauth'] (isVivaWalletPreauth()); when true, the verification step captures the transaction.

Actions

Set Up Viva Wallet Account

On the payment profile detail page, click Setup Viva Wallet Account. This creates a Viva Wallet connected account via Upvendo's ISV integration and opens Viva's onboarding/signup page (a redirect URL returned by Viva). No credentials are entered in Upvendo.

View / Edit Viva Wallet Account

Once created, the profile shows a read-only Viva Wallet Account section (Account ID, Merchant ID, Email, Acquiring Enabled, Legal Name, VAT Number, and a verified/not-verified status). The Edit action opens a dialog that displays the Account ID (with copy) and a link to the Viva Wallet dashboard (accounts.vivapayments.com) — it does not edit credentials in Upvendo; account changes are made on Viva's side.

Assign a Terminal to a Device

Physical terminals are assigned per device (kiosk), not on the payment profile. In Device Management → Devices, open the device's Reader / Terminal section and Add Terminal → Assign Viva Terminal, then pick a terminal from the list available on the merchant's Viva account. (See the Payments feature for the full per-provider pairing flow.)

When Viva Wallet is Used

ChannelPayment providerNotes
Online OrderingStripeCustomer web payments through the profile's Stripe connected account (Viva is not the online provider)
Kiosk / In-Person (terminal)Viva WalletCard payment on the physical Viva terminal assigned to the kiosk device
Any channel when Square POS connectedSquare PaymentsSquare overrides both Stripe and Viva Wallet

A legacy Viva "web payment order" path (createPaymentOrder) still exists in the backend and can drive a hosted Viva checkout (with a country-default method — iDEAL for NL, Bancontact QR for BE, Klarna for DE, Multibanco for PT), but the primary online-ordering provider is Stripe.

Location

  • Backoffice route: payment profile detail page — /settings/payments/profiles/:id (Viva is set up here, not at a dedicated /settings/payments/viva-wallet page)
  • Setup endpoint: POST /payment-profiles/{id}/viva-wallet/accountPaymentProfileController::createVivaWalletAccount
  • Backend service: app/Services/Common/VivaWalletService.php
  • Account model accessors: app/RawModels/PaymentProfile.php (getVivaWalletAccountId(), retrieveVivaWalletData())
  • Back-office components: src/views/settings/Payments/PaymentProfileDetail.vue, EditVivaWalletAccountDialog.vue, VivaAccountIdDialog.vue; terminal assignment in src/views/devices/components/setup-device/reader-section/ReaderSection.vue

Fields

There are no Viva credential or toggle fields in the back office. Setting up Viva is a single Setup Viva Wallet Account action that creates a connected account; everything else is read-only and is sourced from Viva.

Read-only Viva Wallet account details (shown after setup)

FieldSourceNotes
Account IDviva_wallet.accountIdISV connected-account ID (copyable)
Merchant IDviva_wallet.merchantIdScopes payment/terminal API calls
Emailviva_wallet.emailOnboarding email
Acquiring Enabledviva_wallet.acquiringEnabledShown as Enabled/Disabled
Legal Nameviva_wallet.legalNameShown if present
VAT Numberviva_wallet.vatNumberShown if present
Verifiedviva_wallet.verifiedDrives the verified / not-verified status badge

Onboarding (and any credential / business-detail changes) happens on Viva Wallet's dashboard, not in Upvendo.

Test mode (per location, not a Viva field)

Test/simulation is not a Viva Wallet setting. It is the per-location payment_test_mode flag (toggled from the profile detail page's Locations list) that simulates payments for both Stripe and Viva without real charges. See the Payments feature.

Business Logic

Kiosk terminal payment flow

Customer completes kiosk order
        |
        v
Provider check: Square integrated?
  Yes -> route to Square Terminal
  No  -> Viva Wallet terminal sale
        |
        v
initiateTerminalSale (Cloud ECR API)
  sessionId = idempotency key
  terminalId = device's assigned Viva terminal
  amount + tipAmount, merchant/source from location
        |
        v
Card terminal activated -> customer taps/inserts card
        |
        v
Status polled / webhook received -> payment verified
        |
        v
Order confirmed

Online ordering (for contrast)

Online ordering creates a Stripe PaymentIntent on the profile's Stripe connected account (or Square when connected). The Viva createPaymentOrder web-checkout path is a fallback, not the primary online flow.

Webhook capture and retention

Every inbound Viva webhook is persisted losslessly at ingestion — before the duplicate guard and before location resolution — because Viva offers no dashboard resend. If an event cannot be matched to a location, or arrives as a duplicate, the raw payload is still on file and replayable.

  • Stored in the shared logs collection under type: 'viva_webhook'.
  • The capture is an idempotent upsert keyed on {webhook_id, type}, where webhook_id is a content hash. A redelivery increments occurrences rather than inserting a second row, and created_at is written only on insert because it anchors the TTL.
  • Capture failures are swallowed — the payment path is never blocked by a logging problem (a warning is logged instead).
  • Retention is a partial TTL index scoped to type: 'viva_webhook', 90 days (expireAfterSeconds: 7776000), so it prunes only these PII-bearing receipts and never touches other documents in the shared collection.

This is platform behaviour, not a merchant-facing setting. It does not contradict compliance.md's statement that there are no merchant-configurable data-retention settings — there still are none.

Business Rules

  • Kiosk only: Viva Wallet is the kiosk/in-person provider. Online ordering uses Stripe; the provider is chosen at payment time (isSquareIntegrated() → Square, otherwise Viva for kiosk / Stripe for online).
  • Square overrides Viva: When Square POS is connected, kiosk payments route to Square Terminal instead of Viva.
  • ISV / config-level auth: All Viva calls use platform ISV/reseller credentials selected by country (us vs eu); there is no per-profile/per-location API key. ISV partner name is "Upvendo".
  • One connected account per profile: Setting up Viva when an account already exists is rejected (Viva Wallet account already exists for this payment profile).
  • Default profile needs verification: A profile can be set as default only when Viva-verified (or its Stripe online ordering is ready).
  • Source codes deprecated: New locations use the 'Default' source code; existing per-location online/physical source codes are preserved but no longer generated.
  • Idempotency / 409 retry: Each terminal sale uses an idempotency key as the sessionId; on a 409 conflict the system generates a new idempotency key and retries. The device's latest_idempotency_key is updated after each initiation, and the transaction tracks all_idempotency_keys.
  • Amounts in cents: Amounts are normalized to the smallest currency unit before being sent to Viva; currency is sent as Viva's numeric code (EUR 978, GBP 826, USD 840, CHF 756).
  • Environment URLs: Base URLs switch by isProduction (derived from ! isTestEnv()): production uses api.vivapayments.com / www.vivapayments.com / accounts.vivapayments.com; non-production uses the demo-api / demo / demo-accounts equivalents.
  • Webhook security: Viva webhooks are received at /api/viva-webhook/{countryCode}/{eventTypeId}. There is no per-request signature; GET returns the verification key, and POST is protected by IP allowlisting (verify.viva-webhook middleware, production vs demo Viva IP ranges). (Verified: routes/api/guest.php lines 44-47 — the file applies guest as middleware, not as a URL prefix — required from routes/api.php line 38 outside any prefix group, under Laravel's /api prefix from bootstrap/app.php line 14. The comment at routes/api.php line 15 still says /api/guest/... and is stale.)
  • Every webhook is captured for 90 days: Each inbound Viva webhook is persisted to the shared logs collection (type: 'viva_webhook', status: 'received') before the duplicate guard and before location resolution, so every event stays replayable — Viva offers no dashboard resend. Retention is a partial TTL of 90 days (7,776,000s) scoped to that type. (Verified: app/Services/Orchestrators/VivaWebhookOrchestrator.php lines 41-45 and 196-207; app/Repositories/RequestLogRepository.php lines 67-96 and 105-133.)

FAQs

  • "Is Viva Wallet used for online ordering?" No. Online ordering uses Stripe (or Square when connected). Viva Wallet is the kiosk / in-person card-terminal provider. (A legacy Viva web-checkout path exists in the backend but is not the primary online flow.)

  • "Where do I enter my Viva Wallet API key / merchant ID / source code?" You don't. Upvendo authenticates with Viva at the platform level (ISV OAuth). Setup is a single Setup Viva Wallet Account button that creates a connected account; the back office then shows read-only details (Account ID, Merchant ID, etc.). You finish onboarding on Viva's dashboard.

  • "How do I connect Viva Wallet?" On the payment profile detail page, click Setup Viva Wallet Account. Upvendo creates the connected account and opens Viva's onboarding page. Complete onboarding there; the profile then shows your Viva account details and a verified status.

  • "How do I add a Viva terminal to a kiosk?" In Device Management → Devices, open the device, go to the Reader / Terminal section, choose Add Terminal → Assign Viva Terminal, and pick a terminal from your Viva account. Terminals are assigned per device, not on the payment profile.

  • "Can I use Viva Wallet and Square at the same location?" No. At payment time the system checks isSquareIntegrated() and routes to one provider. If Square POS is connected, kiosk payments go through Square instead of Viva.

  • "What happens if the customer doesn't tap their card?" The terminal session stays pending until it times out; the session can be aborted (its idempotency key is tracked), and a retry generates a fresh idempotency key.

  • "What countries / currencies are supported?" ISV credentials are chosen by region (US vs EU). Currency is mapped per country (EUR for BE/NL/DE/FR/IT/ES/PT, GBP for GB, CHF for CH) and sent to Viva as a numeric code.

  • "How are tips handled?" The tip is sent as a separate tipAmount on the terminal sale, captured as part of the same transaction. Whether tips are collected (and the percentage options) is configured at the location/device Collect Tips settings, not on Viva.

Troubleshooting

Kiosk/terminal payments failing

Causes:

  1. No Viva terminal assigned to the device
  2. Viva connected account not verified / onboarding incomplete
  3. Location is in test mode (payment_test_mode) and being simulated
  4. Square is connected, so payments route to Square instead

Solutions:

  1. Assign a terminal in Device Management → Devices → Reader/Terminal
  2. Complete onboarding on Viva's dashboard until the account shows verified
  3. Check the location's test-mode setting on the profile detail page
  4. If using Square, manage kiosk payments through Square

Terminal not responding

Causes:

  1. Terminal offline or powered down
  2. Wrong terminal assigned to the device
  3. Network issue between terminal and Viva Cloud

Solutions:

  1. Check terminal power and connectivity
  2. Re-assign the correct Viva terminal to the device
  3. Check network; the system retries on session conflicts (409) with a new idempotency key

"Viva Wallet account already exists for this payment profile"

A profile can hold only one Viva connected account. The account is already set up — view/edit it from the profile detail page rather than creating a new one.

Assistant Guidance

When answering questions about Viva Wallet:

  • Viva Wallet is the kiosk / in-person provider. Online ordering uses Stripe; Square overrides both when connected.
  • There are no Viva credential fields (API key/secret, merchant ID, source code) in the back office — auth is platform-level ISV OAuth. Do not describe a credentials form.
  • Setup is the Setup Viva Wallet Account button on the payment profile detail page; onboarding finishes on Viva's dashboard. Back-office Viva details are read-only.
  • Terminals are assigned per device (kiosk) in Device Management, not on the payment profile.
  • Per-location source codes are deprecated (new locations use 'Default').
  • Test mode is a per-location setting (payment_test_mode), not a Viva setting.

Relations

Depends On

  • Payment Profiles: The Viva connected account lives on a payment profile (external_data.viva_wallet).
  • Locations: A profile is assigned to locations; the location carries the Viva merchant ID and (deprecated) source codes.
  • Devices: A physical Viva terminal is assigned per device for kiosk payments.

Affects

  • Kiosk payments: Terminal sales, refunds, and pre-auth/capture.
  • Transactions: Viva order/session records and payment verification.
  • Commission / Reporting: Viva terminal IDs are tracked on the merchant for commission attribution.

Storefront / payment-proxy behavior (how the hosted Viva checkout or the kiosk app surface the terminal prompt to the customer) is not verified here.