pspline/php-sdk

Official PHP SDK for PSP Line Merchant API — crypto invoices, payments, wallets

Maintainers

Package info

github.com/pspline/php-sdk

pkg:composer/pspline/php-sdk

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-02-11 10:55 UTC

This package is auto-updated.

Last update: 2026-04-11 11:24:30 UTC


README

CI Latest Version PHP Version License: MIT

Official PHP SDK for the PSP Line Merchant API — create crypto invoices, check payment statuses, and verify webhook signatures.

Requirements

  • PHP 7.2 or higher (tested on 7.4 — 8.4)
  • Extensions: curl, json, mbstring
  • No external dependencies required (Guzzle is optional)

Installation

composer require pspline/php-sdk

Quick Start

use PspLine\PspLine;

$psp = new PspLine(
    232,                    // merchant_id
    'your-public-key',      // publicKey
    'your-private-key'      // privateKey
);

// Create a crypto invoice
$invoice = $psp->invoices->create([
    'service_id'       => 885,
    'wallet_id'        => 52205,
    'currency'         => 'USDT_TRON',
    'estimated_amount' => 15000000,    // 15 USDT (precision 6)
    'callback_url'     => 'https://your-site.test/webhooks/pspline',
    'confirm_url'      => 'https://your-site.test/payment/success',
    'fields'           => ['user_id' => 'customer-123'],
]);

echo $invoice->walletAddress;  // Crypto address for payment
echo $invoice->verifyUrl;      // Web form URL (alternative)
echo $invoice->status;         // 0 = waiting for deposits

Configuration

All Options

Option Type Default Description
base_url string https://app.pspline.com/api/cpci/v1 API base URL
timeout int 30 Request timeout in seconds
retries int 2 Retry count on 5xx/network errors
logger LoggerInterface null PSR-3 logger instance
http_client HttpClientInterface null Custom HTTP transport

Logging

Pass any PSR-3 compatible logger:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('pspline');
$logger->pushHandler(new StreamHandler('logs/pspline.log'));

$psp = new PspLine($merchantId, $publicKey, $privateKey, [
    'logger' => $logger,
]);

Using Guzzle

By default, the SDK uses a built-in cURL client with zero dependencies. If you prefer Guzzle:

use PspLine\PspLine;
use PspLine\Http\GuzzleHttpClient;
use PspLine\Configuration;

$config = new Configuration($merchantId, $publicKey, $privateKey);
$guzzleClient = new GuzzleHttpClient($config);

$psp = new PspLine($merchantId, $publicKey, $privateKey, [
    'http_client' => $guzzleClient,
]);

API Reference

Invoices

Create Invoice

$invoice = $psp->invoices->create([
    // Required
    'service_id'       => 885,          // Service ID
    'wallet_id'        => 52205,        // Wallet to credit
    'currency'         => 'USDT_TRON',  // Currency code
    'estimated_amount' => 15000000,     // Amount in min units

    // Optional
    'external_id'      => 'order-789',  // Your system ID
    'callback_url'     => 'https://...',
    'confirm_url'      => 'https://...',
    'fields'           => ['user_id' => 'u001'],
]);

// Response
$invoice->id;              // string — Invoice UUID
$invoice->walletAddress;   // string|null — Crypto address
$invoice->walletMemo;      // string|null — Memo (XRP, TON, etc.)
$invoice->verifyUrl;       // string|null — Web payment form URL
$invoice->status;          // int — Status code
$invoice->currency;        // string — Currency code
$invoice->estimatedAmount; // int — Expected amount
$invoice->receivedAmount;  // int — Actually received

Find Invoice

// By PSP Line invoice ID
$invoice = $psp->invoices->find(['id' => 'invoice-uuid']);

// By your external ID
$invoice = $psp->invoices->find(['external_id' => 'order-789']);

// Check status
if ($invoice->isSuccessful()) {
    // Payment completed — deliver goods
} elseif ($invoice->isPending()) {
    // Still waiting — check again later
} elseif ($invoice->isFailed()) {
    // Payment failed or timed out
}

Invoice Statuses

