Authentication
Send your API key (Gateway dashboard → Integrations) in the X-Payfim-Api-Key header. Always call the API from your server, never from a browser.
Create an invoice
POST https://yourdomain.com/payfim/api.php?action=create_invoice
X-Payfim-Api-Key: pf_live_xxx
order_id=1001&amount=49.99¤cy=USD
&webhook_url=https://yourstore.com/payfim-webhook
&return_url=https://yourstore.com/thank-you
&cancel_url=https://yourstore.com/cart
&customer_email=buyer@example.com&description=Order+1001
Response:
{"status":"success","invoice":{"id":"3f1c...","status":"new","checkout_url":"https://yourdomain.com/payfim/checkout.php?i=3f1c...", ...}}
Redirect your customer to checkout_url. Calling create_invoice again with the same order_id, amount and webhook URL returns the same open invoice (idempotent).
| Field | Required | Notes |
|---|---|---|
| order_id | yes | Your order reference (letters, digits, - _ # . : /) |
| amount | yes | Decimal, e.g. 49.99 |
| currency | no | ISO code, defaults to the gateway currency |
| webhook_url | recommended | Must be a public https URL |
| return_url / cancel_url | no | Where to send the customer afterwards |
| coin | no | Pre-select a coin, e.g. USDT_TRC20 |
| metadata | no | JSON object echoed back in webhooks |
Get an invoice
GET https://yourdomain.com/payfim/api.php?action=get_invoice&id=3f1c...
X-Payfim-Api-Key: pf_live_xxx
Statuses: new, pending, confirming, paid, underpaid, expired, cancelled.
Webhooks
Payfim POSTs JSON to your webhook_url when the status changes, with the header X-Payfim-Signature: t=TIMESTAMP,v1=HEX. Verify it like this:
$raw = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_PAYFIM_SIGNATURE'] ?? ''), $sig);
$ok = isset($sig['t'], $sig['v1'])
&& abs(time() - (int) $sig['t']) < 300
&& hash_equals(hash_hmac('sha256', $sig['t'] . '.' . $raw, 'pf_live_xxx'), $sig['v1']);
if (!$ok) { http_response_code(401); exit; }
$event = json_decode($raw, true);
// Best practice: re-fetch the invoice with get_invoice before fulfilling the order.
if ($event['status'] === 'paid') { /* mark order paid */ }
http_response_code(200);
Respond with HTTP 2xx. Failed deliveries are retried after 1, 5 and 15 minutes, then 1, 3, 6, 12 and 24 hours.
