The SDK is for developers who connect their own PHP application (custom shop, SaaS billing, membership site, Laravel app ...) to the Payfim Gateway. It creates invoices, reads their status and verifies the signed webhooks your gateway sends. The full API reference is in README.md inside the zip; this part shows the four things every integration needs.
Before you start, install your Payfim Gateway and add your wallets (see Install the gateway and Add wallets). Compatibility: PHP 7.4 – 8.4 · Laravel 8+ (optional) · ext-curl, ext-json.
- Install the SDK.
Unzip
payfim-php.zipinto your project, e.g.packages/payfim-php/, and require it through a Composer path repository:"repositories": [{"type": "path", "url": "packages/payfim-php"}], "require": {"payfim/payfim-php": "^3.0"}then run
composer update payfim/payfim-php. No Composer?README.mdshows a four-line autoloader. Put the Gateway URL and API key (gateway admin > Integrations) in environment variables:$payfim = new Payfim\Client(getenv('PAYFIM_URL'), getenv('PAYFIM_API_KEY')); print_r($payfim->ping()); // version, store name, active coinsTip: The API key creates invoices and signs webhooks. Use it only on the server - never in JavaScript or a mobile app.
- Create an invoice and redirect.
When the customer chooses crypto, create an invoice from your own order record and send the customer to the hosted checkout. Store the invoice id on the order.
$invoice = $payfim->createInvoice([ 'order_id' => (string) $order->id, 'amount' => $order->total, // '49.90' 'currency' => $order->currency, // 'USD' 'webhook_url' => 'https://shop.example.com/payfim/webhook', 'return_url' => 'https://shop.example.com/orders/' . $order->id, ]); $order->payfim_invoice_id = $invoice->getId(); header('Location: ' . $invoice->getCheckoutUrl(), true, 303);Calling it again for the same open order returns the same invoice. Errors throw
Payfim\Exception\ApiExceptionorTransportException- show a friendly "temporarily unavailable" message and log the details. - Handle the webhook.
Your
webhook_urlreceives a signed POST on every status change. Verify it on the raw body, re-fetch the invoice, check it is yours, then update the order once:$event = $payfim->constructEvent(file_get_contents('php://input'), $_SERVER['HTTP_X_PAYFIM_SIGNATURE'] ?? ''); $invoice = $payfim->fetchEventInvoice($event); // never trust the payload alone if ($invoice->isPaid() && $order->status !== 'paid' && $invoice->matchesAmount($order->total, $order->currency)) { $order->markPaid($invoice->getTransactionReference()); // tx hash } http_response_code(200);A bad signature throws
SignatureVerificationException(answer 401). Answer 2xx for events you ignore - otherwise the gateway retries for up to 24 hours.examples/plain-php/webhook.phpis a complete handler including underpaid and expired invoices.Tip: Treat underpaid as "needs review", never as paid, and never mark an order paid just because the customer reached your return page.
- Laravel: config, route and events.
The service provider and the
Payfimfacade are auto-discovered. Add to.env:PAYFIM_URL=https://pay.example.com PAYFIM_API_KEY=pf_live_...
Register the webhook route (signature checked by the
VerifyPayfimSignaturemiddleware) and excludepayfim/webhookfrom CSRF protection:Route::payfimWebhook(); // POST /payfim/webhook
Create invoices with
Payfim::createInvoice([...])and listen forPayfim\Laravel\Events\InvoicePaid(alsoInvoiceUnderpaid,InvoiceExpired...). Each event carries$invoice, already re-fetched from the gateway:public function handle(InvoicePaid $e): void { $order = Order::where('payfim_invoice_id', $e->invoice->getId())->first(); if ($order && $order->status !== 'paid') { $order->markPaid($e->invoice->getTransactionReference()); } }Optional:
php artisan vendor:publish --tag=payfim-config. - Run the tests.
php tests/run.phpruns the built-in test suite (no PHPUnit needed). Point it at your own gateway to run the live tests too:PAYFIM_TEST_URL=https://pay.example.com PAYFIM_TEST_KEY=pf_live_... php tests/run.php
Tip: Everything green? Make a small real payment through your integration (Part 3) and watch the order update.
Troubleshooting
- ApiException "Invalid or missing API key" (401)
- Copy the key again from the gateway's Integrations page. After 20 failed attempts in 15 minutes the gateway rate-limits API calls (429).
- ApiException bad_response
- The Gateway URL does not point to the gateway (you got an HTML page). Use the folder that contains
api.php, without a trailing/admin.php. - SignatureVerificationException on every webhook
- Verify the raw body (
php://input/$request->getContent()), not a re-encoded array, and make sure the server clock is correct (tolerance 5 minutes). - Laravel webhook returns 419
- The route is protected by CSRF. Exclude
payfim/webhookinvalidateCsrfTokens(except: ...)or register it inroutes/api.php(the URL then gets the/apiprefix: setPAYFIM_WEBHOOK_PATH=api/payfim/webhookand useRoute::payfimWebhook('payfim/webhook')).
Get the Payfim PHP & Laravel SDK - the download includes an illustrated PDF version of this guide.
