coinpay/php-integration

php package for coin payment finance

Maintainers

Package info

github.com/coinpay-finance/php-integration-package

pkg:composer/coinpay/php-integration

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.2.0 2025-05-20 14:58 UTC

This package is not auto-updated.

Last update: 2026-08-13 11:29:17 UTC


README

Safe, fast and instant payments; Anytime, anywhere with CoinPay.

This is CoinPay's official framework-agnostic PHP SDK — plain PHP, zero third-party dependencies (only ext-curl and ext-json). If you're on Laravel, use coinpay/laravel-integration instead.

Installation

Install with composer:

composer require coinpay/php-integration

Requires PHP 7.4+ or 8.0+, with the curl and json extensions.

Creating a payment

use Coinpay\Finance\CoinPayGateway;
use Coinpay\Finance\Exceptions\CoinPayException;

$gateway = new CoinPayGateway('###COINPAY_API_KEY###');

try {
    $response = $gateway->createPayment(
        1.0,                                                            // The amount to be paid (in Dollar - $).
        'https://your-callback.url',                                    // The URL the user will be redirected to after payment.
        'ref123',                                                       // A unique reference ID for tracking the transaction.
        'payer@example.com',                                            // The identity of the payer (email or phone number).
        'Alimo',                                                        // Full name of the payer.
        'Test Payment',                                                 // Description of the payment (e.g. "Payment for order #123").
        '1234567890'                                                    // National identification code of the payer.
    );

    echo "Payment URL: " . $response->url . PHP_EOL;                    // Redirect the user to this URL
    echo "Transaction ID: " . $response->transactionId . PHP_EOL;       // Store this ID if you need it later
} catch (CoinPayException $e) {
    // $e->getHttpStatusCode() — HTTP status code, or 0 if the request never got a response
    // $e->getResponseBody()   — decoded (array) or raw (string) response body, if any
    // $e->isNetworkError()    — true for connection/timeout failures rather than API rejections
    echo "Error: " . $e->getMessage() . PHP_EOL;
}

Checking a payment's status

use Coinpay\Finance\CoinPayGateway;
use Coinpay\Finance\Exceptions\CoinPayException;

$gateway = new CoinPayGateway('###COINPAY_API_KEY###');

try {
    $status = $gateway->checkStatus('transaction-id-from-createPayment');

    echo $status->status . PHP_EOL;          // e.g. "completed", "pending", "failed"
    echo $status->amount . PHP_EOL;
    echo $status->transactionId . PHP_EOL;
    echo $status->reason . PHP_EOL;
    echo $status->transactionHash . PHP_EOL;
    echo $status->network . PHP_EOL;
} catch (CoinPayException $e) {
    echo "Error: " . $e->getMessage() . PHP_EOL;
}

Verifying webhooks

CoinPay notifies your application asynchronously about payment status changes. Since this package targets plain PHP with no framework/router to pass you a parsed request, read the raw request body yourself with file_get_contents('php://input') and pull the relevant headers, then verify before trusting anything in the payload.

Two verification schemes exist:

Current: HMAC-SHA256 signature (X-Coinpay-Signature)

The request carries three headers — X-Coinpay-Signature: v1=<hex-hmac-sha256>, X-Coinpay-Timestamp: <unix-seconds>, and X-Coinpay-Delivery: <uuid> — and the signature covers "{timestamp}.{deliveryId}.{rawBody}". CoinPayWebhookVerifier::verify() recomputes the digest, compares it with hash_equals(), and rejects the request if the timestamp is more than 300 seconds old or in the future.

use Coinpay\Finance\CoinPayWebhookVerifier;

$rawBody    = file_get_contents('php://input');
$timestamp  = $_SERVER['HTTP_X_COINPAY_TIMESTAMP'] ?? '';
$deliveryId = $_SERVER['HTTP_X_COINPAY_DELIVERY'] ?? '';
$signature  = $_SERVER['HTTP_X_COINPAY_SIGNATURE'] ?? null;
$secret     = '###YOUR_COINPAY_WEBHOOK_SECRET###';

if (!CoinPayWebhookVerifier::verify($rawBody, $timestamp, $deliveryId, $secret, $signature)) {
    http_response_code(403);
    exit;
}

$payload = json_decode($rawBody, true);

// $payload['status'], $payload['reason'], $payload['transaction_id'],
// $payload['amount'], $payload['transaction_hash']

http_response_code(200);

Legacy: static shared-secret header (SECRET) — deprecated

Older deliveries may still arrive with a plain SECRET header instead of a signature. This scheme is deprecated (no payload binding, no timestamp, no replay protection) but CoinPay still accepts it during the transition window, so a merchant that wants to keep working without gaps should check for it as a fallback when X-Coinpay-Signature is absent:

use Coinpay\Finance\CoinPayWebhookVerifier;

$rawBody = file_get_contents('php://input');
$secret  = '###YOUR_COINPAY_WEBHOOK_SECRET###';

$signature = $_SERVER['HTTP_X_COINPAY_SIGNATURE'] ?? null;

$verified = $signature !== null
    ? CoinPayWebhookVerifier::verify(
        $rawBody,
        $_SERVER['HTTP_X_COINPAY_TIMESTAMP'] ?? '',
        $_SERVER['HTTP_X_COINPAY_DELIVERY'] ?? '',
        $secret,
        $signature
    )
    : CoinPayWebhookVerifier::verifyLegacy($secret, $_SERVER['HTTP_SECRET'] ?? null);

if (!$verified) {
    http_response_code(403);
    exit;
}

Prefer the HMAC path for any new integration; only fall back to the legacy path if you need to support deliveries that predate signature verification.

Exceptions

Every failure — a rejected API request or a network/timeout failure — is thrown as Coinpay\Finance\Exceptions\CoinPayException, which extends \Exception and additionally exposes:

  • getHttpStatusCode(): int — the HTTP status code, or 0 if no response was ever received.
  • getResponseBody() — the decoded (array) or raw (string) response body, if any.
  • isNetworkError(): booltrue for connection/timeout failures rather than API rejections.
  • getCurlErrno(): ?int — the curl error number, when isNetworkError() is true.

Testing

composer install
composer test