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

Viva Local Terminal PHP SDK

qrcommunication/viva-local-terminal-sdk

PHP 8.2+, guzzlehttp/guzzle ^7.8

⚠️ 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

  1. L'hôte exécutant votre code et le terminal doivent être sur le même LAN.
  2. Vous devez connaître l'IP et le port du terminal (app Viva.com Terminal, réseau, ou zeroconf/mDNS).
  3. 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.

composer require qrcommunication/viva-local-terminal-sdk

Compatible avec Laravel, Symfony ou tout projet PHP standard.

Démarrage rapide Quick 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/).
timeout int 30 Timeout par requête (secondes).
connectTimeout int 10 Timeout de connexion TCP (secondes).

Propriétés publiques

$terminal->transactions  // Transactions
$terminal->sessions      // Sessions
$terminal->device        // Device

$terminal->getConfig();  // Config courante (introspection)

TLS — certificats auto-signés TLS — self-signed certificates

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édiatement state + 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.

Paramètre Type Défaut Description
sessionIdstringrequisUUID de session généré par l'appelant
amountintrequisMontant à autoriser, en centimes
merchantReference?stringnullRéférence libre côté marchand
customerTrns?stringnullRéférence libre côté client
preauth?boolnullLe paiement est-il une pré-autorisation
tipAmount?intnullPourboire en centimes (incompatible avec preauth)
paymentMethod?stringnullMéthode affichée en premier (ex : CardPresent)
showTransactionResult?boolnullAfficher le résultat à l'écran
showReceipt?boolnullAfficher le reçu + résultat
currencyCode?intnullCode ISO 4217 numérique (devise marchand)
skipSurcharge?boolnullDésactiver le surcharge même sur cartes éligibles
saleToAcquirerData?stringnullJSON base64 de métadonnées acquéreur
maxInstalments?intnullVersements max (marchands grecs)
aadeProviderIdaadePreloadedDuration?string/?bool/?intnullParamètres AADE (Grèce)
fiscalisationData?arraynullObjet Viva Fiscalisation
isvDetails?arraynullObjet partenaire / fee / multi-marchand (ISV uniquement)

Retourne : array{state?: string, sessionType?: string, sessionId?: string}

$resp = $terminal->transactions->sale(
    sessionId:         '4bdebe62-c211-4ca0-a994-b2fbea2061c5',
    amount:            1170,        // 11,70 EUR
    currencyCode:      978,         // EUR
    merchantReference: 'order-123',
    showReceipt:       true,
);

echo $resp['state'];       // 'PROCESSING'
echo $resp['sessionType']; // 'SALE'

// Puis polling :
$session = $terminal->sessions->get($resp['sessionId']);

capturePreauth(string $sessionId, int $amount, string $transactionId, ...): array

Capturer (compléter) une vente pré-autorisée — POST /pos/v1/preauth-completion. Champs optionnels : merchantReference, customerTrns, currencyCode, saleToAcquirerData, paramètres AADE.

$resp = $terminal->transactions->capturePreauth(
    sessionId:     'a-new-uuid',
    amount:        1500,        // 15,00 EUR
    transactionId: 'preauth-transaction-id',
);

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.

$resp = $terminal->transactions->refund(
    sessionId:     'a-new-uuid',
    amount:        1170,
    transactionId: 'original-sale-transaction-id',
);

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.

$resp = $terminal->transactions->unreferencedRefund(
    sessionId: 'a-new-uuid',
    amount:    500, // 5,00 EUR
);

abort(string $sessionId): array

Interrompre une session SALE en cours — POST /pos/v1/abort.

$terminal->transactions->abort('4bdebe62-c211-4ca0-a994-b2fbea2061c5');

aadeFimControl(string $token): array

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.

Retourne : array{status?: string, message?: string}

$resp = $terminal->transactions->aadeFimControl(
    'ECR0210U/RCFB77000041/CMAC_K:1ED9F7AE0B2509281BBC2DE38EF2A12B:CC5FFF',
);
echo $resp['status'];  // 'success'
echo $resp['message']; // 'Fim control success'

retrieve(?string $cardNumber, ?string $orderCode, int|array|null $transactionTypes, ...): array

Lister les transactions historiques avec filtres optionnels — GET /pos/v1/transactions. transactionTypes accepte un id unique ou une liste.

Retourne : array{isSuccess?: bool, transactions?: array<int, array<string, mixed>>}

