"> Aller au contenu principal
PHP PHP PHP v1.0.0 MIT

Viva Cloud Terminal PHP SDK

qrcommunication/viva-cloud-terminal-sdk

PHP 8.2+, guzzlehttp/guzzle ^7.8

Quoi de neuf en v1.0.0 What's new in v1.0.0 v1.0.0

✨ Version initiale. SDK PHP pour la Cloud Terminal API marchand (/ecr/v1/) de Viva Wallet : piloter un terminal de paiement physique depuis votre back-office (vente, capture preauth, remboursements, rebate, sessions, polling). — Initial release. PHP SDK for the merchant Cloud Terminal API (/ecr/v1/). GitHub Release v1.0.0 →
  • Client VivaCloudTerminalClient — point d'entrée unique avec auth OAuth2 client_credentials automatique (Bearer token caché et rafraîchi 60s avant expiration).
  • Ressource Devices : search() (POST /ecr/v1/devices:search).
  • Ressource Transactions : sale(), capturePreauth(), refund(), unreferencedRefund(), fastRefund(), rebate(), createAction(), getAction().
  • Ressource Sessions : get(), listByDate(), abort(), pollUntilComplete().
  • pollUntilComplete() disponible aussi comme raccourci sur le client.
  • Enum EcrEventId pour interpréter les eventId de session (polling).
  • Montants en centimes, payloads en camelCase.
Périmètre : ce SDK couvre uniquement les endpoints marchand /ecr/v1/. Pour la variante ISV / Partner (/ecr/isv/v1/, marchands connectés, composite auth), utiliser un SDK distinct. — Merchant /ecr/v1/ only. Use a separate SDK for the ISV variant.

Installation

Installez le SDK via Composer. Requiert PHP 8.2+ avec guzzlehttp/guzzle ^7.8.

Install via Composer. Requires PHP 8.2+ with guzzlehttp/guzzle ^7.8.

composer require qrcommunication/viva-cloud-terminal-sdk

Compatible avec Laravel, Symfony ou tout projet PHP standard.

Démarrage rapide Quick Start

<?php

use QrCommunication\VivaCloudTerminal\VivaCloudTerminalClient;

$viva = new VivaCloudTerminalClient(
    clientId:     'your-client-id',
    clientSecret: 'your-client-secret',
    environment:  'demo', // 'demo' (sandbox) ou 'production'
);

// 1. (recommandé) confirmer que le terminal est Live avant de transiger
$devices = $viva->devices->search(statusId: 1);

// 2. initier une vente sur le terminal (montant en centimes)
$sale = $viva->transactions->sale(
    terminalId:        '16000010',
    amount:            1170,        // 11,70 EUR
    cashRegisterId:    'CR-01',
    merchantReference: 'order-42',
);

// 3. poller jusqu'à ce que le client termine (ou décline) sur le terminal
$result = $viva->pollUntilComplete($sale['session_id']);

if (($result['success'] ?? false) === true) {
    // $result['transactionId'], $result['orderCode'], $result['amount'], ...
}

Configuration

Le constructeur VivaCloudTerminalClient accepte les identifiants OAuth2 et l'environnement cible.

Paramètre Type Défaut Description
clientId string requis Client ID OAuth2 (grant client_credentials)
clientSecret string requis Secret OAuth2
environment string|Environment 'demo' 'demo' (sandbox) ou 'production'

Méthodes utilitaires & propriétés publiques

$viva->devices        // Devices
$viva->transactions   // Transactions
$viva->sessions       // Sessions

$viva->getConfig();                       // CloudTerminalConfig courant
$viva->invalidateToken();                 // Forcer un nouveau handshake OAuth
$viva->pollUntilComplete($sessionId);     // Raccourci vers sessions->pollUntilComplete()

Authentification Authentication

La Cloud Terminal API utilise un seul mode d'authentification : OAuth2 client_credentials → Bearer token. Le SDK récupère et met en cache le token automatiquement (rafraîchi 60s avant expiration).

Étape Hôte Auth
Token accounts.vivapayments.com/connect/token (demo : demo-accounts…) Basic client_id:client_secret, grant_type=client_credentials
Appels API api.vivapayments.com/ecr/v1/… (demo : demo-api…) Authorization: Bearer {token}
CRITIQUE : tous les payloads /ecr/v1/ sont en camelCase. — All /ecr/v1/ payloads use camelCase keys.

Ressources

1 Devices $viva->devices

