Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Viva Payments Laravel Package

sebdesign/laravel-viva-payments

Laravel integration for Viva Payments (Viva Wallet), giving you a clean, expressive API to create payment orders, handle transactions, and add the gateway to your Laravel apps. Includes configuration, facades, and support for the Viva Wallet Smart Checkout flow.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install and publish config: composer require sebdesign/laravel-viva-payments, then php artisan vendor:publish --tag=config (package auto-discovers its service provider and Viva facade). Everything you can tune lives in config/viva.php — read it top to bottom before writing code, since it defines the environment switch, credentials, and defaults.
  • Collect credentials from the Viva Wallet dashboard (Settings → API Access): merchant ID, API key, client ID and client secret, plus a payment source code (the 4-digit sourceCode) if you're doing Smart/Native Checkout. Put them in .env (VIVA_ENVIRONMENT=demo, VIVA_MERCHANT_ID, VIVA_API_KEY, VIVA_CLIENT_ID, VIVA_CLIENT_SECRET, VIVA_SOURCE_CODE) and never commit them.
  • Where to look first: config/viva.php → the Viva facade → the service classes under src/ (orders, transactions, webhooks, paymentSources, and their legacy equivalents). Services are the API surface; the facade is only a locator.
  • First use case — read before write. In php artisan tinker, fetch something you already know exists in the demo environment (e.g. an order or transaction by its code/ID). This proves credentials, environment, and token acquisition in one shot before you touch checkout or webhooks.
  • Second use case — take a payment. Create an order server-side, redirect the customer to the checkout URL for that order code, then confirm the outcome via webhook rather than trusting the browser redirect.
  • v6.5.0, in one line: if you route traffic through a proxy, a custom CA bundle, or need a non-default timeout, register those once instead of per call:
// AppServiceProvider::boot()
use GuzzleHttp\RequestOptions;
use Sebdesign\VivaPayments\Facades\Viva;

Viva::withRequestOptions([
    RequestOptions::TIMEOUT => 30,
    RequestOptions::PROXY => 'http://proxy.example.com:8080',
]);

Implementation Patterns

  • Wrap the package behind your own class. Don't sprinkle Viva:: calls through controllers. Create a small VivaGateway/PaymentService injected via the container; you get a single seam for logging, retries, correlation IDs, and tests. It also isolates you from method renames between major versions.
  • Order → checkout → webhook is the canonical flow. Create the order server-side (amounts in minor units, customer details, source code), hand the order code to the checkout screen, and treat the webhook as the source of truth for the final state. The browser redirect is UX only.
  • Webhooks are the integration point, not an afterthought. Add a route excluded from CSRF in bootstrap/app.php/VerifyCsrfToken, verify the payload with the verification key from the dashboard, return 200 immediately, and dispatch a queued job for the actual work. Viva retries deliveries, so make the handler idempotent — key off the order code / transaction ID and store a processed marker.
  • Keep a local mirror of transactions and orders. Persist orderCode, transactionId, status, and amount when you create an order and again on each webhook. You will need to reconcile, refund, and support customers long after the API response is gone.
  • Recurring/MIT payments: store the card payment source token plus display-safe metadata (brand, last 4, expiry), never raw PAN data. Token creation is a separate step from charging it; make the token reusable and audit it.
  • Layer request options deliberately. v6.5.0 establishes a precedence chain: per-request options (where a service method accepts an options array) override Viva::withRequestOptions(), which in turn overrides whatever Guzzle defaults the package config supplies. Use the global setter for infrastructure-wide settings (proxy, CA bundle, baseline timeout) and per-request options only for genuinely slow endpoints such as reports or large transaction listings.
  • Set request options in AppServiceProvider::boot(), guarded by environment if proxy/CA settings differ between demo and production. Don't call withRequestOptions() inside controllers — it's global state on a shared client.
  • Testing: the package talks Guzzle directly, so Laravel's Http::fake() won't intercept it. Fake at your own gateway boundary instead, or inject a Guzzle client with a MockHandler through the container binding.

Gotchas and Tips

  • v6.5.0 fixes a real, confusing bug: before it, options passed to individual service methods never reached the automatic access-token request. Behind a corporate proxy or with a custom CA bundle you'd get opaque token failures while every other call worked. If you previously worked around this by configuring Guzzle globally, upgrade and simplify.
  • withRequestOptions() is sticky global state. It merges into the client for all subsequent calls. Under Octane or in long-lived queue workers, set it once at boot — do not mutate it per request, and be aware there's no obvious per-request reset, so a leaked timeout will follow every later call.
  • Amounts are integers in the currency's smallest unit. 1050 is €10.50. Casting floats into order amounts silently produces wrong charges; keep an integer cast and validate at the boundary.
  • Demo vs production is a config switch, not a code path. Mismatched credentials produce 401s that look like token bugs. When a 401 appears, check VIVA_ENVIRONMENT first, then clear the cached access token — the package caches it for roughly the token lifetime, so rotated keys can appear to "not work" until the cache expires.
  • No Viva::fake(). There's no first-party test double; plan for that before you write a test suite.
  • Missing or wrong sourceCode is the most common cause of checkout creation failures — it's account-specific and differs per environment.
  • Debugging: RequestOptions::DEBUG => true (via withRequestOptions() or a per-call option) dumps full request/response including auth headers. Never leave it on in production logs. For less invasive tracing, add a logging middleware to the underlying client through a container rebind — the client is resolvable, and this is the cleanest extension point in the package.
  • Handle 429/5xx yourself. Don't assume retries exist; wrap idempotent GETs in a backoff and let webhooks absorb the rest rather than blindly retrying order creation.
  • Verify webhook signatures before parsing. Reject unverified payloads and log the raw body on failure — you'll need it when the dashboard and your database disagree.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console