qrcommunication/viva-merchant-sdk

PHP SDK for Viva Wallet Merchant API — orders, transactions, sources, webhooks

Maintainers

Package info

github.com/QrCommunication/sdk-php-viva-merchant

pkg:composer/qrcommunication/viva-merchant-sdk

Statistics

Installs: 62

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.4.0 2026-03-18 19:59 UTC

This package is auto-updated.

Last update: 2026-03-18 19:59:56 UTC


README

Version 1.3.5 PHP 8.2+ License: MIT Packagist

SDK PHP complet pour l'intégration Viva Wallet. Couvre 9 ressources : Orders, Transactions, Sources, Wallets, BankAccounts, NativeCheckout, DataServices, Account et Webhooks.

PHP 8.2+ requis. Compatible Laravel, Symfony, ou tout projet PHP.

Ce SDK couvre les opérations marchands standard. Pour les opérations ISV (comptes connectés, composite auth), voir sdk-php-viva-isv.

Table des matières

Installation

composer require qrcommunication/viva-merchant-sdk

Prérequis : PHP 8.2+ avec ext-json et ext-curl.

Démarrage rapide

use QrCommunication\VivaMerchant\VivaClient;

$viva = new VivaClient(
    merchantId: 'votre-merchant-uuid',
    apiKey: 'votre-api-key',
    clientId: 'xxx.apps.vivapayments.com',
    clientSecret: 'votre-client-secret',
    environment: 'demo', // ou 'production'
);

// Créer un ordre de paiement
$order = $viva->orders->create(amount: 1500, customerDescription: 'Consultation');
// Rediriger le client vers $order['checkout_url']

// Vérifier une transaction après paiement
$txn = $viva->transactions->getV2('transaction-uuid');

// Rembourser
$viva->transactions->cancel('transaction-uuid', amount: 500);

// Capturer une pré-autorisation
$viva->transactions->capture('preauth-uuid', amount: 1500);

// Charge récurrente
$viva->transactions->recurring('initial-txn-uuid', amount: 1500);

// Apple Pay / Google Pay
$token = $viva->nativeCheckout->createChargeToken(1500, $applePayData);
$txn = $viva->nativeCheckout->createTransaction($token['chargeToken'], 1500);

// Tester la connexion
$viva->testConnection(); // true ou false

Référence des ressources

1. Orders — $viva->orders

Ordres de paiement Smart Checkout.

create() — Créer un ordre

$order = $viva->orders->create(
    amount: 1500,                         // Centimes (15,00 EUR)
    customerDescription: 'Consultation',  // Affiché au client
    merchantReference: 'session_123',     // Référence interne
    allowRecurring: true,                 // Tokeniser la carte
    preauth: false,                       // Pré-autorisation ?
    maxInstallments: 3,                   // Paiement en 3x
);

echo $order['order_code'];   // 1234567890
echo $order['checkout_url']; // https://demo.vivapayments.com/web/checkout?ref=1234567890
Paramètre Type Défaut Description
amount int requis Montant en centimes
customerDescription ?string null Texte affiché au client
merchantReference ?string null Référence interne (exports)
sourceCode ?string null Source de paiement
allowRecurring bool false Autoriser les charges récurrentes
preauth bool false Pré-autorisation uniquement
maxInstallments int 0 Nombre max de versements

Retour : array{order_code: int, checkout_url: string}

get() — Statut d'un ordre

$order = $viva->orders->get(orderCode: 1234567890);

cancel() — Annuler un ordre non payé

$viva->orders->cancel(orderCode: 1234567890);

checkoutUrl() — URL de checkout (sans appel API)

$url = $viva->orders->checkoutUrl(orderCode: 1234567890);
// 'https://demo.vivapayments.com/web/checkout?ref=1234567890'

2. Transactions — $viva->transactions

Consultation, remboursement, capture et paiements récurrents.

get() — Détails complets (Legacy API, PascalCase)

$txn = $viva->transactions->get('transaction-uuid');
echo $txn['Transactions'][0]['Amount'];
echo $txn['Transactions'][0]['StatusId'];

getV2() — Détails légers (New API, camelCase)

$txn = $viva->transactions->getV2('transaction-uuid');
echo $txn['email'];
echo $txn['amount'];      // En EUR (pas en centimes)
echo $txn['statusId'];    // 'F'
echo $txn['orderCode'];