Découverte des terminaux POS (EFT POS) et de leur statut. Recommandé en pré-flight avant toute transaction (surtout sur WAN) pour confirmer que le terminal est Live (statusId 1).

Discover POS devices and their status. Recommended pre-flight check before any transaction.

search(?int $statusId = null, ?string $sourceCode = null): array

Rechercher les terminaux POS — POST /ecr/v1/devices:search.

Paramètre Type Défaut Description
statusId?intnullFiltrer par statut (0 = WareHouse, 1 = Live, 2 = Ready To Ship, 3 = In Stock, 4 = Pending Key Injection, 5 = Lost, 6 = Broken)
sourceCode?stringnullCode d'identification personnalisé assigné au terminal par le marchand

Retourne : array<int|string, mixed> — chaque entrée : terminalId, statusId, sourceCode, virtualTerminalId

$devices = $viva->devices->search(statusId: 1);

foreach ($devices as $device) {
    echo $device['terminalId'] . ' — statut ' . $device['statusId'] . "\n";
    // 16000010 — statut 1
}

2 Transactions $viva->transactions

Vente, capture de pré-autorisation, remboursements, rebate et actions sur le terminal. Montants toujours en centimes.

Body vide sur succès. La plupart des endpoints /ecr/v1/transactions:* répondent HTTP 200 sans body — c'est le succès du dispatch vers le terminal, pas le résultat du paiement. Chaque méthode retourne array{session_id, response} : pollez la session pour le résultat réel. — Empty body on success: poll the session for the actual payment outcome.