Status Constant Description
0 InvoiceStatus::WAITING Waiting for deposits
1 InvoiceStatus::SUCCESS Successful
2 InvoiceStatus::FAILED Unsuccessful
3 InvoiceStatus::CANCELLED Cancelled
4 InvoiceStatus::TIMEOUT Timeout
10 InvoiceStatus::CHECKING Data checking
11 InvoiceStatus::PARTIAL_SUCCESS Partial success
12 InvoiceStatus::UNCOMPLETED_MERGE Uncompleted merge
13 InvoiceStatus::UNCOMPLETED_CHARGE Uncompleted charge
14 InvoiceStatus::UNIDENTIFIED Unidentified

Cryptocurrency Amounts

PSP Line uses integer amounts in minimum currency units:

Currency Precision Example
USDT_TRON 6 15 USDT → 15000000
BTC 8 0.001 BTC → 100000
ETH 18 0.027 ETH → 27000000000000000
USDT_ETH 6 100 USDT → 100000000

Webhook Verification

PSP Line sends POST callbacks with HMAC signatures. Always verify them:

use PspLine\Webhook\SignatureValidator;

$body      = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_TIMESTAMP'] ?? '';

$isValid = SignatureValidator::isValid(
    $body,
    $signature,
    $timestamp,
    'your-private-key',
    120  // max age in seconds (default)
);

if (!$isValid) {
    http_response_code(401);
    exit('Invalid signature');
}

// Process the webhook safely
$data = json_decode($body, true);

Error Handling

The SDK throws specific exceptions for different error types:

use PspLine\Exception\PspLineException;
use PspLine\Exception\AuthenticationException;
use PspLine\Exception\ApiException;
use PspLine\Exception\ValidationException;
use PspLine\Exception\NetworkException;

try {
    $invoice = $psp->invoices->create([...]);
} catch (AuthenticationException $e) {
    // Invalid keys, timestamp, or signature
    // API codes: 2001, 2002, 2003
    echo "Auth error: " . $e->getMessage();

} catch (ValidationException $e) {
    // Missing or invalid parameters
    echo "Validation: " . $e->getMessage();

} catch (ApiException $e) {
    // PSP Line API returned an error
    echo "API error [{$e->getApiCode()}]: {$e->getMessage()}";
    echo "HTTP: {$e->getHttpCode()}";
    echo "Raw: {$e->getRawBody()}";

} catch (NetworkException $e) {
    // Connection timeout, DNS failure, etc.
    echo "Network error: " . $e->getMessage();

} catch (PspLineException $e) {
    // Base catch-all for any SDK error
    echo "SDK error: " . $e->getMessage();
}

Exception Hierarchy

PspLineException (base)
├── NetworkException        — cURL/connection failures
└── ApiException            — API returned error code
    ├── AuthenticationException — auth errors (2001-2006)
    └── ValidationException     — input validation (100, 422)

Testing

# Run all tests
composer test

# With coverage report
composer test:coverage

# Static analysis
composer analyse

# Code style check
composer cs-check

# Code style fix
composer cs-fix

Framework Integration

Laravel

// config/services.php
'pspline' => [
    'merchant_id' => env('PSPLINE_MERCHANT_ID'),
    'public_key'  => env('PSPLINE_PUBLIC_KEY'),
    'private_key' => env('PSPLINE_PRIVATE_KEY'),
    'base_url'    => env('PSPLINE_BASE_URL'),
],

// AppServiceProvider.php
$this->app->singleton(PspLine::class, function ($app) {
    $cfg = config('services.pspline');
    return new PspLine(
        $cfg['merchant_id'],
        $cfg['public_key'],
        $cfg['private_key'],
        array_filter(['base_url' => $cfg['base_url']])
    );
});

// In your controller
public function createPayment(PspLine $psp)
{
    $invoice = $psp->invoices->create([...]);
    return redirect($invoice->verifyUrl);
}

Symfony

# config/services.yaml
services:
    PspLine\PspLine:
        arguments:
            $merchantId: '%env(int:PSPLINE_MERCHANT_ID)%'
            $publicKey: '%env(PSPLINE_PUBLIC_KEY)%'
            $privateKey: '%env(PSPLINE_PRIVATE_KEY)%'
            $options:
                base_url: '%env(PSPLINE_BASE_URL)%'

Security

If you discover a security vulnerability, please email security@pspline.com instead of creating a public issue.

License

The MIT License (MIT). See LICENSE for details.