PHP code example of kosovopay / php-sdk

1. Go to this page and download the library: Download kosovopay/php-sdk library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

kosovopay / php-sdk example snippets


use KosovoPay\KosovoPay;

$kp = new KosovoPay('sk_test_…');

$kp = new KosovoPay(
    apiKey:         'sk_live_…',
    baseUrl:        'https://api.kosovo.sh',   // override for a private/staging gateway
    apiVersion:     '2026-06-01',              // pinned via the Kosovopay-Version header
    connectTimeout: 10,                         // seconds to establish the TCP/TLS connection
    requestTimeout: 30,                         // seconds for the full request/response
    maxRetries:     3,                          // total attempts for retryable failures
);

> $kp = new KosovoPay($_ENV['KOSOVOPAY_SECRET_KEY']);
> 

use KosovoPay\KosovoPay;
use KosovoPay\Enums\CurrencyCode;
use KosovoPay\Params\CreatePaymentParams;

$kp = new KosovoPay($_ENV['KOSOVOPAY_SECRET_KEY']);

$payment = $kp->payments->create(new CreatePaymentParams(
    amount:      4990,                  // €49.90 in minor units
    currency:    CurrencyCode::EUR,
    successUrl:  'https://shop.test/thank-you',
    cancelUrl:   'https://shop.test/cart',
    description: 'Order #1024',
    metadata:    ['order_id' => '1024'],
));

header('Location: ' . $payment->hostedUrl);
exit;

$payment = $kp->payments->create($params, idempotencyKey: 'order-1024');
// Re-running this exact call returns the original payment instead of creating a second.

use KosovoPay\Enums\CurrencyCode;
use KosovoPay\Enums\CheckoutMode;
use KosovoPay\Params\CreatePaymentParams;
use KosovoPay\Params\LineItem;

$payment = $kp->payments->create(new CreatePaymentParams(
    amount:            4990,
    currency:          CurrencyCode::EUR,
    successUrl:        'https://shop.test/thank-you',
    mode:              CheckoutMode::Hosted,          // default — can be omitted
    cancelUrl:         'https://shop.test/cart',
    failUrl:           'https://shop.test/payment-failed',
    description:       'Order #1024',
    merchantReference: 'ORDER-1024',
    expiresAt:         time() + 1800,                 // optional: link expires in 30 min
    lineItems: [
        new LineItem(name: 'Wireless mouse', quantity: 1, unitAmountCents: 2990, sku: 'WM-01'),
        new LineItem(name: 'USB-C cable',    quantity: 2, unitAmountCents: 1000),
    ],
    metadata: ['order_id' => '1024', 'customer_tier' => 'gold'],
));

echo $payment->id;          // "pi_…"
echo $payment->hostedUrl;   // redirect the buyer here

use KosovoPay\Enums\BankCode;

$payment = $kp->payments->create(new CreatePaymentParams(
    amount:     4990,
    currency:   CurrencyCode::EUR,
    successUrl: 'https://shop.test/thank-you',
    mode:       CheckoutMode::Direct,
    bankCode:   BankCode::Onefor,
));

header('Location: ' . $payment->redirectUrl);

$payment = $kp->payments->retrieve('pi_1024');

echo $payment->status->value;        // "captured"
echo $payment->amountCaptured;       // 4990
echo $payment->createdAt()->format(DateTimeInterface::ATOM);

use KosovoPay\Enums\PaymentStatus;
use KosovoPay\Params\ListPaymentsParams;

$captured = $kp->payments->all(new ListPaymentsParams(
    status:     PaymentStatus::Captured,
    currency:   CurrencyCode::EUR,
    createdGte: strtotime('-30 days'),
    limit:      100,                     // page size; the iterator still spans all pages
));

foreach ($captured as $payment) {
    printf("%s  %d %s  %s\n", $payment->id, $payment->amount, $payment->currency->value, $payment->status->value);
}

foreach ($kp->payments->timeline('pi_1024') as $event) {
    printf("%s @ %d\n", $event->type, $event->at);
}

$payment = $kp->payments->cancel('pi_1024', reason: 'customer_changed_mind');

assert($payment->status === PaymentStatus::Canceled);

use KosovoPay\Enums\RefundReason;
use KosovoPay\Params\CreateRefundParams;