$result = $terminal->transactions->retrieve(
    transactionTypes: [5, 4], // ventes + remboursements
    startDate:        '2026-03-01T00:00:00Z',
    endDate:          '2026-03-31T23:59:59Z',
);

foreach ($result['transactions'] ?? [] as $txn) {
    echo $txn['orderCode'] . PHP_EOL;
}

2 Sessions $terminal->sessions

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}.

Retourne : array{state?: string, sessionType?: string, sessionId?: string, payloadData?: array<string, mixed>}

use QrCommunication\VivaLocalTerminal\Enums\SessionState;

do {
    $session = $terminal->sessions->get($sessionId);
    $state = $session['state'] ?? null;

    if ($state === SessionState::SUCCESS->value) {
        // Paiement réussi — $session['payloadData'] contient le détail
        break;
    }
    if ($state === SessionState::FAILURE->value) {
        break; // Paiement échoué
    }

    sleep(2);
} while ($state === SessionState::PROCESSING->value);

3 Device $terminal->device

Contrôle du terminal physique : réveil/veille de l'écran et luminosité.

screenControl(bool $wakeUpLock): array

Contrôler l'écran / mode veille — POST /pos/v1/awake-lock. true : réveil + écran actif jusqu'au déverrouillage. false : veille normale.

Retourne : array{isSuccess?: bool}

$resp = $terminal->device->screenControl(wakeUpLock: true);
echo $resp['isSuccess']; // true

brightness(float $brightness): array

Régler la luminosité — POST /pos/v1/brightness. Valeur dans (0, 1] (0 interdit). Lève \InvalidArgumentException hors plage.

$terminal->device->brightness(0.5); // 50 %
$terminal->device->brightness(1.0); // maximum
// $terminal->device->brightness(0.0); // ❌ InvalidArgumentException

Enums

Sous QrCommunication\VivaLocalTerminal\Enums.

SessionState

ValeurDescription
PROCESSINGL'opération est en cours sur le terminal
BUSY_ERRORUne autre transaction est déjà en cours
SERVER_ERRORErreur côté serveur du terminal
SESSION_NOT_FOUND_ERRORLe sessionId fourni est introuvable (abort)
SUCCESSLa transaction s'est terminée avec succès
FAILURELa transaction s'est terminée en erreur

SessionType

ValeurDescription
SALETransaction de vente
CAPTURE_PREAUTHCapture d'une vente pré-autorisée
CANCELRemboursement / annulation référencé
UNREFERENCED_REFUNDRemboursement non référencé
ABORTInterruption d'une session SALE

TransactionTypeId

ConstanteValeurDescription
SALE5Vente
REFUND4Remboursement
REVERSAL7Annulation (reversal)
IRIS_SALE60Vente IRIS
IRIS_REFUND61Remboursement IRIS
IRIS_VOID85Annulation IRIS

PaymentMethod

ConstanteValeur
CARD_PRESENTCardPresent
IRISIris

Gestion des erreurs Error Handling

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)
MembreTypeDescription
$httpStatusintCode HTTP (0 si le terminal est injoignable)
$responseBody?arrayCorps décodé ; chaîne brute préservée sous ['raw' => '...']
getErrorText()?stringmessage, 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.

$terminal = new VivaLocalTerminalClient(
    terminalBaseUrl: 'https://192.168.1.50:8080',
    useIsvEndpoints: true,
);

$terminal->transactions->sale(
    sessionId:  $sessionId,
    amount:     1170,
    isvDetails: [/* objet partenaire / fee / multi-marchand ISV */],
);

isvDetails est omis du corps quand il vaut null — inoffensif pour les appels merchant.

Changelog v1.0.0

✨ Version initiale. SDK P2P sans authentification pour la Local Terminal API de Viva.com. GitHub Release v1.0.0 →
  • Modèle P2P sans authentification : communication directe avec le terminal sur le LAN, aucun header Authorization.
  • TLS configurable (verifyTls : true / chemin PEM / false) pour certificats auto-signés.
  • Ressource Transactions : sale(), capturePreauth(), refund(), unreferencedRefund(), abort(), aadeFimControl(), retrieve().
  • Ressource Sessions : get() (polling du résultat).
  • Ressource Device : screenControl(), brightness().
  • Enums : SessionState, SessionType, TransactionTypeId, PaymentMethod.
  • Variantes Merchant et ISV via useIsvEndpoints.
  • Erreurs 400 préservées en chaîne brute ; ApiException avec httpStatus === 0 sur terminal injoignable.