paykrypt/paykrypt-php-sdk

Official PHP SDK for the PayKrypt crypto payment gateway API.

Maintainers

Package info

github.com/PayKrypt/paykrypt-php-sdk

Homepage

pkg:composer/paykrypt/paykrypt-php-sdk

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-08-02 13:42 UTC

This package is not auto-updated.

Last update: 2026-08-30 14:24:25 UTC


README

Official PHP SDK for the PayKrypt crypto payment gateway API.

Installation

composer require paykrypt/paykrypt-php-sdk
composer require guzzlehttp/guzzle

The SDK is framework-agnostic and uses PSR-18 HTTP clients. If no PSR-18 client can be auto-discovered, install one such as guzzlehttp/guzzle or symfony/http-client.

Requires PHP 8.1 or newer.

Quick Start

use PayKrypt\PayKryptClient;

$paykrypt = new PayKryptClient([
    'apiKey' => getenv('PAYKRYPT_API_KEY'),
    'baseUrl' => getenv('PAYKRYPT_BASE_URL') ?: 'https://api.paykrypt.io',
]);

$intent = $paykrypt->paymentIntents->create([
    'amount' => '100.00',
    'currency' => 'USD',
    'description' => 'Order #12345',
    'customerEmail' => 'customer@example.com',
    'allowedChains' => ['ethereum', 'tron'],
    'expiresInMinutes' => 60,
]);

// Redirect the customer to:
// https://gate.paykrypt.io/pay/{$intent['id']}

Configuration

$paykrypt = new PayKryptClient([
    'apiKey' => 'pk_12345678_...',
    'baseUrl' => 'https://api.paykrypt.io',
    'timeout' => 30_000,
    'retries' => 3,
    'retryDelayMs' => 250,
]);

All merchant API calls use:

Authorization: Bearer pk_<prefix>_<secret>

The key decides which mode you are in, not baseUrl. A pk_test_<prefix>_<secret> key resolves to your sandbox merchant and a pk_<prefix>_<secret> key resolves to your live one, against the same host. The two cannot cross: a test key authenticating against a live merchant is rejected, and so is the reverse.

baseUrl exists to point the client at a self-hosted or local PayKrypt instance. It is not how you reach test mode.

if (!$paykrypt->isTestMode()) {
    throw new RuntimeException('Refusing to run the integration suite against a live key');
}

See Test mode below.

Idempotency

PayKrypt requires an Idempotency-Key on value-creating POST endpoints. The SDK generates one automatically for:

  • paymentIntents->create()
  • payouts->create()
  • payouts->createWithVerification()
  • refunds->create()
  • refunds->createWithVerification()
  • conversions->convert()

Pass your own stable key when retrying the same app-level action:

$intent = $paykrypt->paymentIntents->create(
    ['amount' => '100.00', 'currency' => 'USD'],
    ['idempotencyKey' => 'order:12345'],
);

Resources

$paykrypt->paymentIntents->retrieve('pi_...');
$paykrypt->paymentIntents->list(['page' => 1, 'limit' => 20]);
$paykrypt->paymentIntents->cancel('pi_...');

$paykrypt->payouts->create([
    'amount' => '95',
    'currency' => 'USDT',
    'destinationAddress' => 'TXYZ...',
    'chainId' => 'tron',
]);
$paykrypt->payouts->stats();

$paykrypt->refunds->create([
    'paymentIntentId' => '00000000-0000-0000-0000-000000000000',
    'amount' => '50.00',
    'reason' => 'Customer requested refund',
]);

$paykrypt->webhooks->register([
    'url' => 'https://example.com/webhooks/paykrypt',
    'events' => ['payment.confirmed.v1'],
]);

// What was actually sent to your endpoints, what they answered, and which attempt it was.
$paykrypt->webhooks->deliveries(['limit' => 20, 'paymentIntentId' => 'pi_...']);

$paykrypt->addressBook->create([
    'label' => 'Treasury wallet',
    'address' => 'TXYZ...',
    'chainId' => 'tron',
]);

$paykrypt->conversions->preview([
    'fromAssetId' => 1,
    'toAssetId' => 2,
    'amount' => 10,
]);

