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
Create Payment
Your backend calls
POST /api/paymentswith the amount, currency, gateway, and your internal reference. Never call this from the browser. -
2
Display QR or Redirect
Render
qr_dataas a QR image, or send the customer toredirect_urlif the gateway returned one. Show a countdown usingexpires_at. -
3
Wait for Webhook
After you configure a webhook URL, GatewayHub notifies your server asynchronously whenever the payment
statuschanges (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
Verify via API
Before fulfilling the order, confirm the payment with
GET /api/payments/{payment_id}/statusfrom 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
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_idfor 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_urlwhen 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.
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
statuschanges (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_idand 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
timestampbe the value ofX-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-Signaturewith a constant-time comparison (e.g.hash_equalsin PHP). Do not prefix withsha256=. - 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.
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 + "." + bodydoes 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.