GatewayHub
Developer Docs

GatewayHub API Documentation

Integrate payments using GatewayHub APIs. This is the public reference for endpoints, payment flow, webhooks, and security best practices.

Overview

  • GatewayHub is a payment orchestration platform that lets you accept payments through multiple rails with a single integration.
  • Dynamic QR is the primary processing rail today. Additional rails may be enabled per merchant.
  • Authenticate merchant API calls with a Bearer token issued from your merchant dashboard. Keep this token server-side only.
  • After you configure a callback URL, final payment status updates are delivered by webhook. Treat that webhook as the source of truth.

Base URL

All production API calls are made against the GatewayHub production host. Prepend this base URL to every endpoint shown below.

https://gatewayhub.io

Marketing site: gatewayhub.io

Payment Flow

Every payment moves through these four steps. Implement them in this exact order.

  1. 1

    Create Payment

    Your backend calls POST /api/payments with the amount, currency, gateway, and your internal reference. Never call this from the browser.

  2. 2

    Display QR or Redirect

    Render qr_data as a QR image, or send the customer to redirect_url if the gateway returned one. Show a countdown using expires_at.

  3. 3

    Wait for Webhook

    After you configure a webhook URL, GatewayHub notifies your server asynchronously whenever the payment status changes (for example pending → paid). This callback is the source of truth — not the browser.

    Do NOT trust any status observed in the browser. The tab can be closed, reloaded, or tampered with. Only the webhook (or a backend status check) is authoritative.
  4. 4

    Verify via API

    Before fulfilling the order, confirm the payment with GET /api/payments/{payment_id}/status from your backend. Use this as a fallback when webhooks are delayed and as a final guard at checkout.

Authentication

Every merchant API call must include your API key as a Bearer token. Your API key is issued privately in your merchant dashboard — never hard-code or share it.

Authorization: Bearer YOUR_API_KEY
Never expose your API key in the frontend. Do not embed it in JavaScript, mobile apps, or public repositories. All merchant API calls must originate from your own backend.

Get Enabled Gateways

Returns the payment options currently enabled for your merchant account. Use it to render only the methods the customer can actually pay with.

Sample Request

GET /api/gateways/enabled HTTP/1.1
Authorization: Bearer YOUR_API_KEY
Accept: application/json

Sample Response

{
"success": true,
"data": {
  "gateways": [
    { "code": "gcash", "name": "Gcash" },
    { "code": "maya",  "name": "Maya"  },
    { "code": "qrph",  "name": "QRPH"  }
  ],
  "count": 3
},
"error": null
}

Create Payment

Creates a new payment and returns the data you need to collect funds (QR or redirect URL).

Sample Request

POST /api/payments HTTP/1.1
Authorization: Bearer YOUR_API_KEY
Accept: application/json
Content-Type: application/json

JSON Payload

{
"amount": 500.00,
"currency": "PHP",
"gateway": "gcash",
"reference": "ORDER-20260228-0001"
}

cURL Example

curl -X POST https://gatewayhub.io/api/payments \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"amount":500.00,"currency":"PHP","gateway":"gcash","reference":"ORDER-20260228-0001"}'

Sample Response

{
"success": true,
"data": {
  "payment_id": "uuid-value",
  "transaction_id": "uuid-value",
  "gateway": "gcash",
  "amount": 500,
  "currency": "PHP",
  "status": "pending",
  "qr_data": "000201...",
  "expires_at": "2026-02-28T12:00:00+08:00",
  "redirect_url": null,
  "checkout_url": null,
  "merchant": {
    "name": "Your business name",
    "logo": "https://...",
    "theme_color": "#1D4ED8"
  }
},
"error": null
}

Response Field Reference

payment_id
Unique identifier for this payment. Store it against your order and use it for every status check or webhook match.
transaction_id
Same value as payment_id for compatibility with clients that expect a transaction identifier.
qr_data
EMVCo-compatible QR payload string. Encode it as a QR code image and display it to the customer. Do not modify the string.
expires_at
ISO-8601 timestamp of when the QR or redirect session expires. After this, the payment cannot be completed.
redirect_url
If the gateway returns a hosted checkout page or wallet deep link, send the customer here. When null, use qr_data.
checkout_url
Same as redirect_url when present; otherwise null.
merchant
Branding for hosted checkout: display name, logo URL, and theme color.
status
Current payment state. On creation this is always pending. Final states arrive via webhook.