Recommandé pour vérifier les paiements Smart Checkout.

listByDate() — Lister par date

$transactions = $viva->transactions->listByDate('2026-03-18');

foreach ($transactions as $txn) {
    echo $txn['TransactionId'] . '' . $txn['Amount'] . "\n";
}

Retour : array<int, array<string, mixed>>

cancel() — Annuler / Rembourser

// Remboursement total
$result = $viva->transactions->cancel('transaction-uuid');

// Remboursement partiel (5,00 EUR)
$result = $viva->transactions->cancel('transaction-uuid', amount: 500);

echo $result['TransactionId']; // UUID du remboursement
Paramètre Type Défaut Description
transactionId string requis UUID de la transaction
amount ?int null Centimes (null = total)
sourceCode ?string null Source de paiement

Même jour = annulation (void). Jour passé = remboursement (refund).

capture() — Capturer une pré-autorisation

$result = $viva->transactions->capture('preauth-uuid', amount: 1500);

Lève ApiException si la capture échoue.

recurring() — Charge récurrente

$result = $viva->transactions->recurring(
    initialTransactionId: 'initial-txn-uuid',
    amount: 1500,
    sourceCode: '1234', // optionnel
);

Prérequis : l'ordre initial doit avoir été créé avec allowRecurring: true.

3. Sources — $viva->sources

Gestion des sources de paiement (domaines autorisés, URLs de redirection).

list() — Lister les sources

$sources = $viva->sources->list();

foreach ($sources as $source) {
    echo $source['Name'] . '' . $source['SourceCode'] . "\n";
}

create() — Créer une source

$source = $viva->sources->create(
    name: 'Mon site web',
    sourceCode: '1234',
    domain: 'www.example.com',
    pathSuccess: '/paiement/succes',
    pathFail: '/paiement/echec',
);
Paramètre Type Défaut Description
name string requis Nom d'affichage
sourceCode string requis Code à 4 chiffres
domain ?string null Domaine du site
pathSuccess ?string null Redirection succès
pathFail ?string null Redirection échec

4. Wallets — $viva->wallets

Portefeuilles (sous-comptes), soldes et transferts.

list() — Lister les portefeuilles

$wallets = $viva->wallets->list();

balance() — Solde agrégé

$balance = $viva->wallets->balance();
echo $balance['available'];  // 150.50
echo $balance['pending'];    // 25.00
echo $balance['reserved'];   // 0.00
echo $balance['currency'];   // 'EUR'

Retour : array{available: float, pending: float, reserved: float, currency: string}

transfer() — Transfert entre wallets

$viva->wallets->transfer(
    amount: 5000,                        // 50,00 EUR
    sourceWalletId: 'source-uuid',
    targetWalletId: 'target-uuid',
    description: 'Transfert mensuel',
);

Prérequis : « Allow transfers between accounts » dans Settings > API Access.

listDetailed() — Liste enrichie (IBAN, SWIFT)

$wallets = $viva->wallets->listDetailed();

foreach ($wallets as $wallet) {
    echo $wallet['iban'] . '' . $wallet['amount'] . "\n";
    echo $wallet['isPrimary'] ? 'Principal' : 'Secondaire';
}

create() — Créer un portefeuille

$viva->wallets->create(friendlyName: 'Compte secondaire', currencyCode: 'EUR');

update() — Renommer un portefeuille

$viva->wallets->update(walletId: 12345, friendlyName: 'Nouveau nom');

searchTransactions() — Rechercher les transactions de compte

$transactions = $viva->wallets->searchTransactions([
    'date_from' => '2026-03-01',
    'date_to' => '2026-03-18',
    'walletId' => 12345,
]);

getTransaction() — Détails d'une transaction de compte

$txn = $viva->wallets->getTransaction('transaction-uuid');

5. BankAccounts — $viva->bankAccounts

Comptes bancaires IBAN et virements SEPA.

link() — Lier un IBAN

$result = $viva->bankAccounts->link(
    iban: 'FR7630006000011234567890189',
    beneficiaryName: 'Jean Dupont',
    friendlyName: 'Compte principal',
);

echo $result['bankAccountId']; // UUID
echo $result['isVivaIban'];    // false

transferOptions() — Options de transfert

$options = $viva->bankAccounts->transferOptions('bank-account-uuid');

feeCommand() — Calculer les frais avant virement

