PHP SDK

Official PHP SDK for Scan & Pay — accept PayTo PayID payments via QR code from any PHP backend (Laravel, Symfony, Magento, plain PHP, …).

Install

composer require scanandpay/php

Requires PHP 8.1+ with the curl, json, and hash extensions.

Quickstart

use ScanAndPay\ScanAndPay;
use ScanAndPay\Exceptions\WebhookSignatureException;

$client = new ScanAndPay(
    merchantId: getenv('SCANANDPAY_MERCHANT_ID'),
    apiSecret: getenv('SCANANDPAY_API_SECRET'),
    webhookSecret: getenv('SCANANDPAY_WEBHOOK_SECRET'), // optional
);

// 1. Create a session at checkout. Amount is float dollars.
$session = $client->createSession(
    amount: 19.90, // $19.90
    platformOrderId: 'order_456',
    payId: 'merchant@example.com.au',
    merchantName: 'Acme Coffee',
);

// 2. Render the QR widget on the page.
echo scanandpay_checkout($session, pollUrl: '/scanandpay/status');

// 3. In your webhook handler, verify and consume the event.
try {
    $event = $client->webhooks()->verify(
        signature: $_SERVER['HTTP_X_SCANPAY_SIGNATURE'] ?? '',
        body: file_get_contents('php://input'),
    );

    if ($event->isPaid()) {
        // Mark order paid using $event->orderId, $event->txId, ...
    }
} catch (WebhookSignatureException $e) {
    http_response_code(401);
    exit('Invalid webhook');
}

Amount format

amount is always float dollars (e.g. 19.90 for $19.90). This matches the Scan & Pay API directly — no multiplication or division needed.

$client->createSession(amount: 19.90, ...);   // ✓ $19.90
$client->createSession(amount: 0.50, ...);    // ✓ $0.50
$client->createSession(amount: 1000.00, ...); // ✓ $1,000.00
$client->createSession(amount: -1, ...);      // ✗ ValidationException
$client->createSession(amount: 0, ...);       // ✗ ValidationException

For display, use $session->amount directly:

$display = number_format($session->amount, 2);  // "19.90"

Error handling

All thrown errors extend ScanAndPay\\Exceptions\\ScanAndPayException.

ClassWhen
ValidationExceptionBad input rejected before any HTTP call.
AuthenticationExceptionAPI rejected API Secret (rotate your keys).
ApiExceptionNon-2xx response from the API.
NetworkExceptionTransport failure after exhausting retries.
WebhookSignatureExceptionWebhook signature or timestamp check failed.

Resources