---
title: Viva Wallet Merchant SDK - Documentation
version: 1.3.5
language: PHP
package: qrcommunication/viva-merchant-sdk
github: https://github.com/QrCommunication/sdk-php-viva-merchant
---

# Viva Wallet Merchant SDK — Documentation PHP

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

- **Version** : 1.3.5
- **Prérequis** : PHP 8.2+, `ext-json`, `ext-curl`, `guzzlehttp/guzzle ^7.8`
- **Licence** : MIT
- **Packagist** : `qrcommunication/viva-merchant-sdk`
- **Docs interactives** : https://qrcommunication.github.io/sdk-php-viva-merchant/

> 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

1. [Installation](#installation)
2. [Démarrage rapide](#démarrage-rapide)
3. [Configuration](#configuration)
4. [Ressources](#ressources)
   - [Orders](#1-orders--vivaorders)
   - [Transactions](#2-transactions--vivatransactions)
   - [Sources](#3-sources--vivasources)
   - [Wallets](#4-wallets--vivawallets)
   - [BankAccounts](#5-bankaccounts--vivabankaccounts)
   - [NativeCheckout](#6-nativecheckout--vivanativecheckout)
   - [DataServices](#7-dataservices--vivadataservices)
   - [Webhooks](#8-webhooks--vivawebhooks)
   - [Account](#9-account--vivaaccount)
5. [Enums](#enums)
6. [Gestion des erreurs](#gestion-des-erreurs)
7. [Guide d'intégration Webhooks](#guide-dintégration-webhooks)
8. [Carte de test](#carte-de-test)

---

## Installation

```bash
composer require qrcommunication/viva-merchant-sdk
```

Prérequis : PHP 8.2+ avec `ext-json` et `ext-curl`. Compatible Laravel, Symfony ou tout projet PHP.

---

## Démarrage rapide

```php
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');

// Remboursement partiel (5,00 EUR)
$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
$ok = $viva->testConnection(); // true ou false
```

---

## Configuration

### Constructeur `VivaClient`

```php
new VivaClient(
    string $merchantId,
    string $apiKey,
    string $clientId,
    string $clientSecret,
    string|Environment $environment = Environment::DEMO,
)
```

| Paramètre | Type | Requis | Description |
|-----------|------|--------|-------------|
| `merchantId` | `string` | Oui | UUID du marchand Viva Wallet |
| `apiKey` | `string` | Oui | Clé API (Legacy API — Basic Auth) |
| `clientId` | `string` | Oui | Client ID OAuth2 (format `xxx.apps.vivapayments.com`) |
| `clientSecret` | `string` | Oui | Secret OAuth2 |
| `environment` | `string\|Environment` | Non | `'demo'` (défaut) ou `'production'` |

### Architecture d'authentification

L'authentification est gérée automatiquement par `HttpClient`. Le token OAuth2 est mis en cache en mémoire et rafraîchi automatiquement avant expiration.

| API | Méthode | Ressources concernées |
|-----|---------|----------------------|
| Legacy API | Basic Auth (`merchantId:apiKey`) | Orders, Transactions, Sources |
| New API | Bearer OAuth2 (auto-refresh) | Wallets, BankAccounts, NativeCheckout, DataServices, Account |

### Méthodes utilitaires du `VivaClient`

```php
$viva->getConfig(): Config        // Configuration courante
$viva->invalidateToken(): void    // Forcer la ré-authentification
$viva->testConnection(): bool     // Tester la connexion (appelle account->info())
```

### Propriétés publiques

```php
$viva->orders          // Orders
$viva->transactions    // Transactions
$viva->sources         // Sources
$viva->wallets         // Wallets
$viva->bankAccounts    // BankAccounts
$viva->webhooks        // Webhooks
$viva->account         // Account
$viva->nativeCheckout  // NativeCheckout
$viva->dataServices    // DataServices
```

---

## Ressources

### 1. Orders — `$viva->orders`

Ordres de paiement Smart Checkout. Crée des liens de paiement hébergés sur les serveurs Viva Wallet.

#### `create()` — Créer un ordre

```php
public function create(
    int $amount,
    ?string $customerDescription = null,
    ?string $merchantReference = null,
    ?string $sourceCode = null,
    bool $allowRecurring = false,
    bool $preauth = false,
    int $maxInstallments = 0,
): array // array{order_code: int, checkout_url: string}
```

| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| `amount` | `int` | **requis** | Montant en centimes (ex : 1500 = 15,00 EUR) |
| `customerDescription` | `?string` | `null` | Texte affiché au client sur la page de paiement |
| `merchantReference` | `?string` | `null` | Référence interne (visible dans les exports) |
| `sourceCode` | `?string` | `null` | Code source de paiement (null = source par défaut) |
| `allowRecurring` | `bool` | `false` | Tokeniser la carte pour les charges futures |
| `preauth` | `bool` | `false` | Pré-autorisation uniquement (capture séparée) |
| `maxInstallments` | `int` | `0` | Nombre max de versements (0 = désactivé) |

**Retourne :** `array{order_code: int, checkout_url: string}`

```php
$order = $viva->orders->create(
    amount:              1500,
    customerDescription: 'Consultation',
    merchantReference:   'session_123',
    allowRecurring:      true,
    maxInstallments:     3,
);

echo $order['order_code'];   // 1234567890
echo $order['checkout_url']; // https://demo.vivapayments.com/web/checkout?ref=1234567890
```

#### `get()` — Statut d'un ordre

```php
public function get(int $orderCode): array
```

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

#### `cancel()` — Annuler un ordre non payé

```php
public function cancel(int $orderCode): array
```

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

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

```php
public function checkoutUrl(int $orderCode): string
```

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

---

### 2. Transactions — `$viva->transactions`

Consultation, remboursement, capture de pré-autorisation et paiements récurrents.

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

```php
public function get(string $transactionId): array
```

Retourne les données complètes incluant frais, commission, infos carte (PascalCase).

```php
$txn = $viva->transactions->get('transaction-uuid');

echo $txn['Transactions'][0]['Amount'];   // en centimes
echo $txn['Transactions'][0]['StatusId']; // 'F', 'A', 'C', etc.
echo $txn['Transactions'][0]['Fee'];
echo $txn['Transactions'][0]['CreditCard']['Number']; // masqué
```

#### `getV2()` — Détails allégés (New API, camelCase)

```php
public function getV2(string $transactionId): array
```

Réponse allégée en camelCase. **Recommandé pour vérifier les paiements Smart Checkout.**

```php
$txn = $viva->transactions->getV2('transaction-uuid');

echo $txn['email'];            // email acheteur
echo $txn['amount'];           // en EUR (pas en centimes)
echo $txn['statusId'];         // 'F' = finalisée
echo $txn['orderCode'];        // code de commande
echo $txn['cardNumber'];       // numéro masqué
echo $txn['currencyCode'];     // ex: 978 (EUR)
echo $txn['recurringSupport']; // true si carte tokenisée
```

#### `listByDate()` — Lister par date

```php
public function listByDate(string $date): array
// array<int, array<string, mixed>>
```

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

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

#### `cancel()` — Annuler / Rembourser

```php
public function cancel(
    string $transactionId,
    ?int $amount = null,
    ?string $sourceCode = null,
): array // array{TransactionId: string}
```

| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| `transactionId` | `string` | **requis** | UUID de la transaction |
| `amount` | `?int` | `null` | Centimes (`null` = remboursement total) |
| `sourceCode` | `?string` | `null` | Code source de paiement |

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

```php
// 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
```

#### `capture()` — Capturer une pré-autorisation

```php
public function capture(string $transactionId, int $amount): array
```

Lève `ApiException` si la capture échoue.

```php
$result = $viva->transactions->capture(
    transactionId: 'preauth-uuid',
    amount:        1500, // 15,00 EUR
);
```

#### `recurring()` — Charge récurrente

```php
public function recurring(
    string $initialTransactionId,
    int $amount,
    ?string $sourceCode = null,
): array
```

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

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

---

### 3. Sources — `$viva->sources`

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

#### `list()` — Lister les sources

```php
public function list(): array
```

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

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

#### `create()` — Créer une source

```php
public function create(
    string $name,
    string $sourceCode,
    ?string $domain = null,
    ?string $pathSuccess = null,
    ?string $pathFail = null,
): array
```

| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| `name` | `string` | **requis** | Nom d'affichage de la source |
| `sourceCode` | `string` | **requis** | Code à 4 chiffres |
| `domain` | `?string` | `null` | Domaine du site (ex : `www.example.com`) |
| `pathSuccess` | `?string` | `null` | Chemin de redirection après paiement réussi |
| `pathFail` | `?string` | `null` | Chemin de redirection après échec |

```php
$source = $viva->sources->create(
    name:        'Mon site web',
    sourceCode:  '1234',
    domain:      'www.example.com',
    pathSuccess: '/paiement/succes',
    pathFail:    '/paiement/echec',
);
```

---

### 4. Wallets — `$viva->wallets`

Gestion des portefeuilles (sous-comptes), soldes et transferts internes.

#### `list()` — Lister les portefeuilles

```php
public function list(): array
```

#### `balance()` — Solde agrégé

```php
public function balance(): array
// array{available: float, pending: float, reserved: float, currency: string}
```

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

#### `transfer()` — Transfert entre wallets

```php
public function transfer(
    int $amount,
    string $sourceWalletId,
    string $targetWalletId,
    ?string $description = null,
): array
```

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

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

#### `listDetailed()` — Liste enrichie (IBAN, SWIFT)

```php
public function listDetailed(): array
```

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

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

#### `create()` — Créer un portefeuille

```php
public function create(string $friendlyName, string $currencyCode = 'EUR'): array
```

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

#### `update()` — Renommer un portefeuille

```php
public function update(int $walletId, string $friendlyName): array
```

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

#### `searchTransactions()` — Rechercher les transactions

```php
public function searchTransactions(array $params): array
```

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

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

```php
public function getTransaction(string $transactionId): array
```

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

---

### 5. BankAccounts — `$viva->bankAccounts`

Gestion des comptes bancaires IBAN et virements SEPA (standard et instantané).

#### `link()` — Lier un IBAN

```php
public function link(
    string $iban,
    string $beneficiaryName,
    ?string $friendlyName = null,
): array
```

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

echo $result['bankAccountId']; // UUID
echo $result['isVivaIban'];    // false (IBAN externe)
```

#### `transferOptions()` — Options de transfert disponibles

```php
public function transferOptions(string $bankAccountId): array
```

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

#### `feeCommand()` — Calculer les frais avant virement

```php
public function feeCommand(
    string $bankAccountId,
    int $amount,
    string $walletId,
    bool $isInstant = false,
    string $instructionType = 'SHA',
): array
```

Le `bankCommandId` retourné doit être passé à `send()`.

```php
$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

```php
public function send(
    string $bankAccountId,
    int $amount,
    string $walletId,
    ?string $bankCommandId = null,
    ?string $description = null,
): array
```

```php
$result = $viva->bankAccounts->send(
    bankAccountId: 'bank-account-uuid',
    amount:        10000,
    walletId:      'source-wallet-uuid',
    bankCommandId: 'fee-command-uuid',
    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

```php
public function list(): array
```

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

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

```php
public function get(string $bankAccountId): array
```

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

---

### 6. NativeCheckout — `$viva->nativeCheckout`

Paiements natifs Apple Pay et Google Pay. Flux en deux étapes : générer un `chargeToken`, puis créer la transaction.

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

```php
public function createChargeToken(
    int $amount,
    string $paymentData,
    string $paymentMethod = 'applepay',
    ?string $sourceCode = null,
    ?string $dynamicDescriptor = null,
): array
// array{chargeToken: string, redirectToACSForm: ?string}
```

| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| `amount` | `int` | **requis** | Montant en centimes |
| `paymentData` | `string` | **requis** | Données Apple Pay ou Google Pay (JSON sérialisé) |
| `paymentMethod` | `string` | `'applepay'` | `'applepay'` ou `'googlepay'` |
| `sourceCode` | `?string` | `null` | Code source de paiement |
| `dynamicDescriptor` | `?string` | `null` | Descripteur dynamique sur le relevé bancaire |

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

echo $token['chargeToken'];       // à passer à createTransaction()
echo $token['redirectToACSForm']; // formulaire 3DS (si applicable)
```

#### `createTransaction()` — Finaliser la transaction

```php
public function createTransaction(
    string $chargeToken,
    int $amount,
    int $currencyCode = 978,
    ?string $sourceCode = null,
    ?string $merchantTrns = null,
    ?string $customerTrns = null,
    bool $preauth = false,
    int $tipAmount = 0,
    ?int $installments = null,
): array
// array{transactionId: string, statusId: string, amount: int, orderCode: int}
```

| Paramètre | Type | Défaut | Description |
|-----------|------|--------|-------------|
| `chargeToken` | `string` | **requis** | Token issu de `createChargeToken()` |
| `amount` | `int` | **requis** | Montant en centimes |
| `currencyCode` | `int` | `978` | Code ISO 4217 numérique (978 = EUR) |
| `sourceCode` | `?string` | `null` | Code source de paiement |
| `merchantTrns` | `?string` | `null` | Référence interne marchand |
| `customerTrns` | `?string` | `null` | Description visible par le client |
| `preauth` | `bool` | `false` | Pré-autorisation uniquement |
| `tipAmount` | `int` | `0` | Pourboire en centimes |
| `installments` | `?int` | `null` | Nombre de versements |

```php
$txn = $viva->nativeCheckout->createTransaction(
    chargeToken:  $token['chargeToken'],
    amount:       1500,
    currencyCode: 978,
    merchantTrns: 'ref_123',
    customerTrns: 'Consultation',
);

echo $txn['transactionId']; // UUID
echo $txn['statusId'];      // 'F' = finalisée
echo $txn['amount'];        // 1500
echo $txn['orderCode'];     // code de commande
```

---

### 7. DataServices — `$viva->dataServices`

Rapports MT940 et souscriptions webhook pour la génération de fichiers de données.

#### `mt940()` — Rapport MT940

```php
public function mt940(string $date): array
```

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

#### `createSubscription()` — Créer une souscription webhook

```php
public function createSubscription(string $url, string $eventType): array
```

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

#### `updateSubscription()` — Mettre à jour une souscription

```php
public function updateSubscription(
    string $subscriptionId,
    ?string $url,
    ?string $eventType,
): array
```

`null` conserve la valeur actuelle.

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

#### `deleteSubscription()` — Supprimer une souscription

```php
public function deleteSubscription(string $subscriptionId): void
```

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

#### `listSubscriptions()` — Lister les souscriptions actives

```php
public function listSubscriptions(): array
```

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

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

#### `requestFile()` — Déclencher la génération d'un fichier

```php
public function requestFile(string $date): void
```

Déclenche la génération asynchrone. Utilisez une souscription webhook pour être notifié (événement `sale.transactions.file`, ID 1828).

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

---

### 8. Webhooks — `$viva->webhooks`

Vérification et parsing des webhooks Viva Wallet. **Aucun appel API** — traitement entièrement local.

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

```php
public function verificationResponse(string $verificationKey): array
// array{StatusCode: int, Key: string}
```

```php
// Route GET /webhooks/viva
public function verify()
{
    return response()->json(
        $viva->webhooks->verificationResponse('votre-clé-de-vérification')
    );
    // {"StatusCode": 0, "Key": "votre-clé-de-vérification"}
}
```

#### `parse()` — Parser un webhook POST

```php
public function parse(string $rawBody): array
// array{event_type: string, event_type_id: int, event_data: array<string, mixed>}
```

Lève `\InvalidArgumentException` si le JSON est invalide.

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

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

    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']);
}
```

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

```php
public function isKnownEvent(int $eventTypeId): bool
```

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

#### `eventTypeIds()` — Lister les IDs connus

```php
public function eventTypeIds(): array // array<int>
```

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

#### Constante `Webhooks::EVENTS`

```php
public const EVENTS = [
    1796 => 'transaction.payment.created',
    1797 => 'transaction.refund.created',
    // ...
];
```

#### 21 types d'événements supportés

| ID | Type d'événement | Description |
|----|-----------------|-------------|
| 1796 | `transaction.payment.created` | Paiement créé / reçu |
| 1797 | `transaction.refund.created` | Remboursement créé |
| 1798 | `transaction.payment.cancelled` | Paiement annulé |
| 1799 | `transaction.reversal.created` | Annulation (void) créée |
| 1800 | `transaction.preauth.created` | Pré-autorisation créée |
| 1801 | `transaction.preauth.completed` | Pré-autorisation capturée |
| 1802 | `transaction.preauth.cancelled` | Pré-autorisation annulée |
| 1810 | `pos.session.created` | Session POS créée |
| 1811 | `pos.session.failed` | Session POS échouée |
| 1812 | `transaction.price.calculated` | Prix calculé (frais dynamiques) |
| 1813 | `transaction.failed` | Transaction échouée |
| 1819 | `account.connected` | Compte connecté |
| 1820 | `account.verification.status.changed` | Statut de vérification du compte modifié |
| 1821 | `account.transaction.created` | Transaction de compte (wallet) créée |
| 1822 | `command.bank.transfer.created` | Virement bancaire initié |
| 1823 | `command.bank.transfer.executed` | Virement bancaire exécuté |
| 1824 | `transfer.created` | Transfert entre wallets créé |
| 1825 | `obligation.created` | Obligation créée |
| 1826 | `obligation.captured` | Obligation capturée |
| 1827 | `order.updated` | Ordre mis à jour |
| 1828 | `sale.transactions.file` | Fichier de transactions disponible |

---

### 9. Account — `$viva->account`

Informations et portefeuilles du compte marchand.

#### `info()` — Informations du compte

```php
public function info(): array
```

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

#### `wallets()` — Portefeuilles du compte

```php
public function wallets(): array
```

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

---

## Enums

### `Environment`

```php
namespace QrCommunication\VivaMerchant\Enums;

enum Environment: string
{
    case DEMO       = 'demo';
    case PRODUCTION = 'production';

    public function apiUrl(): string;      // 'https://demo-api.vivapayments.com'
    public function legacyUrl(): string;   // 'https://demo.vivapayments.com'
    public function checkoutUrl(): string; // 'https://demo.vivapayments.com/web/checkout'
    public function accountsUrl(): string; // 'https://demo-accounts.vivapayments.com'
}
```

```php
use QrCommunication\VivaMerchant\Enums\Environment;

$env = Environment::DEMO;
$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`

```php
namespace QrCommunication\VivaMerchant\Enums;

enum Currency: int
{
    case EUR = 978; case GBP = 826; case USD = 840;
    case PLN = 985; case RON = 946; case BGN = 975;
    case CZK = 203; case HRK = 191; case HUF = 348;
    case DKK = 208; case SEK = 752; case NOK = 578;

    public function iso(): string;                    // 'EUR', 'GBP', etc.
    public static function fromIso(string $iso): self; // Currency::fromIso('GBP') → Currency::GBP
}
```

| Constante | Valeur ISO numérique | Code ISO |
|-----------|---------------------|----------|
| `Currency::EUR` | 978 | EUR |
| `Currency::GBP` | 826 | GBP |
| `Currency::USD` | 840 | USD |
| `Currency::PLN` | 985 | PLN |
| `Currency::RON` | 946 | RON |
| `Currency::BGN` | 975 | BGN |
| `Currency::CZK` | 203 | CZK |
| `Currency::HRK` | 191 | HRK |
| `Currency::HUF` | 348 | HUF |
| `Currency::DKK` | 208 | DKK |
| `Currency::SEK` | 752 | SEK |
| `Currency::NOK` | 578 | NOK |

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

### `TransactionStatus`

```php
namespace QrCommunication\VivaMerchant\Enums;

enum TransactionStatus: string
{
    case FINALIZED       = 'F';
    case PENDING         = 'A';
    case CLEARING        = 'C';
    case ERROR           = 'E';
    case MANUALLY_REVERSED = 'M';
    case REQUIRES_ACTION = 'X';
    case REFUNDED        = 'R';

    public function isSuccessful(): bool; // true uniquement pour FINALIZED
    public function isPending(): bool;    // true pour PENDING et CLEARING
    public function isFailed(): bool;     // true pour ERROR et MANUALLY_REVERSED
    public function label(): string;      // 'Finalized', 'Pending', etc.
}
```

| Valeur | Constante | `isSuccessful()` | `isPending()` | `isFailed()` | `label()` |
|--------|-----------|:---:|:---:|:---:|---------|
| `'F'` | `FINALIZED` | oui | | | Finalized |
| `'A'` | `PENDING` | | oui | | Pending |
| `'C'` | `CLEARING` | | oui | | Clearing |
| `'E'` | `ERROR` | | | oui | Error |
| `'M'` | `MANUALLY_REVERSED` | | | oui | Reversed |
| `'X'` | `REQUIRES_ACTION` | | | | Requires Action |
| `'R'` | `REFUNDED` | | | | Refunded |

```php
$status = TransactionStatus::from('F');
$status->isSuccessful(); // true
$status->label();        // 'Finalized'

// Usage typique
$txn = $viva->transactions->getV2('transaction-uuid');
$status = TransactionStatus::from($txn['statusId']);
if ($status->isSuccessful()) {
    // Paiement confirmé
}
```

---

## Gestion des erreurs

Toutes les exceptions héritent de `VivaException` (extends `RuntimeException`).

### Hiérarchie

```
RuntimeException
└── VivaException                    // Classe de base
    ├── ApiException                 // Erreurs 4xx / 5xx générales
    ├── AuthenticationException      // 401 — identifiants invalides
    └── ValidationException          // 422 — erreurs de validation
```

### 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 Viva |
| `getErrorCode()` | `?int` | Code d'erreur Viva (`ErrorCode` ou `errorCode`) |
| `getErrorText()` | `?string` | Message d'erreur Viva (`ErrorText`, `message`, ou `detail`) |

### Propriété spécifique à `ValidationException`

| Membre | Type | Description |
|--------|------|-------------|
| `$errors` | `array<string, string[]>` | Erreurs de validation par champ |

### Exemple complet

```php
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 — $e->httpStatus === 401
    echo $e->getMessage();

} catch (ValidationException $e) {
    // Erreur de validation — $e->httpStatus === 422
    foreach ($e->errors as $field => $messages) {
        echo "$field : " . implode(', ', $messages) . "\n";
    }

} catch (ApiException $e) {
    // Erreur API générale (400, 404, 500, etc.)
    echo $e->httpStatus;       // code HTTP
    echo $e->getErrorCode();   // code Viva
    echo $e->getErrorText();   // message Viva
    print_r($e->responseBody); // corps JSON complet

} catch (VivaException $e) {
    // Toute autre erreur SDK
    echo $e->getMessage();
}
```

---

## Guide d'intégration Webhooks

### Étape 1 — Configurer dans le Dashboard Viva

1. Aller dans **Settings > API Access > Webhooks**
2. Ajouter l'URL de votre endpoint (ex : `https://example.com/webhooks/viva`)
3. Noter la **clé de vérification** affichée

### Étape 2 — Gérer la vérification GET

Viva Wallet envoie une requête GET pour vérifier la disponibilité de l'endpoint.

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

### Étape 3 — Recevoir les événements POST

```php
// 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']);
}
```

### Configuration Laravel

Exclure l'URL webhook du middleware `VerifyCsrfToken` dans `bootstrap/app.php`.

---

## Architecture interne

```
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           # 12 codes ISO 4217 numériques
│   └── TransactionStatus.php  # F, A, C, E, M, X, R
├── Exceptions/
│   ├── VivaException.php          # Classe de base (RuntimeException)
│   ├── ApiException.php           # Erreurs 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
    ├── Webhooks.php           # Vérification et parsing (local)
    └── Account.php            # Infos du compte
```

---

## Carte de test

Pour l'environnement `demo` uniquement. Aucun 3DS requis en mode démo.

| Champ | Valeur |
|-------|--------|
| Numéro de carte | `4111 1111 1111 1111` |
| Expiration | Toute date future |
| CVV | `111` |
| 3DS | Non requis en mode demo |