$fees = $viva->bankAccounts->feeCommand(
    bankAccountId: 'bank-account-uuid',
    amount: 10000,                    // 100,00 EUR
    walletId: 'source-wallet-uuid',
    isInstant: true,                  // SEPA instantané
    instructionType: 'SHA',           // Frais partagés
);

echo $fees['bankCommandId']; // À passer à send()
echo $fees['fee'];           // Frais en centimes

send() — Exécuter un virement SEPA

$result = $viva->bankAccounts->send(
    bankAccountId: 'bank-account-uuid',
    amount: 10000,
    walletId: 'source-wallet-uuid',
    bankCommandId: 'fee-command-uuid',  // Optionnel
    description: 'Virement mensuel',
);

echo $result['commandId']; // UUID du virement
echo $result['isInstant']; // true/false
echo $result['fee'];       // Frais en centimes

list() — Lister les comptes liés

$accounts = $viva->bankAccounts->list();

get() — Détails d'un compte lié

$account = $viva->bankAccounts->get('bank-account-uuid');

6. NativeCheckout — $viva->nativeCheckout

Paiements Apple Pay et Google Pay.

createChargeToken() — Générer un token de charge

$token = $viva->nativeCheckout->createChargeToken(
    amount: 1500,
    paymentData: $applePayPaymentDataString,
    paymentMethod: 'applepay', // ou 'googlepay'
    sourceCode: '1234',
);

echo $token['chargeToken'];       // Token à passer à createTransaction()
echo $token['redirectToACSForm']; // Formulaire 3DS (si applicable)
Paramètre Type Défaut Description
amount int requis Montant en centimes
paymentData string requis Données Apple Pay / Google Pay
paymentMethod string 'applepay' 'applepay' ou 'googlepay'
sourceCode ?string null Source de paiement
dynamicDescriptor ?string null Descripteur dynamique

createTransaction() — Exécuter la transaction

$txn = $viva->nativeCheckout->createTransaction(
    chargeToken: $token['chargeToken'],
    amount: 1500,
    currencyCode: 978,             // EUR (ISO 4217 numérique)
    merchantTrns: 'ref_123',
    customerTrns: 'Consultation',
);

echo $txn['transactionId']; // UUID
echo $txn['statusId'];      // 'F' = finalisée
echo $txn['amount'];        // 1500
echo $txn['orderCode'];     // Code de l'ordre
Paramètre Type Défaut Description
chargeToken string requis Token de createChargeToken()
amount int requis Montant en centimes
currencyCode int 978 ISO 4217 numérique
sourceCode ?string null Source de paiement
merchantTrns ?string null Référence interne
customerTrns ?string null Description client
preauth bool false Pré-autorisation ?
tipAmount int 0 Pourboire en centimes
installments ?int null Nombre de versements

7. DataServices — $viva->dataServices

Rapports MT940 et souscriptions webhook pour les fichiers de données.

mt940() — Rapport MT940

$report = $viva->dataServices->mt940('2026-03-18');

createSubscription() — Créer une souscription webhook

$sub = $viva->dataServices->createSubscription(
    url: 'https://example.com/webhooks/viva-files',
    eventType: 'SaleTransactionsFileGenerated',
);
echo $sub['subscriptionId'];

updateSubscription() — Mettre à jour

$viva->dataServices->updateSubscription(
    subscriptionId: 'sub-uuid',
    url: 'https://example.com/webhooks/new-url',
    eventType: null, // null = conserver l'actuel
);

deleteSubscription() — Supprimer

$viva->dataServices->deleteSubscription('sub-uuid');

listSubscriptions() — Lister

$subs = $viva->dataServices->listSubscriptions();

foreach ($subs as $sub) {
    echo $sub['subscriptionId'] . '' . $sub['url'] . "\n";
}

requestFile() — Demander la génération d'un fichier

$viva->dataServices->requestFile('2026-03-18');

Déclenche la génération asynchrone. Utilisez une souscription webhook pour être notifié.

8. Webhooks — $viva->webhooks

Vérification et parsing des webhooks Viva Wallet. Aucun appel API — tout est local.

verificationResponse() — Répondre au GET de vérification

public function verify()
{
    return response()->json(
        $viva->webhooks->verificationResponse('votre-verification-key')
    );
    // => {"StatusCode": 0, "Key": "votre-verification-key"}
}

parse() — Parser un webhook POST