// Full refund
$refund = $kp->refunds->create(new CreateRefundParams(payment: 'pi_1024'));

// Partial refund with a reason
$refund = $kp->refunds->create(new CreateRefundParams(
    payment: 'pi_1024',
    amount:  1000,                              // €10.00
    reason:  RefundReason::RequestedByCustomer,
), idempotencyKey: 'refund-order-1024-partial-1');

echo $refund->status->value;   // "succeeded" | "pending" | "failed"

$refund = $kp->refunds->retrieve('re_77');

use KosovoPay\Params\ListRefundsParams;

foreach ($kp->refunds->all(new ListRefundsParams(payment: 'pi_1024')) as $refund) {
    echo $refund->id, PHP_EOL;
}

use KosovoPay\Enums\BankCode;

// All banks enabled for your account, as a Collection<Bank>
$banks = $kp->banks->all();

foreach ($banks as $bank) {
    printf(
        "%-10s min %d step %d  partial-refunds: %s\n",
        $bank->code->value,
        $bank->capabilities->minAmount,
        $bank->capabilities->amountStep,
        $bank->capabilities->refunds->partial ? 'yes' : 'no',
    );
}

// A single bank
$onefor = $kp->banks->retrieve(BankCode::Onefor);

$onefor->capabilities->currencies;     // list<CurrencyCode> the bank accepts
$onefor->capabilities->minAmount;      // smallest accepted amount, minor units
$onefor->capabilities->amountStep;     // amount must be a multiple of this
$onefor->capabilities->refunds->supported;
$onefor->capabilities->refunds->partial;

use KosovoPay\Enums\CurrencyCode;

// Supported settlement currencies
foreach ($kp->currencies->all() as $currency) {
    printf("%s (%s) — %d decimals%s\n",
        $currency->code->value, $currency->symbol, $currency->decimals,
        $currency->isDefault ? ' [default]' : '');
}

// A live FX rate
$rate = $kp->rates->retrieve(CurrencyCode::EUR, CurrencyCode::USD);

echo $rate->rate;       // "1.0850" — a decimal string, never a lossy float
echo $rate->syncedAt;   // ISO-8601 timestamp of the last sync
var_dump($rate->stale); // true if the upstream feed is behind

$me = $kp->me();

echo $me->team->name;                   // "Acme Store"
echo $me->mode->value;                  // "test" | "live"
echo $me->keyPrefix;                    // "sk_test_ab" — safe to log
$me->enabledBanks;                      // list<BankCode>
$me->defaultCurrency;                   // ?CurrencyCode

use KosovoPay\Webhook;
use KosovoPay\Enums\WebhookEventType;
use KosovoPay\Exceptions\WebhookSignatureException;

$payload   = file_get_contents('php://input');                 // the RAW body — do not decode first
$signature = $_SERVER['HTTP_KOSOVOPAY_SIGNATURE'] ?? '';
$secret    = $_ENV['KOSOVOPAY_WEBHOOK_SECRET'];                 // whsec_… from the endpoint

try {
    $event = Webhook::constructEvent($payload, $signature, $secret);
} catch (WebhookSignatureException $e) {
    http_response_code(400);
    exit;
}

match ($event->type) {
    WebhookEventType::PaymentCaptured => fulfilOrder($event->asPayment()),
    WebhookEventType::PaymentFailed   => notifyFailure($event->asPayment()),
    WebhookEventType::RefundSucceeded => recordRefund($event->asRefund()),
    default                           => null,   // ignore everything else, stay forward-compatible
};

http_response_code(200);

use Illuminate\Http\Request;
use KosovoPay\Webhook;
use KosovoPay\Exceptions\WebhookSignatureException;

Route::post('/webhooks/kosovopay', function (Request $request) {
    try {
        $event = Webhook::constructEvent(
            payload:         $request->getContent(),
            signatureHeader: $request->header(Webhook::SIGNATURE_HEADER, ''),
            secret:          config('services.kosovopay.webhook_secret'),
        );
    } catch (WebhookSignatureException) {
        abort(400);
    }

    ProcessKosovoPayEvent::dispatch($event->id, $event->type->value);

    return response()->noContent();
});

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use KosovoPay\Webhook;
use KosovoPay\Exceptions\WebhookSignatureException;

