bahaa-io/gateway-php-sdk

Official PHP SDK for Bahaa Gateway.

Maintainers

Package info

github.com/bahaa-io/gateway-php-sdk

Homepage

pkg:composer/bahaa-io/gateway-php-sdk

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 3

Open Issues: 0

1.0.0 2026-04-18 04:54 UTC

This package is auto-updated.

Last update: 2026-04-18 04:55:48 UTC


README

Official PHP SDK for Bahaa Gateway — accept crypto payments on TRON and TON networks. Create invoices, track payments, manage withdrawals, and securely verify webhooks with just a few lines of code.

Requirements

  • PHP 7.4 or later
  • ext-curl
  • ext-json

Installation

composer require bahaa-io/gateway-php-sdk

Quick Start

<?php

require __DIR__ . '/vendor/autoload.php';

use Bahaa\Gateway\Client;

$gateway = new Client(
    'pk_your_api_key',    // API key
    'sk_your_api_secret'  // API secret
);

// Create a $50 USDT invoice
$invoice = $gateway->createInvoice(50.00, 'USDT', [
    'description' => 'Order #1234',
]);

echo $invoice['payment_url'];
// → https://gateway.bahaa.io/abc123...

Authentication

All merchant endpoints are signed automatically. The SDK computes an HMAC-SHA256 signature from your API secret on every request — you don't need to do anything manually.

Header Description
X-API-Key Your merchant API key (pk_...)
X-Timestamp Current UNIX epoch
X-Signature HMAC-SHA256 of timestamp\nmethod\npath\nbody

API Reference

Public Endpoints

These don't require authentication.

// Health check
$gateway->health();
// → ['status' => 'ok']

// List supported networks
$networks = $gateway->getNetworks();
// → ['networks' => [['name' => 'tron', ...], ['name' => 'ton', ...]]]

// List supported symbols (optionally filter by network)
$symbols = $gateway->getSymbols();
$symbols = $gateway->getSymbols('tron');

Merchant Profile

$profile = $gateway->getProfile();
// → ['id' => 1, 'email' => '...', 'fee_percent' => 1.0, ...]

Invoices

// Create invoice
$invoice = $gateway->createInvoice(100.00, 'USDT', [
    'description'    => 'Premium Plan',
    'fee_payer'      => 'user',          // or 'merchant' (default)
    'allow_networks' => ['tron', 'ton'], // restrict networks
    'allow_symbols'  => ['USDT'],        // restrict symbols
]);

echo $invoice['id'];          // "f7a8b..."
echo $invoice['payment_url']; // full URL to the payment page

// Build a payment URL with language/theme
$url = $gateway->paymentUrl($invoice['id'], 'fa', 'dark');
// → https://gateway.bahaa.io/f7a8b...?lang=fa&theme=dark

// Get invoice
$invoice = $gateway->getInvoice('f7a8b...');

// List invoices (with optional filters)
$list = $gateway->getInvoices(['status' => 'completed', 'limit' => 10]);
foreach ($list['invoices'] as $inv) {
    echo $inv['id'] . '' . $inv['status'] . "\n";
}

// Cancel invoice
$result = $gateway->cancelInvoice('f7a8b...');
// → ['id' => 'f7a8b...', 'status' => 'cancelled']

Hosted checkout (public, no HMAC)

Same routes as the browser payment page: GET /{invoice_id}, POST …/select, GET …/status, POST …/cancel, and GET …/ws over WebSocket. These do not use your API key — safe to call from a server building a custom checkout.

$id = $invoice['id'];

// After the shopper picks chain + token
$selected = $gateway->checkoutSelect($id, 'tron', 'USDT');

// Poll status
$live = $gateway->checkoutStatus($id);

// Shopper cancels from checkout
$gateway->checkoutCancel($id);

WebSocket (live updates) — blocking call until the gateway closes the connection (e.g. invoice completed / expired / cancelled). Each text frame is JSON like the /status response.

$gateway->listenCheckoutUpdates($id, function (array $frame) {
    $data = $frame['data'] ?? $frame;
    // inspect status, confirmations, tx_hash, …
}, 300); // optional read timeout in seconds (default max(120, HTTP timeout))

// Or build the URL yourself (e.g. for another WS client):
$url = $gateway->checkoutWebSocketUrl($id);

wss:// needs PHP openssl (see composer.json suggest). Self-hosted gateway: pass a fourth constructor argument to Client:

$gateway = new Client($pk, $sk, 30, 'https://pay.example.com');

Balance

$balance = $gateway->getBalance();
foreach ($balance['balances'] as $b) {
    echo $b['symbol'] . ': ' . $b['available'] . "\n";
}

Withdrawals

// Create withdrawal
$wd = $gateway->createWithdrawal('tron', 'USDT', 50.0, 'TQd8...');

echo $wd['id'];     // withdrawal ID
echo $wd['status']; // "pending"

// Get withdrawal
$wd = $gateway->getWithdrawal('wd_abc...');