public function handle(Request $request)
{
    $event = $viva->webhooks->parse($request->getContent());

    echo $event['event_type'];     // 'transaction.payment.created'
    echo $event['event_type_id'];  // 1796
    echo $event['event_data'];     // Données de l'événement

    match ($event['event_type']) {
        'transaction.payment.created' => $this->handlePayment($event['event_data']),
        'transaction.refund.created'  => $this->handleRefund($event['event_data']),
        default => null,
    };
}

Retour : array{event_type: string, event_type_id: int, event_data: array<string, mixed>}

Lève InvalidArgumentException si le JSON est invalide.

isKnownEvent() — Vérifier un ID d'événement

$viva->webhooks->isKnownEvent(1796); // true
$viva->webhooks->isKnownEvent(9999); // false

eventTypeIds() — Lister les IDs connus

$ids = $viva->webhooks->eventTypeIds();
// [1796, 1797, 1798, ..., 1828]

21 types d'événements supportés

ID Type
1796 transaction.payment.created
1797 transaction.refund.created
1798 transaction.payment.cancelled
1799 transaction.reversal.created
1800 transaction.preauth.created
1801 transaction.preauth.completed
1802 transaction.preauth.cancelled
1810 pos.session.created
1811 pos.session.failed
1812 transaction.price.calculated
1813 transaction.failed
1819 account.connected
1820 account.verification.status.changed
1821 account.transaction.created
1822 command.bank.transfer.created
1823 command.bank.transfer.executed
1824 transfer.created
1825 obligation.created
1826 obligation.captured
1827 order.updated
1828 sale.transactions.file

9. Account — $viva->account

Informations du compte marchand.

info() — Informations du compte

$info = $viva->account->info();
echo $info['merchantId'];
echo $info['businessName'];
echo $info['email'];

wallets() — Portefeuilles du compte

$wallets = $viva->account->wallets();

Architecture

src/
├── VivaClient.php          # Point d'entrée — instancie les 9 ressources
├── Config.php              # Configuration (URLs par environnement)
├── HttpClient.php          # Client HTTP Guzzle (OAuth2 auto, Basic Auth)
├── Enums/
│   ├── Environment.php     # demo | production
│   ├── Currency.php        # Codes ISO 4217 numériques
│   └── TransactionStatus.php  # F, A, C, E, M, X, R
├── Exceptions/
│   ├── VivaException.php          # Classe de base (RuntimeException)
│   ├── ApiException.php           # Erreur API (4xx, 5xx)
│   ├── AuthenticationException.php # Échec OAuth2 (401)
│   └── ValidationException.php    # Validation (422)
└── Resources/
    ├── Orders.php           # Smart Checkout
    ├── Transactions.php     # Get, list, cancel, capture, recurring
    ├── Sources.php          # Sources de paiement
    ├── Wallets.php          # Portefeuilles, soldes, transferts
    ├── BankAccounts.php     # IBAN, virements SEPA
    ├── NativeCheckout.php   # Apple Pay, Google Pay
    ├── DataServices.php     # MT940, souscriptions webhook
    ├── Webhooks.php         # Vérification et parsing
    └── Account.php          # Infos du compte

L'authentification est gérée automatiquement par HttpClient :

  • Legacy API (Basic Auth) — utilisée par Orders, Transactions, Sources
  • New API (Bearer OAuth2) — utilisée par Wallets, BankAccounts, NativeCheckout, DataServices, Account

Le token OAuth2 est mis en cache en mémoire et rafraîchi automatiquement avant expiration.

Enums

Environment

use QrCommunication\VivaMerchant\Enums\Environment;

$env = Environment::DEMO;
$env = Environment::PRODUCTION;
$env = Environment::from('demo');

$env->value;         // 'demo'
$env->apiUrl();      // 'https://demo-api.vivapayments.com'
$env->legacyUrl();   // 'https://demo.vivapayments.com'
$env->checkoutUrl(); // 'https://demo.vivapayments.com/web/checkout'
$env->accountsUrl(); // 'https://demo-accounts.vivapayments.com'

Currency

use QrCommunication\VivaMerchant\Enums\Currency;

Currency::EUR->value;     // 978
Currency::EUR->iso();     // 'EUR'
Currency::fromIso('GBP'); // Currency::GBP (826)

