⚠️ Ce n'est PAS l'API cloud Viva
This is NOT the Viva cloud API
Modèle peer-to-peer (P2P), sans authentification. Ce SDK ne communique pas avec
api.vivapayments.com. Il parle directement au terminal de carte sur votre
réseau local, en adressant l'adresse IP et le port du terminal lui-même.
— Peer-to-peer (P2P), no authentication. This SDK talks directly to the card terminal on your LAN.
API cloud Viva
Local Terminal API (ce SDK)
Base URL
https://api.vivapayments.com
https://<ip-terminal>:<port>
Réseau
Internet
Réseau local (LAN), P2P
Authentification
OAuth2 / Basic / Bearer
Aucune — pas de header Authorization
TLS
CA publique
Certificat auto-signé du terminal
Erreurs 400
JSON structuré
Chaîne brute (texte du terminal verbatim)
Spec officielle : « In a closed network environment, authentication is not required for peer-to-peer
communication. [...] eliminating the need to include an Authorization tag in the header. »
Modèle asynchrone (polling)
Les opérations de transaction (sale, refund, capturePreauth…)
retournent immédiatement un state (typiquement PROCESSING) et un
sessionId. Vous générez vous-même le sessionId (UUID), puis vous
interrogez $terminal->sessions->get($sessionId) jusqu'à SUCCESS ou
FAILURE (champ payloadData renseigné).
Prérequis réseau
L'hôte exécutant votre code et le terminal doivent être sur le même LAN.
Vous devez connaître l'IP et le port du terminal (app Viva.com Terminal, réseau, ou zeroconf/mDNS).
Le terminal sert du HTTPS, généralement avec un certificat auto-signé — voir TLS.
Installation
Installez le SDK via Composer. Requiert PHP 8.2+ avec l'extension ext-json.
Install via Composer. Requires PHP 8.2+ with the ext-json extension.
Compatible avec Laravel, Symfony ou tout projet PHP standard.
Démarrage rapideQuick Start
<?php
use QrCommunication\VivaLocalTerminal\VivaLocalTerminalClient;
// 1. Pointer le client sur l'IP + port du terminal sur le LAN
$terminal = new VivaLocalTerminalClient(
terminalBaseUrl: 'https://192.168.1.50:8080', // IP + port du terminal
verifyTls: false, // certificat auto-signé sur LAN fermé
);
// 2. Démarrer une vente (montant en centimes) — vous générez le sessionId
$sessionId = '4bdebe62-c211-4ca0-a994-b2fbea2061c5';
$resp = $terminal->transactions->sale(
sessionId: $sessionId,
amount: 1170, // 11,70 EUR
currencyCode: 978, // EUR
merchantReference: 'order-123',
);
// $resp = ['state' => 'PROCESSING', 'sessionType' => 'SALE', 'sessionId' => ...]
// 3. Interroger le résultat une fois le client ayant payé
$session = $terminal->sessions->get($sessionId);
// $session['state'] === 'SUCCESS' une fois la carte traitée
// 4. Contrôler le terminal
$terminal->device->screenControl(wakeUpLock: true);
$terminal->device->brightness(0.5);
Configuration
Le constructeur VivaLocalTerminalClient n'accepte aucun identifiant
(pas de clé API, client ID ou secret) — le modèle P2P est sans authentification.
The constructor accepts no credentials — the P2P model is unauthenticated.
Paramètre
Type
Défaut
Description
terminalBaseUrl
string
requis
URL de base : scheme + IP + port (ex : https://192.168.1.50:8080). Scheme obligatoire.
verifyTls
bool|string
true
true = CA système ; string = chemin PEM (CA pinné) ; false = pas de vérif (LAN fermé).
useIsvEndpoints
bool
false
Cible les variantes ISV (chemins à slash final, ex : /pos/v1/sale/).
Le terminal sert du HTTPS, le plus souvent avec un certificat auto-signé. Trois modes :
// 1. Vérification standard (CA système) — défaut. Échoue sur cert auto-signé.
$terminal = new VivaLocalTerminalClient('https://192.168.1.50:8080');
// 2. Pinner le bundle CA du terminal (recommandé en production)
$terminal = new VivaLocalTerminalClient(
terminalBaseUrl: 'https://192.168.1.50:8080',
verifyTls: '/chemin/vers/terminal-ca.pem',
);
// 3. Désactiver la vérification (modèle de confiance LAN-only)
$terminal = new VivaLocalTerminalClient(
terminalBaseUrl: 'https://192.168.1.50:8080',
verifyTls: false,
);
verifyTls est transmis tel quel à l'option Guzzle verify. Privilégiez le pinning
du CA (option 2) plutôt que false dès que possible.
Ressources
1
Transactions
$terminal->transactions
Opérations de transaction. Chaque opération retourne immédiatementstate + sessionId ; interroger sessions->get() pour le résultat
final. Montants toujours en centimes.
Transaction operations. Each returns immediately with state + sessionId; poll sessions->get() for the outcome. Amounts in cents.
sale()
Initier une vente — POST /pos/v1/sale. Le terminal affiche le montant et attend la carte.
refund(string $sessionId, int $amount, string $transactionId, ...): array
Rembourser / annuler une transaction par son ID d'origine — POST /pos/v1/refund.
Champs optionnels : orderCode, shortOrderCode, currencyCode,
showTransactionResult, showReceipt, txnDateFrom,
txnDateTo, paramètres AADE.
unreferencedRefund(string $sessionId, int $amount, ...): array
Remboursement non lié à une transaction d'origine — POST /pos/v1/unreferenced-refund.
Champs optionnels : merchantReference, customerTrns,
showTransactionResult, showReceipt, paramètres AADE,
fiscalisationData.
Action de contrôle AADE FIM (fiscalisation grecque) — POST /pos/v1/aade-fim-control.
Crée l'Echo Message + le Control Message et valide la Master Key, le KCV et la Session Key chiffrée.
Récupération de session (polling). Après qu'une opération a retourné PROCESSING, interrogez
la session pour le résultat final. payloadData n'est renseigné qu'une fois la transaction
terminée (SUCCESS/FAILURE).
get(string $sessionId): array
Récupérer le détail d'une session — GET /pos/v1/sessions/{sessionId}.
Erreurs 400 = chaînes brutes. La Local Terminal API ne retourne pas de codes d'erreur
structurés. Sur une 400, elle renvoie un corps en chaîne de caractères brute
(ex : "ZeroconfException error message Amount cannot be null"). Le SDK préserve ce texte verbatim.
— 400 errors are raw strings, not JSON. The SDK preserves them verbatim.
Toutes les exceptions héritent de VivaException (extends RuntimeException).
RuntimeException
└── VivaException (base — httpStatus, responseBody, getErrorText())
└── ApiException (levée sur 4xx ET sur terminal injoignable : httpStatus === 0)
Membre
Type
Description
$httpStatus
int
Code HTTP (0 si le terminal est injoignable)
$responseBody
?array
Corps décodé ; chaîne brute préservée sous ['raw' => '...']
getErrorText()
?string
message, error, puis fallback sur raw
use QrCommunication\VivaLocalTerminal\Exceptions\ApiException;
use QrCommunication\VivaLocalTerminal\Exceptions\VivaException;
try {
$resp = $terminal->transactions->sale(sessionId: $sessionId, amount: 1170);
} catch (ApiException $e) {
echo $e->httpStatus; // 400, ou 0 si injoignable sur le LAN
echo $e->getErrorText(); // ex: "ZeroconfException error message Amount cannot be null"
echo $e->responseBody['raw']; // chaîne brute du terminal (si 400 non-JSON)
if ($e->httpStatus === 0) {
// Terminal injoignable — vérifier IP/port/réseau
}
} catch (VivaException $e) {
echo $e->getMessage();
}
Variantes Merchant vs ISV
Merchant vs ISV variants
Chaque endpoint existe en deux variantes : merchant (sans slash final) et
ISV (avec slash final, ex : /pos/v1/sale/). Un seul jeu de méthodes +
le toggle global useIsvEndpoints gère les deux.