#[Route('/webhooks/kosovopay', methods: ['POST'])]
public function handle(Request $request): Response
{
    try {
        $event = Webhook::constructEvent(
            $request->getContent(),
            $request->headers->get(Webhook::SIGNATURE_HEADER, ''),
            $this->webhookSecret,
        );
    } catch (WebhookSignatureException) {
        return new Response('', 400);
    }

    // … handle $event …

    return new Response('', 200);
}

use KosovoPay\Enums\WebhookEventType;
use KosovoPay\Params\CreateWebhookEndpointParams;

// Create — the secret is returned exactly ONCE, on creation. Store it now.
$endpoint = $kp->webhookEndpoints->create(new CreateWebhookEndpointParams(
    url:           'https://shop.test/webhooks/kosovopay',
    enabledEvents: [WebhookEventType::PaymentCaptured, WebhookEventType::RefundSucceeded],
    description:   'Production fulfilment hook',
));

$secret = $endpoint->secret;   // "whsec_…" — persist this; it is never shown again

// List
foreach ($kp->webhookEndpoints->all() as $e) {
    printf("%s → %s [%s]\n", $e->id, $e->url, $e->status);
}

// Rotate the signing secret (returns the new secret once)
$rotated = $kp->webhookEndpoints->rotateSecret('we_1');
$newSecret = $rotated->secret;

// Delete
$deleted = $kp->webhookEndpoints->delete('we_1');
assert($deleted->deleted === true);

use KosovoPay\Money;

// Minor units → display string
Money::format(4990, decimals: 2, symbol: '€');     // "€49.90"
Money::formatCurrency(4990, $currencyDto);          // uses the Currency DTO's symbol + decimals

// Exact FX conversion (uses bcmath when available, rounds half-up to minor units)
$usd = Money::convert(4990, $rate->rate);           // 4990 EUR-cents × "1.0850" → 5414

use KosovoPay\Enums\CurrencyCode;
use KosovoPay\Enums\BankCode;

$check = $kp->validateAmount(125, CurrencyCode::EUR, BankCode::Onefor);

if (! $check->valid) {
    echo $check->code;          // "amount_below_minimum"
    echo $check->message;       // human-readable explanation
    print_r($check->nearestValid); // suggested valid amount(s), when applicable
}

use KosovoPay\Exceptions\KosovoPayException;
use KosovoPay\Exceptions\ValidationException;
use KosovoPay\Exceptions\RateLimitException;
use KosovoPay\Exceptions\AuthenticationException;
use KosovoPay\Exceptions\Payment\AmountBelowMinimumException;

try {
    $payment = $kp->payments->create($params);
} catch (AmountBelowMinimumException $e) {
    // a precise, recoverable payment error
    return back()->withErrors(['amount' => $e->getMessage()]);
} catch (ValidationException $e) {
    // $e->param tells you which field was rejected
    return back()->withErrors([$e->param ?? 'request' => $e->getMessage()]);
} catch (RateLimitException $e) {
    sleep($e->retryAfter ?? 1);
    // … retry …
} catch (AuthenticationException $e) {
    Log::critical('KosovoPay key rejected', ['request_id' => $e->requestId]);
    throw $e;
} catch (KosovoPayException $e) {
    // catch-all — always log the request id for support
    Log::error($e->getMessage(), [
        'code'       => $e->errorCode,
        'type'       => $e->errorType,
        'status'     => $e->statusCode,
        'request_id' => $e->requestId,
        'doc_url'    => $e->docUrl,
    ]);
    throw $e;
}

use KosovoPay\KosovoPay;
use KosovoPay\Requests\Payments\CreatePayment;
use Saloon\Http\Faking\MockClient;
use Saloon\Http\Faking\MockResponse;
use Saloon\Http\Request;

$mock = new MockClient([
    CreatePayment::class => MockResponse::make([
        'object' => 'payment', 'id' => 'pi_test', 'status' => 'pending', 'mode' => 'test',
        'amount' => 4990, 'amount_captured' => 0, 'amount_refunded' => 0, 'currency' => 'EUR',
        'created' => 1749600000, 'refunds' => [],
    ], 201),
]);

$kp = new KosovoPay('sk_test_x');
$kp->connector()->withMockClient($mock);

$payment = $kp->payments->create($params);

$mock->assertSent(fn (Request $r) => $r->headers()->get('Idempotency-Key') !== null);
bash
composer