Devises supportées : EUR (978), GBP (826), USD (840), PLN (985), RON (946), BGN (975), CZK (203), HRK (191), HUF (348), DKK (208), SEK (752), NOK (578).

TransactionStatus

use QrCommunication\VivaMerchant\Enums\TransactionStatus;

$status = TransactionStatus::from('F');
$status->isSuccessful();  // true
$status->isPending();     // false
$status->isFailed();      // false
$status->label();         // 'Finalized'
Valeur Constante isSuccessful() isPending() isFailed()
F FINALIZED oui
A PENDING oui
C CLEARING oui
E ERROR oui
M MANUALLY_REVERSED oui
X REQUIRES_ACTION
R REFUNDED

Gestion d'erreurs

Toutes les exceptions héritent de VivaException qui étend RuntimeException.

RuntimeException
└── VivaException
    ├── ApiException
    ├── AuthenticationException
    └── ValidationException
use QrCommunication\VivaMerchant\Exceptions\ApiException;
use QrCommunication\VivaMerchant\Exceptions\AuthenticationException;
use QrCommunication\VivaMerchant\Exceptions\ValidationException;
use QrCommunication\VivaMerchant\Exceptions\VivaException;

try {
    $order = $viva->orders->create(amount: 1500);
} catch (AuthenticationException $e) {
    // Identifiants invalides — httpStatus = 401
    echo $e->getMessage();
} catch (ValidationException $e) {
    // Erreur de validation — httpStatus = 422
    foreach ($e->errors as $field => $messages) {
        echo "$field: " . implode(', ', $messages);
    }
} catch (ApiException $e) {
    // Erreur API générale — 400, 404, 500, etc.
    echo $e->httpStatus;
    echo $e->getErrorCode();
    echo $e->getErrorText();
    print_r($e->responseBody);
} catch (VivaException $e) {
    // Toute autre erreur SDK
}

Propriétés et méthodes de VivaException

Membre Type Description
$httpStatus int Code HTTP de la réponse
$responseBody ?array Corps JSON décodé de la réponse
getErrorCode() ?int Code d'erreur Viva (ErrorCode)
getErrorText() ?string Message d'erreur Viva (ErrorText, message, ou detail)

Webhooks — Guide d'intégration

1. Configurer le webhook dans le Dashboard Viva

  1. Aller dans Settings > API Access > Webhooks
  2. Ajouter l'URL de votre endpoint
  3. Noter la clé de vérification

2. Gérer la vérification (GET)

// Route GET /webhooks/viva
public function verify()
{
    return response()->json(
        $viva->webhooks->verificationResponse('votre-clé')
    );
}

3. Recevoir les événements (POST)

// Route POST /webhooks/viva
public function handle(Request $request)
{
    $event = $viva->webhooks->parse($request->getContent());

    match ($event['event_type']) {
        'transaction.payment.created'   => $this->onPayment($event['event_data']),
        'transaction.refund.created'    => $this->onRefund($event['event_data']),
        'transaction.preauth.created'   => $this->onPreauth($event['event_data']),
        'transaction.preauth.completed' => $this->onCapture($event['event_data']),
        default => logger()->info('Webhook ignoré : ' . $event['event_type']),
    };

    return response()->json(['status' => 'ok']);
}

Carte de test

Pour l'environnement demo :

Champ Valeur
Numéro de carte 4111 1111 1111 1111
Expiration Toute date future
CVV 111
3DS Pas de 3DS en demo

Documentation interactive

La documentation interactive (ReDoc) est disponible en ligne :

https://qrcommunication.github.io/sdk-php-viva-merchant/

Elle détaille chaque classe, méthode, paramètre et type de retour du SDK.

Intégration IA

Ce SDK inclut un skill détaillé (skill/SKILL.md) automatiquement détecté par les assistants IA. Il fournit la référence complète des 9 resources, 34+ méthodes, enums, exceptions et patterns d'implémentation.

Outil Fichier Détection
Claude Code CLAUDE.md + skill/SKILL.md Automatique
Cursor .cursorrules Automatique
GitHub Copilot .github/copilot-instructions.md Automatique
OpenAI Codex AGENTS.md Automatique
// Un agent IA peut construire cet appel à partir de :
// "Crée un paiement de 25 EUR pour une consultation"
$order = $viva->orders->create(
    amount: 2500,
    customerDescription: 'Consultation',
);

Licence

MIT — QrCommunication