Skip to content

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.

Do not fulfil the order when the customer lands on 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 200

5. 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 POST sends a unique Idempotency-Key.
  • Webhook signatures are verified with a constant-time comparison and a timestamp check.
  • Your webhook handler is idempotent and returns 2xx quickly.
  • Orders are fulfilled only from verified status, never from the redirect.
  • Amounts are handled as decimal strings, not floats.