// List withdrawals
$list = $gateway->getWithdrawals(['limit' => 20]);

Transactions

// Get transaction
$tx = $gateway->getTransaction(42);

// List transactions
$list = $gateway->getTransactions(['limit' => 50]);

Webhooks

When an invoice status changes, Bahaa Gateway sends a POST request to your configured webhook URL. The SDK provides a simple way to verify and parse these requests.

Receiving Webhooks

<?php
// webhook.php

require __DIR__ . '/vendor/autoload.php';

use Bahaa\Gateway\Webhook;
use Bahaa\Gateway\Exception\GatewayException;

$webhook = new Webhook('sk_your_api_secret');

try {
    $payload = $webhook->verify();
} catch (GatewayException $e) {
    http_response_code(400);
    exit('Invalid webhook: ' . $e->getMessage());
}

$event = $payload['event'];
$data  = $payload['data'];

switch ($event) {
    case 'invoice.confirming':
        // Payment detected, waiting for confirmations
        // $data['invoice_id'], $data['tx_hash'], ...
        break;

    case 'invoice.completed':
        // Payment confirmed! Fulfill the order.
        markOrderAsPaid($data['invoice_id']);
        break;

    case 'invoice.cancelled':
        // Cancelled via API, checkout, or policy — release holds, stop polling.
        break;

    case 'invoice.expired':
        // TTL passed with no payment — treat as abandoned checkout.
        break;
}

http_response_code(200);
echo 'OK';

Using via the Client

You can also create a webhook verifier from an existing client instance:

$gateway = new Client('pk_...', 'sk_...');

$payload = $gateway->webhook()->verify();

Webhook Payload

{
    "event": "invoice.completed",
    "timestamp": 1708790400,
    "data": {
        "invoice_id": "abc123",
        "amount": 50.00,
        "symbol": "USDT",
        "status": "completed",
        "tx_hash": "0x...",
        "crypto_amount": 50.123456,
        "crypto_symbol": "TRX",
        "crypto_network": "tron"
    }
}

Webhook Events

Event Description
invoice.confirming Payment detected on-chain, waiting for block confirmations.
invoice.completed Payment fully confirmed, merchant balance credited.
invoice.cancelled Invoice cancelled (merchant API, hosted checkout, or operator) before completion.
invoice.expired Invoice TTL elapsed with no qualifying payment.

Signature Verification (Manual)

If you prefer to verify manually without the SDK:

$timestamp = $_SERVER['HTTP_X_GATEWAY_TIMESTAMP'];
$signature = $_SERVER['HTTP_X_GATEWAY_SIGNATURE'];
$body      = file_get_contents('php://input');

$expected = hash_hmac('sha256', $timestamp . '.' . $body, $apiSecret);

if (!hash_equals($expected, $signature)) {
    die('Invalid signature');
}

Error Handling

The SDK throws specific exceptions for different error types:

use Bahaa\Gateway\Exception\GatewayException;
use Bahaa\Gateway\Exception\AuthenticationException;
use Bahaa\Gateway\Exception\ValidationException;
use Bahaa\Gateway\Exception\NotFoundException;

try {
    $invoice = $gateway->getInvoice('nonexistent');
} catch (NotFoundException $e) {
    echo 'Not found: ' . $e->getMessage();
} catch (AuthenticationException $e) {
    echo 'Auth error: ' . $e->getMessage();
} catch (ValidationException $e) {
    echo 'Validation: ' . $e->getMessage();
    echo 'Code: ' . $e->getErrorCode();
} catch (GatewayException $e) {
    echo 'Gateway error: ' . $e->getMessage();
    echo 'HTTP status: ' . $e->getHttpStatus();
}
Exception HTTP Status When
AuthenticationException 401 Invalid API key, expired timestamp, or bad signature.
ValidationException 400, 422 Invalid request parameters.
NotFoundException 404 Resource not found.
GatewayException Any Base class for all gateway errors.

Full Example

A complete payment flow:

<?php

require __DIR__ . '/vendor/autoload.php';

use Bahaa\Gateway\Client;

$gateway = new Client(
    'pk_your_api_key',
    'sk_your_api_secret'
);

// 1. Create invoice
$invoice = $gateway->createInvoice(25.00, 'USDT', [
    'description' => 'Monthly subscription',
]);

// 2. Redirect user to payment page (Farsi, dark theme)
$url = $gateway->paymentUrl($invoice['id'], 'fa', 'dark');
header('Location: ' . $url);

// 3. Later, check status programmatically
$status = $gateway->getInvoice($invoice['id']);
echo 'Status: ' . $status['status']; // pending → awaiting_payment → confirming → completed

// 4. Check your balance
$balance = $gateway->getBalance();
print_r($balance['balances']);

// 5. Withdraw funds
$wd = $gateway->createWithdrawal('tron', 'USDT', 20.0, 'TQd8...');
echo 'Withdrawal: ' . $wd['status'];

Links

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT