pspline / php-sdk
Official PHP SDK for PSP Line Merchant API — crypto invoices, payments, wallets
v1.0.0
2026-02-11 10:55 UTC
Requires
- php: >=7.2
- ext-curl: *
- ext-json: *
- ext-mbstring: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- guzzlehttp/guzzle: ^6.5 || ^7.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^8.5 || ^9.5 || ^10.0 || ^11.0
- psr/log: ^1.0 || ^2.0 || ^3.0
Suggests
- guzzlehttp/guzzle: Use Guzzle as HTTP transport (v6.5+ or v7.0+)
- psr/log: PSR-3 logger interface for SDK logging
README
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.