Integration guide
This guide walks through a complete checkout integration: create a payment when the customer checks out, send them to pay, and fulfil the order when our signed webhook confirms the payment.
1. Create the payment on your server
When the customer places an order, call POST /payments from your backend. Use your order ID as both the reference and the Idempotency-Key, so a retried request can never create two payments.
curl -X POST https://gatway.hunario.com/api/v1/payments \
-H "Authorization: Bearer $GATEWAY_SECRET_KEY" \
-H "Idempotency-Key: order-1001" \
-H "Content-Type: application/json" \
-d '{
"amount": "49.90",
"currency": "USDT",
"reference": "order-1001",
"description": "Order #1001",
"customer_email": "buyer@example.com",
"success_url": "https://shop.example.com/orders/1001/thanks",
"cancel_url": "https://shop.example.com/cart"
}'Save the returned id (for example pay_01h…) with your order.
2. Send the customer to pay
Redirect the customer to checkout_url. They pay on the provider's hosted page and are then sent back to your success_url or cancel_url.
success_url. Anyone can open that URL. Fulfil only after the webhook in step 4, or after GET /payments/{id} returns completed.3. Set up a webhook endpoint
In Developers → Webhooks, add the URL on your server that should receive events and copy its signing secret. Subscribe to at least payment.completed, payment.failed and payment.expired.
4. Fulfil on payment.completed
Verify the signature, then look up the order by data.reference and fulfil it. See Webhooks for the signature algorithm.
// Pseudocode
event = verifyAndParse(rawBody, headers["X-Gateway-Signature"], WEBHOOK_SECRET)
if event.type == "payment.completed":
order = findOrder(event.data.reference)
if not order.paid: // events can arrive more than once
order.markPaid(event.data.id, event.data.received_amount)
return 2005. Handle other outcomes
payment.expired/payment.failed: release the stock or ask the customer to try again with a new payment.payment.underpaid: the customer sent less than requested. Only the received amount is credited. Decide whether to accept it, request the difference or refund (contact support for refunds).payment.on_hold: the payment is under compliance review by us or the provider. Wait for a final event.
6. Reconcile
If a webhook was missed (for example, your server was down), call GET /payments/{id}. If the payment is still open, POST /payments/{id}/verify asks the provider for the latest status. Keep a periodic job that checks orders stuck in "awaiting payment".
Checklist before going live
- Secret key stored in server configuration, not in code or the browser.
- Every
POSTsends a uniqueIdempotency-Key. - Webhook signatures are verified with a constant-time comparison and a timestamp check.
- Your webhook handler is idempotent and returns
2xxquickly. - Orders are fulfilled only from verified status, never from the redirect.
- Amounts are handled as decimal strings, not floats.