sale(string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Initier une vente — POST /ecr/v1/transactions:sale.

Paramètre Type Défaut Description
terminalIdstring|intrequisID du terminal cible (ex : '16000010')
amountintrequisMontant à autoriser, en centimes
cashRegisterIdstringrequisIdentification de la caisse (défini par le marchand)
merchantReference?stringnullRéférence marchand (défaut : "SDK-{sessionId}")
currencyCodestring'978'Code ISO 4217 numérique en string ('978' = EUR)
tipAmountint0Pourboire en centimes (incompatible avec preauth)
preauth?boolnullFlag de pré-autorisation (nécessite activation Viva)
customerTrns?stringnullRéférence client (texte libre)
paymentMethod?stringnullMéthode de paiement affichée (ex : 'CardPresent')
skipSurcharge?boolnullDésactiver la surcharge pour cette transaction
showTransactionResult?boolnullAfficher le résultat sur le terminal
showReceipt?boolnullAfficher le reçu + résultat sur le terminal
sessionId?stringnullUUID de session (auto-généré si null)
extraarray[]Champs API additionnels fusionnés tels quels (ex : fiscalisationData)

Retourne : array{session_id: string, response: array<string, mixed>}

$sale = $viva->transactions->sale(
    terminalId:     '16000010',
    amount:         2599,          // 25,99 EUR
    cashRegisterId: 'CR-01',
    customerTrns:   'Table 12',
    showReceipt:    true,
);

$final = $viva->pollUntilComplete($sale['session_id'], timeoutSeconds: 90);

capturePreauth(string $parentSessionId, string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Capturer une transaction pré-autorisée — POST /ecr/v1/transactions:preauth-completion. Capture le montant retenu par la pré-autorisation identifiée par parentSessionId. Champs optionnels : merchantReference, currencyCode, customerTrns, showTransactionResult, showReceipt, sessionId, extra.

Retourne : array{session_id: string, response: array<string, mixed>}

// Pré-autoriser (nécessite preauth activé sur le compte Viva)
$preauth = $viva->transactions->sale(
    terminalId:     '16000010',
    amount:         5000,
    cashRegisterId: 'CR-01',
    preauth:        true,
);
$viva->pollUntilComplete($preauth['session_id']);

// Plus tard, capturer le montant final (peut être inférieur à l'autorisé)
$capture = $viva->transactions->capturePreauth(
    parentSessionId: $preauth['session_id'],
    terminalId:      '16000010',
    amount:          4200,
    cashRegisterId:  'CR-01',
);
$viva->pollUntilComplete($capture['session_id']);

refund(string $parentSessionId, string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Rembourser une vente, en référençant la session originale — POST /ecr/v1/transactions:refund. Un nouveau sessionId est généré pour le remboursement ; parentSessionId référence la vente originale. Champs optionnels : merchantReference, currencyCode, customerTrns, showTransactionResult, showReceipt, sessionId, extra.

Retourne : array{session_id: string, response: array<string, mixed>}

$refund = $viva->transactions->refund(
    parentSessionId: $sale['session_id'],
    terminalId:      '16000010',
    amount:          1170,
    cashRegisterId:  'CR-01',
);
$viva->pollUntilComplete($refund['session_id']);

unreferencedRefund(string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Remboursement autonome (non référencé), non lié à une vente originale — POST /ecr/v1/transactions:unreferenced-refund. Champs optionnels : merchantReference, currencyCode, customerTrns, showTransactionResult, showReceipt, sessionId, extra.

Retourne : array{session_id: string, response: array<string, mixed>}

$refund = $viva->transactions->unreferencedRefund(
    terminalId:     '16000010',
    amount:         1500,
    cashRegisterId: 'CR-01',
);
$viva->pollUntilComplete($refund['session_id']);

fastRefund(string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Remboursement rapide (swift) sur Visa / Mastercard / Maestro — POST /ecr/v1/transactions:fast-refund. Mêmes paramètres optionnels que unreferencedRefund().

Retourne : array{session_id: string, response: array<string, mixed>}

$refund = $viva->transactions->fastRefund(
    terminalId:     '16000010',
    amount:         1170,
    cashRegisterId: 'CR-01',
);
$viva->pollUntilComplete($refund['session_id']);

rebate(string|int $terminalId, int $amount, string $cashRegisterId, ...): array

Rabais vers une carte Visa / Mastercard / Maestro — POST /ecr/v1/transactions:rebate. Mêmes paramètres optionnels que unreferencedRefund().

Retourne : array{session_id: string, response: array<string, mixed>}

$rebate = $viva->transactions->rebate(
    terminalId:     '16000010',
    amount:         500,
    cashRegisterId: 'CR-01',
);
$viva->pollUntilComplete($rebate['session_id']);

createAction(array $payload): array

Créer une action à invoquer sur un terminal (ex : aade-fim-control) — POST /ecr/v1/actions. Le payload est transmis tel quel (camelCase) et doit inclure terminalId, cashRegisterId, actionType et request.

Retourne : array{terminalId?, cashRegisterId?, actionType?, actionId?}

$action = $viva->transactions->createAction([
    'terminalId'     => '16000010',
    'cashRegisterId' => 'XDE384678UY',
    'actionType'     => 'aade-fim-control',
    'request'        => ['token' => 'ECR0210U/RCFB77000041/CMAC_K:299BFD51...:CC5FFF'],
]);

echo $action['actionId']; // f7287549-e93a-4d33-b936-000027d326d0

getAction(string $actionId): array

Récupérer le résultat d'une action — GET /ecr/v1/actions/{actionId}. Retourne HTTP 202 (body vide → []) tant que l'action est en cours, ou le résultat une fois terminée.

Retourne : array<string, mixed> (successfullyProcessed, response, …)

$result = $viva->transactions->getAction('f7287549-e93a-4d33-b936-000027d326d0');

if (($result['successfullyProcessed'] ?? false) === true) {
    echo $result['response']['status'];  // 'success'
    echo $result['response']['message']; // 'Set decimal amount successful'
}

3 Sessions $viva->sessions

Récupération, listing, abort et polling des sessions. Une session représente le cycle de vie d'une transaction sur un terminal. Après avoir initié une transaction, pollez la session par son id pour observer son résultat (eventId, success, transactionId, …).

get(string $sessionId): array

Récupérer une session par son id — GET /ecr/v1/sessions/{sessionId}.

Retourne : array<string, mixed> (success, eventId, transactionId, amount, …)

$session = $viva->sessions->get($sale['session_id']);

echo $session['eventId'];       // 0 = succès
echo $session['transactionId']; // UUID de la transaction Viva

listByDate(string $date, ?bool $aadeAutonomouslyOnly = null): array

Lister toutes les sessions d'une date — GET /ecr/v1/sessions?date=Y-m-d.

Paramètre Type Défaut Description
datestringrequisDate au format Y-m-d
aadeAutonomouslyOnly?boolnullFiltrer aux sessions AADE-autonomes uniquement (Grèce)

Retourne : array<int|string, mixed>

$sessions = $viva->sessions->listByDate('2026-06-06');

foreach ($sessions as $session) {
    echo ($session['sessionId'] ?? '') . ' — ' . ($session['eventId'] ?? '') . "\n";
}

abort(string $sessionId, string $cashRegisterId): array

Annuler une session active — DELETE /ecr/v1/sessions/{sessionId}?cashRegisterId=…. Seule la caisse ayant créé la transaction peut l'annuler.

Retourne : array<string, mixed>

$viva->sessions->abort($sale['session_id'], cashRegisterId: 'CR-01');

pollUntilComplete(string $sessionId, int $timeoutSeconds = 120, int $intervalMs = 3000): array

Poll une session jusqu'à un état terminal ou expiration du timeout. Continue tant que eventId vaut IN_PROGRESS (1100), en dormant intervalMs entre les tentatives. S'arrête aussi sur un eventId inconnu (fail-safe). Disponible sur la ressource sessions et comme raccourci sur le client.

Paramètre Type Défaut Description
sessionIdstringrequisUUID de la session à poller
timeoutSecondsint120Temps d'attente total maximum (secondes)
intervalMsint3000Délai entre deux tentatives (millisecondes)

Retourne : array<string, mixed> — l'état final. En cas de timeout : ['success' => false, 'eventId' => 1003, 'message' => 'SDK poll timeout'].

use QrCommunication\VivaCloudTerminal\Enums\EcrEventId;

// Sur le client (raccourci)
$result = $viva->pollUntilComplete($sale['session_id'], timeoutSeconds: 90);

// Ou sur la ressource sessions
$result = $viva->sessions->pollUntilComplete($sale['session_id'], 90, 2000);

$event = EcrEventId::tryFrom($result['eventId'] ?? -1);
if ($event?->isSuccessful()) {
    // Paiement confirmé
}

Enums

Sous QrCommunication\VivaCloudTerminal\Enums.

EcrEventId

Interprétation de l'eventId retourné dans la réponse de poll de session. Méthodes : isTerminal(), isSuccessful(), shouldPoll(), label().

eventIdCasisSuccessful()shouldPoll()label()
0SUCCESSouiTransaction successful
1003TERMINAL_TIMEOUTTerminal timed out
1006DECLINEDTransaction declined
1016ABORTEDTransaction aborted
1020INSUFFICIENT_FUNDSInsufficient funds
1099GENERIC_ERRORGeneric error
1100IN_PROGRESSouiIn progress
6000BAD_PARAMSBad parameters
use QrCommunication\VivaCloudTerminal\Enums\EcrEventId;

$event = EcrEventId::tryFrom($result['eventId']);
$event?->isSuccessful(); // true en cas de succès
$event?->shouldPoll();   // true tant que IN_PROGRESS (1100)
$event?->label();        // libellé lisible

Environment

CasaccountsUrl()apiUrl()
DEMOhttps://demo-accounts.vivapayments.comhttps://demo-api.vivapayments.com
PRODUCTIONhttps://accounts.vivapayments.comhttps://api.vivapayments.com

Gestion des erreurs Error Handling

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

RuntimeException
└── VivaException                    (classe de base)
    ├── ApiException                 (erreurs HTTP 4xx / 5xx)
    └── AuthenticationException      (OAuth2 invalide — 401)
MéthodeTypeDescription
getHttpStatus()intCode HTTP de la réponse
getErrorText()?stringMessage d'erreur Viva lisible
getErrorCode()?intCode d'erreur Viva, si présent
use QrCommunication\VivaCloudTerminal\Exceptions\ApiException;
use QrCommunication\VivaCloudTerminal\Exceptions\AuthenticationException;
use QrCommunication\VivaCloudTerminal\Exceptions\VivaException;

try {
    $viva->transactions->sale(
        terminalId:     '16000010',
        amount:         1170,
        cashRegisterId: 'CR-01',
    );
} catch (AuthenticationException $e) {
    // Handshake OAuth échoué (client_id/secret invalides)
} catch (ApiException $e) {
    echo $e->getHttpStatus();   // ex : 409
    echo $e->getErrorText();    // message lisible
    echo $e->getErrorCode();    // code Viva, si présent
} catch (VivaException $e) {
    // Classe de base pour toutes les exceptions SDK
}

Carte de test Test Card

Environnement demo (sandbox).

ChampValeur
Numéro de carte4111 1111 1111 1111
CVV111
Mot de passe 3DSSecret!33

Montants de déclin courants : 9951 (fonds insuffisants), 9954 (carte expirée), 9920 (carte volée), 9957 (non autorisé), 9961 (limite de retrait).