$paykrypt->currencies->list();
$paykrypt->assets->list();
$paykrypt->assets->listByChain('tron');
$paykrypt->pricing->rates(['currency' => 'USD', 'symbols' => ['BTC', 'ETH', 'USDT']]);

Responses are returned as associative arrays to stay compatible with PayKrypt's evolving API response shapes.

Test mode

A pk_test_ key puts every call into your sandbox merchant. Payments there run through the real settlement pipeline, so you get the same status transitions, ledger postings and webhooks, with no blockchain involved and nothing moving on-chain.

Your sandbox key is created with your account and is permanently viewable in the dashboard, so there is no setup step.

$paykrypt = new PayKryptClient(['apiKey' => getenv('PAYKRYPT_TEST_KEY')]);

if (!$paykrypt->isTestMode()) {
    throw new RuntimeException('Refusing to run tests against a live key');
}

$intent = $paykrypt->paymentIntents->create(['amount' => '25.00', 'currency' => 'USD']);

$paykrypt->test->pay($intent['id'], [
    'scenario' => 'confirm',
    'chainId' => 'tron',
    'assetSymbol' => 'USDT',
]);

Scenarios: detect, confirm, underpay, overpay, reject. Call pay() twice with the same txId to simulate a redelivered event and check your handler is idempotent, or twice without one to build up a multi-transaction payment.

$paykrypt->test->expire($intent['id']);

// A sandbox payout waits in `pending` exactly as a real one does. Drive the outcome:
$paykrypt->test->completePayout($payout['id'], ['outcome' => 'confirmed']);
$paykrypt->test->completeRefund($refund['id'], [
    'outcome' => 'rejected',
    'reason' => 'Insufficient hot wallet balance',
]);

Two things to know about these four methods:

  • They are unauthenticated, and the gate is the target rather than the caller. Each resolves the intent, payout or refund and refuses with 403 unless the merchant behind it is in test mode. A 403 therefore means the resource you named belongs to a live business, most often because it was created with a live key. Your key is not sent on these calls.
  • They are limited to 10 requests per minute per calling IP address. The client retries a 429 with backoff and honours Retry-After, but a suite that fans out will still feel it.

Conversions are refused in test mode with an explanatory error rather than faked, because faking hedge accounting would report numbers that do not mean anything.

Full reference: https://docs.paykrypt.io/api/test-mode

Webhook Verification

PayKrypt signs webhook deliveries with X-PayKrypt-Signature and X-PayKrypt-Timestamp. Use the secret returned from webhooks->register(...) as PAYKRYPT_WEBHOOK_SECRET.

use PayKrypt\Webhook;
use PayKrypt\WebhookVerificationException;

$rawBody = file_get_contents('php://input');
$headers = getallheaders() ?: [];

try {
    $event = Webhook::constructEvent(
        $rawBody,
        $headers,
        getenv('PAYKRYPT_WEBHOOK_SECRET')
    );

    if ($event['type'] === 'payment.confirmed.v1') {
        // Fulfill the order.
    }
} catch (WebhookVerificationException $exception) {
    http_response_code(400);
    echo 'Invalid webhook signature';
    return;
}

The signature payload is:

<millisecond_timestamp>.<raw_body>

The SDK also accepts the older documented aliases Paykrypt-Signature and Paykrypt-Timestamp.

Error Handling

use PayKrypt\PayKryptApiException;

try {
    $paykrypt->paymentIntents->retrieve('pi_missing');
} catch (PayKryptApiException $exception) {
    error_log($exception->getStatusCode() . ' ' . $exception->getErrorCode() . ' ' . $exception->getMessage());
}

Development

composer validate --strict
composer install
composer lint
composer analyse
composer test

Publishing To Packagist

  1. Push main to https://github.com/PayKrypt/paykrypt-php-sdk.
  2. Submit the public repository URL to Packagist once under paykrypt/paykrypt-php-sdk.
  3. Enable Packagist auto-updates through the GitHub app, or configure a GitHub webhook manually: payload URL https://packagist.org/api/github?username=PACKAGIST_USERNAME, content type application/json, secret set to your Packagist API token, and push events only.
  4. Tag releases with semantic version tags such as v1.0.0; Composer reads package versions from VCS tags, so do not add a version field to composer.json.
  5. Create a GitHub Release from the tag and verify Packagist indexed the new version.

License

MIT