PHP code example of dominaite / merchant-sdk

1. Go to this page and download the library: Download dominaite/merchant-sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

dominaite / merchant-sdk example snippets



Dominaite\DominaiteClient;

$client = new DominaiteClient(getenv('DOMINAITE_KEY_ID'), getenv('DOMINAITE_SECRET'));

print_r($client->ping());
// ['pong' => true, 'merchantId' => '...', 'serverTime' => '...', 'clockSkewSeconds' => 0]


Dominaite\DominaiteClient;
use Dominaite\Exception\CheckoutRefusedException;
use Dominaite\Exception\RateLimitException;
use Dominaite\Exception\TransportException;

$client = new DominaiteClient(getenv('DOMINAITE_KEY_ID'), getenv('DOMINAITE_SECRET'));

try {
    $session = $client->createCheckoutSession([
        'amount'         => 2500,            // minor units: 2500 = 25.00 EUR
        'currency'       => 'EUR',
        'orderReference' => 'order-1042',    // your own order id, shows up in your dashboard
        'customer'       => [
            // Pass everything you already know - prefilled fields are hidden from the
            // payer, so the checkout form stays short.
            'firstName' => 'Ana',
            'lastName'  => 'Kirova',
            'email'     => '[email protected]',
        ],
        'language'       => 'bg',            // widget UI language
        'theme'          => 'dark',
    ]);
} catch (CheckoutRefusedException $e) {
    // Machine-readable: $e->getErrorCode() - see the exception docblock for the codes.
    http_response_code(409);
    exit('Payment unavailable: ' . $e->getErrorCode());
} catch (RateLimitException $e) {
    // You are over the rate limit. Nothing is retried for you - back off first.
    http_response_code(503);
    header('Retry-After: ' . ($e->getRetryAfterSeconds() ?? 5));
    exit('Payment temporarily unavailable');
} catch (TransportException $e) {
    // Network blip or a 5xx - retry with $client->getLastIdempotencyKey(), never a fresh key.
    http_response_code(503);
    exit('Payment temporarily unavailable');
}

// Store $session['transactionId'] against your order, then render the widget:


Dominaite\DominaiteClient;

// The RAW body, before any parsing. Do not use $_POST and do not re-encode:
// the signature covers these exact bytes.
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';

if (!DominaiteClient::verifyWebhook($payload, $signature, getenv('DOMINAITE_WEBHOOK_SECRET'))) {
    http_response_code(400);
    exit;
}

$event = json_decode($payload, true);

// Answer immediately, then do the work. Anything slow here eats into the delivery
// timeout and earns you a retry you did not need.
http_response_code(200);

if (!already_handled($event['id'])) {          // dedupe on the delivery id
    queue_fulfilment($event);                  // your own job queue
    mark_handled($event['id']);
}

$session = null;
$key = null;

for ($attempt = 1; $attempt <= 3 && $session === null; $attempt++) {
    if ($key !== null) {
        $params['idempotencyKey'] = $key;
    }
    try {
        $session = $client->createCheckoutSession($params);
    } catch (TransportException $e) {
        // Read the key here, in the catch - store it against your order before you
        // sleep or hand off, because the next create() call overwrites it.
        $key = $client->getLastIdempotencyKey();
        if ($attempt === 3) {
            throw $e;
        }
        sleep($attempt);
    }
}

use Dominaite\Exception\ChargeException;
use Dominaite\Exception\RevokeException;

$session = $client->createCheckoutSession([
    'amount'         => 2500,
    'currency'       => 'EUR',
    'orderReference' => 'sub-8817-first',
    'saveCard'       => true,
]);
// ... the payer completes the hosted checkout ...
$status = $client->getStatus($session['transactionId']);
$stored = $status['storedPaymentMethod'] ?? null; // absent until the payment is approved
if ($status['status'] === 'succeeded' && ($stored['status'] ?? null) === 'active') {
    $db->saveCard($customerId, $stored['id']); // pm_...
}

// Later, off-session, no payer present:
try {
    $charge = $client->chargePaymentMethod($paymentMethodId, [
        'amount'         => 2500,
        'currency'       => 'EUR',
        'orderReference' => 'sub-8817-2026-10',
        'description'    => 'Monthly plan, October',
        'idempotencyKey' => 'sub-8817-2026-10', // derive it from the billing period, never random per attempt
    ]);

    switch ($charge['status']) {
        case 'succeeded':
            break;
        case 'pending':
            // Not terminal. Poll getStatus($charge['transactionId']), or wait for the webhook.
            break;
        case 'failed':
            // HTTP 402 from the gateway, but not an exception: branch on the class, log the code.
            // hard              - give up on this card, ask the customer for another one
            // soft_funds        - insufficient funds, retry later (not in a loop)
            // soft_sca_ (RevokeException $e) {
    if ($e->getErrorCode() === 'MERCHANT_API_UNAVAILABLE') {
        // 503: nothing changed, retry later.
    } else {
        // 502 UPSTREAM_CONTRACT_ERROR: the provider refused for good, nothing changed. Contact support with the id.
    }
}

$status = $client->getStatus($session['transactionId']);
// ['transactionId' => ..., 'orderReference' => 'order-1042', 'status' => 'succeeded',
//  'amount' => 2500, 'currency' => 'EUR', ...]

try {
    $session = $client->createCheckoutSession($params);
} catch (CheckoutRefusedException $refusal) {
    if ($refusal->getTransactionId() !== null) {
        $status = $client->getStatus($refusal->getTransactionId());
        // Now you know what the earlier attempt actually did.
    }
}
bash
composer