Get Payment Status

Fetch the current status of a payment from your backend. Call this before fulfilling an order, or as a fallback when a webhook is delayed.

Sample Request

GET /api/payments/{payment_id}/status HTTP/1.1
Authorization: Bearer YOUR_API_KEY
Accept: application/json

cURL Example

curl -X GET https://gatewayhub.io/api/payments/{payment_id}/status \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"

Webhook Handling

A webhook is a server-to-server notification. When a payment status changes, GatewayHub sends an HTTP POST to your endpoint so you do not need to poll.

Rule of thumb: Always trust the webhook over any frontend polling. The browser can lie; the webhook cannot.

Delivery

Register your HTTPS endpoint and signing secret on the API Credentials page. GatewayHub delivers webhooks with these headers:

POST https://your-server.example.com/your-webhook-endpoint HTTP/1.1
Content-Type: application/json
User-Agent: GatewayHub-Webhooks/1.0
X-Merchant-Timestamp: 1700000000
X-Merchant-Signature: <hex-hmac-sha256>

How It Works

  • GatewayHub sends a POST whenever a payment’s status changes (not only when it becomes paid).
  • Deliveries are asynchronous — usually within seconds, but network delays can happen.
  • Your endpoint must respond with HTTP 200 quickly (under ~5 seconds). Do heavy work in a queue.
  • If your endpoint errors or times out, GatewayHub retries with backoff.
  • Duplicate deliveries are possible. Make your handler idempotent by keying on payment_id and ignoring already-applied updates.

Example Payload

{
"event": "payment.updated",
"timestamp": "2026-02-28T12:00:00+08:00",
"data": {
  "payment_id": "uuid-value",
  "status": "paid",
  "amount": 500,
  "currency": "PHP",
  "gateway": "coins",
  "reference": "ORDER-20260228-0001",
  "provider_reference": "provider-ref-optional",
  "paid_at": "2026-02-28T12:01:42+08:00",
  "created_at": "2026-02-28T12:00:10+08:00",
  "updated_at": "2026-02-28T12:01:42+08:00"
}
}

Signature Verification

Each delivery is signed with the same secret you configure for webhooks so you can verify it came from GatewayHub.

  • Use the raw request body bytes exactly as received (no re-encoding or whitespace changes).
  • Let timestamp be the value of X-Merchant-Timestamp (Unix time as a decimal string).
  • Compute the hex digest hash_hmac('sha256', timestamp + '.' + body, your_secret) — the signing input is the timestamp, a single dot, then the raw JSON body.
  • Compare that digest to X-Merchant-Signature with a constant-time comparison (e.g. hash_equals in PHP). Do not prefix with sha256=.
  • If they do not match, return 401 and do not act on the payload.
  • Optionally reject requests whose timestamp is too far from your server clock to limit replay windows.
Tip: After verifying the signature, re-check the payment with GET /api/payments/{payment_id}/status before releasing goods — this guards against replayed or spoofed payloads.

Security Notes

  • Never expose your API key in the frontend. Do not embed it in JavaScript, mobile apps, or public repositories. All merchant API calls must originate from your backend.
  • Always verify payments from your backend. Before shipping, granting credits, or unlocking a service, confirm the status with GET /api/payments/{payment_id}/status.
  • Do not trust client-side status. A success screen in the browser is not proof of payment. The customer may have closed the tab, faked the redirect, or manipulated local state.
  • Verify webhook signatures on every request. Reject any payload whose HMAC of timestamp + "." + body does not match. Generate a new signing secret on the API Credentials page if you suspect the old one leaked.
  • Use HTTPS everywhere. Your webhook endpoint and your checkout pages must be served over TLS.
  • Keep handlers idempotent. The same webhook may be delivered more than once. Apply the update only if the payment is not already in that state.

Errors

All API errors use a consistent response envelope.

Error Response Structure

{
"success": false,
"data": [],
"error": "Human-readable error message"
}

Common Status Codes

  • 401 — Unauthenticated or invalid API key.
  • 403 — Merchant account is inactive or gateway is not allowed.
  • 404 — Resource not found.
  • 422 — Validation error in request payload.
  • 429 — Rate limit exceeded.