Merchant API reference

GatePay Merchant REST API

Create hosted payment links, accept configured wallet and gateway methods, and follow every payment state through webhooks or merchant-scoped status verification.

One API, two environments. The request mode and credential prefixes select sandbox or live processing. The merchant ID is always derived from the credentials and must never be sent in the request body.

Authentication

Every request is authenticated with a mode-matching client ID and client secret. Keep both credentials on your server and send JSON explicitly.

Environment-aware API integration
GatePay supports sandbox testing and live production processing through the same endpoints. Always complete payment, redirect, status, and webhook testing in sandbox before switching your server integration to live credentials.
Environment configuration
Sandbox mode

Use for: Development, integration testing, simulated provider outcomes, and webhook verification.

Request mode: sandbox

Credentials: ci_test_... and cs_test_...

Processing: Uses sandbox merchant and payment records. No real provider charge or wallet balance movement occurs.

Live mode

Use for: Production payment links, real gateway processing, and customer wallet payments.

Request mode: live

Credentials: ci_live_... and cs_live_...

Processing: Uses production merchant records and the payment gateways configured by the GatePay administrator.

01Choose the modesandbox uses the sandbox database. Live uses production services.
02Match the credentialsci_test_ / cs_test_ or ci_live_ / cs_live_.
03Send JSON headersUse JSON Accept on every request and JSON Content-Type on POST requests.

Required headers

HeaderValueRequiredDescription
Acceptapplication/jsonYesRequired on POST and GET.
Content-Typeapplication/jsonPOSTRequired for payment creation.
X-Client-Idci_test_...YesMerchant application client ID.
X-Client-Secretcs_test_...YesMerchant application client secret.
Security notice Never expose your Client Secret in client-side code. Store the Client ID and Client Secret securely on your server.

Quick start

A complete integration starts on your server and ends with webhook verification or a status lookup. The hosted checkout handles the customer-facing payment step.

01Generate credentialsCopy sandbox or live credentials from the approved merchant application.
02Create the linkPOST payment information and the allowed payment method names.
03Redirect customerOpen the returned payment_url in the customer browser.
04Process returnRead trx_reference and your original reference from the merchant URL.
05Verify paymentUse the signed success webhook or poll by your merchant reference.
06Handle idempotentlyDeduplicate webhook deliveries and safely handle repeated callbacks.

Merchant setup and credentials

The REST API is available through an Express merchant application. GatePay creates credentials for the merchant mode, while every request remains scoped to the authenticated application and its owning merchant.

Merchant dashboard

One Express merchant, mode-specific credentials

Open Merchant, select the Express merchant, and use App Info / Merchant Credentials to copy the client ID and secret. Credentials are server-side secrets and must never be exposed in browser or mobile application code.

Merchant typeExpress
Required statusApproved
Owner statusActive
Credential sourceApp Info
Register or create an Express merchantFrontend merchant registration creates the Express merchant application and its initial mode-specific credential pair.
Complete approvalThe Express merchant must be Approved, and its owning GatePay user must be Active in both sandbox and live requests.
Copy credentials securelyUse the client ID and client secret from App Info / Merchant Credentials only from your backend server.
Rotate when necessaryCredential regeneration requires verification. After rotation, the previous client ID and secret stop authenticating immediately.

Environment credential matrix

ModeClient IDClient secretData and processing
sandboxci_test_...cs_test_...Merchant application and payment records use the sandbox database. Provider outcomes are simulated and no wallet balance moves.
liveci_live_...cs_live_...Merchant application and payment records use production data and configured live gateway processors.
Credential mode is enforced. The mode in the request body, both credential prefixes, and the database containing the merchant application must agree. Mixed or mode-incompatible credentials are rejected before payment data is stored.

Currency and gateway rules

GatePay administrators control currency, payment-method, and fee availability. The payment_methods array requests full method names, but it cannot enable a gateway that is inactive, unsupported, or not configured for Merchant payment.

Admin-managed availability. The GatePay administrator must activate each supported payment method for Merchant payment. Only activated methods can be requested by an authenticated REST API merchant.

Runtime decision order

01
Validate the currency

The currency code must exist, be Active, and have the Fiat type. Crypto currency records are not accepted as the payment currency.

02
Resolve every requested method

Names are matched case-insensitively against active GatePay payment methods with an implemented REST API processor.

03
Apply Merchant payment activation

The administrator must activate every requested method for Merchant payment for the selected fiat currency.

04
Apply Wallet requirements

Mts follows the Wallet payment flow. Live payments require an eligible payer wallet, while sandbox payments use demo wallet outcomes.

05
Calculate Merchant payment fees

Gateway percentage and fixed charges come from the Payment_Received transaction type shown as Merchant payment, then the merchant group fee and fee-bearer rule are applied.

Configuration matrix

Method or ruleRequired configurationCheckout behavior
Mts, Stripe, Paypal, PayUmoney, CoinPayments, Payeer, Coinbase, Flutterwave, Mtn, CybersourceThe GatePay administrator must activate every requested method for Merchant payment.Mts requires an active logged-in payer with an eligible wallet. MTN is a guest, asynchronous checkout. Cybersource uses Secure Acceptance Hosted Checkout (same as deposit and invoice) and settles only after signature validation with decision=ACCEPT and reason_code=100. PayUmoney sandbox links require INR.
Mtn provider prerequisitesMTN uses the administrator-configured provider mode and the credentials required by that mode; a public HTTPS callback URL and the MTN reconciliation scheduler are also required.The REST payment remains pending after RequestToPay is accepted and becomes final through polling, callback verification, or scheduled reconciliation—even if the customer closes the tab.
Merchant receiver walletNo wallet check is performed when the payment link is created.After a successful live payment, GatePay creates the merchant currency wallet if it does not already exist, then credits it once.
All methods must pass. If one requested payment method is unavailable, GatePay rejects the complete request with HTTP 422 and returns unavailable_payment_methods. It never silently removes a method from the payment link.
POST

Create payment link

Creates a hosted checkout link for an approved merchant, active fiat currency, and payment methods enabled for merchant payment.

https://gatepay.techvill.net/api/v1/payments
Credentials required Sandbox and live Active fiat currency
Payment method selection. Send full method names such as Stripe, Paypal, Mts, Mtn, or Cybersource. External gateways must be active for merchant payment and the selected currency. Cybersource additionally requires active Payment Received fees and limits plus Secure Acceptance Hosted Checkout credentials (profile_id, access_key, secret_key, mode).

Request body

FieldTypeRequiredDescription
modestringYessandbox or live.
amountstringYesPositive decimal with up to eight decimal places.
currencystringYesActive three-letter fiat currency code.
payment_methodsarrayYesOne or more unique payment method names.
referencestringYesYour unique reference, up to 100 characters.
success_urlURLYesReturn URL for success and pending outcomes.
webhook_urlURLYesPublic endpoint for payment lifecycle events.
cancel_urlURLYesReturn URL for failed and cancelled outcomes.
descriptionstringOptionalPayment description, up to 1000 characters.
metadataobjectOptionalUp to 20 scalar key-value pairs.
Merchant ID is prohibited. GatePay derives the merchant from the authenticated application. Live URLs must use HTTPS, and callback_url is not accepted; use success_url.
curl --request POST 'https://gatepay.techvill.net/api/v1/payments' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'X-Client-Id: ci_test_your_client_id' \
  --header 'X-Client-Secret: cs_test_your_client_secret' \
  --data '{
    "mode": "sandbox",
    "amount": "100.00",
    "currency": "USD",
    "payment_methods": ["Stripe"],
    "reference": "ORDER-1001",
    "success_url": "https://merchant.example/payments/success",
    "webhook_url": "https://merchant.example/webhooks/payments",
    "cancel_url": "https://merchant.example/payments/cancel",
    "description": "Payment for order 1001",
    "metadata": {"order_id": "1001"}
  }'
use Illuminate\Support\Facades\Http;

$response = Http::acceptJson()
    ->withHeaders([
        'X-Client-Id' => 'ci_test_your_client_id',
        'X-Client-Secret' => 'cs_test_your_client_secret',
    ])
    ->post('https://gatepay.techvill.net/api/v1/payments', [
        'mode' => 'sandbox',
        'amount' => '100.00',
        'currency' => 'USD',
        'payment_methods' => ['Stripe'],
        'reference' => 'ORDER-1001',
        'success_url' => 'https://merchant.example/payments/success',
        'webhook_url' => 'https://merchant.example/webhooks/payments',
        'cancel_url' => 'https://merchant.example/payments/cancel',
        'description' => 'Payment for order 1001',
        'metadata' => ['order_id' => '1001'],
    ]);

201 Created

{
  "response": {
    "status": {
      "code": 201,
      "message": "Payment link created successfully."
    },
    "records": {
      "code": "payment_link_created",
      "transaction_id": "01KXQBBN9Y1CN3T3NSQHZ15W4V",
      "reference": "ORDER-1001",
      "mode": "sandbox",
      "status": "PENDING",
      "amount": "100.00000000",
      "currency": "USD",
      "payment_methods": ["Stripe"],
      "payment_url": "https://gatepay.techvill.net/pay/8fK2mQ7xN4vR9cT6pL3zWa",
      "expires_at": "2026-07-21T10:30:00+00:00",
      "metadata": {"order_id": "1001"}
    }
  }
}

Idempotency: Repeating the same reference with the identical payload returns the existing link with HTTP 200. Reusing it with changed data returns HTTP 409.

GET

Verify transaction status

Fetches the current public transaction status using the exact merchant reference supplied during link creation. A found transaction always returns HTTP 200.

https://gatepay.techvill.net/api/v1/payments/status?mode=sandbox&reference=ORDER-1001
Credentials required Merchant-scoped lookup No Content-Type required

Query parameters

ParameterRequiredDescription
modeYesMust match the credential prefixes and transaction environment.
referenceYesExact, case-sensitive merchant reference.
curl --get 'https://gatepay.techvill.net/api/v1/payments/status' \
  --data-urlencode 'mode=sandbox' \
  --data-urlencode 'reference=ORDER-1001' \
  --header 'Accept: application/json' \
  --header 'X-Client-Id: ci_test_your_client_id' \
  --header 'X-Client-Secret: cs_test_your_client_secret'
use Illuminate\Support\Facades\Http;

$response = Http::acceptJson()
    ->withHeaders([
        'X-Client-Id' => 'ci_test_your_client_id',
        'X-Client-Secret' => 'cs_test_your_client_secret',
    ])
    ->get('https://gatepay.techvill.net/api/v1/payments/status', [
        'mode' => 'sandbox',
        'reference' => 'ORDER-1001',
    ]);

200 OK

{
  "response": {
    "status": {
      "code": 200,
      "message": "Transaction status retrieved successfully."
    },
    "records": {
      "code": "transaction_status_retrieved",
      "trx_reference": "01KXQBBN9Y1CN3T3NSQHZ15W4V",
      "reference": "ORDER-1001",
      "status": "SUCCESS",
      "mode": "sandbox",
      "amount": "100.00000000",
      "currency": "USD",
      "payment_method": "Stripe"
    }
  }
}

Checkout and merchant returns

Redirect the customer to the returned payment_url. The checkout shows only payment methods saved on that transaction and validates the selected method again before processing.

SUCCESSReturns to success_url.
PENDINGReturns to success_url while processing continues.
FAILEDReturns to cancel_url.
CANCELLEDReturns to cancel_url.
EXPIREDUnstarted link passed its stored expiry.
Return URL data. GatePay preserves existing merchant query parameters and appends only trx_reference and reference. Treat browser returns as informational and use webhooks or status verification for fulfillment.

Webhooks

GatePay posts lifecycle events to the webhook_url stored on the payment link. Sandbox and live use the same contract, with delivery records stored in their originating environment.

Supported events

EventPublic statusBody signature
payment.status.createdPENDINGYes
payment.status.successSUCCESSYes
payment.status.failedFAILEDYes
payment.status.cancelledCANCELLEDYes
payment.status.expiredEXPIREDYes

Delivery headers

HeaderDescription
X-EventLifecycle event name.
X-Delivery-IdUnique ID used to deduplicate at-least-once deliveries.
X-TimestampUnix timestamp used to verify the event signature.
Content-Typeapplication/json

Successful payment event

{
  "id": "evt_01KX...",
  "event": "payment.status.success",
  "created_at": "2026-07-21T10:00:00+00:00",
  "data": {
    "trx_reference": "01KXQBBN9Y1CN3T3NSQHZ15W4V",
    "reference": "ORDER-1001",
    "status": "SUCCESS",
    "mode": "live",
    "amount": "100.00000000",
    "currency": "USD",
    "payment_method": "Stripe",
    "metadata": {"order_id": "1001"}
  },
  "signature": "hex_hmac_sha256"
}
Webhook signatures. Every event contains a signature field. It is HMAC-SHA256 of timestamp + "." + unsigned compact JSON body using the matching client secret. Reject timestamps older than five minutes.

Laravel signature verification

$timestamp = request()->header('X-Timestamp');
abort_unless(is_string($timestamp) && ctype_digit($timestamp), 401);

$now = time();
abort_if((int) $timestamp < $now - 300 || (int) $timestamp > $now + 300, 401);

$rawBody = request()->getContent();
try {
    $event = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
    abort_unless(is_array($event), 401);

    $receivedSignature = $event['signature'] ?? null;
    abort_unless(is_string($receivedSignature), 401);

    unset($event['signature']);

    $unsignedBody = json_encode(
        $event,
        JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
    );
} catch (\JsonException) {
    abort(401);
}

$expectedSignature = hash_hmac(
    'sha256',
    $timestamp.'.'.$unsignedBody,
    config('services.merchant_api.client_secret')
);

abort_unless(hash_equals($expectedSignature, $receivedSignature), 401);

return response()->noContent();

Retry policy: Any 2xx response acknowledges delivery. GatePay retries connection failures, timeouts, 408, 429, and 5xx responses immediately, then after 1 minute, 5 minutes, 15 minutes, and 1 hour. Other 4xx responses and redirects are terminal.

Sandbox testing

Sandbox checkout never calls a real provider or changes a wallet balance. Select an enabled method and use one of the demo values below to produce a deterministic result.

Provider rules. Stripe and Flutterwave accept listed test cards. MTN uses its local phone simulator. Cybersource uses the generic success, failed, pending, and cancelled simulator in API sandbox mode; live-mode links use Secure Acceptance Hosted Checkout like deposit and invoice. PayUmoney sandbox payments require INR. Bank is not supported by the REST API.

Wallet

WLT-1000000001 SUCCESS
WLT-1000000002 FAILED
WLT-1000000003 PENDING
WLT-1000000004 CANCELLED
WLT-1000000005 INSUFFICIENT BALANCE

Stripe

Card Number MM/YY CVC
4242424242424242 08/28 123 SUCCESS
4000000000000002 08/28 123 FAILED
4000000000009995 08/28 123 PENDING
4000000000000069 08/28 123 CANCELLED

PayPal

success@paypal.test SUCCESS
failed@paypal.test FAILED
pending@paypal.test PENDING
cancelled@paypal.test CANCELLED

Flutterwave

Card Number MM/YY CVV
5531886652142950 08/28 123 SUCCESS
5531886652142951 08/28 123 FAILED
5531886652142952 08/28 123 PENDING
5531886652142953 08/28 123 CANCELLED

CoinPayments

BTC SUCCESS
ETH FAILED
USDT PENDING
LTC CANCELLED

PayUmoney

payu-success SUCCESS
payu-failed FAILED
payu-pending PENDING
payu-cancelled CANCELLED

Payeer

P-SBX-100001 SUCCESS
P-SBX-100002 FAILED
P-SBX-100003 PENDING
P-SBX-100004 CANCELLED

Coinbase

cb-success SUCCESS
cb-failed FAILED
cb-pending PENDING
cb-cancelled CANCELLED

MTN

46733123450 FAILED
46733123451 PENDING
46733123452 EXPIRED
46733123453 SUCCESS

Cybersource

success SUCCESS
failed FAILED
pending PENDING
cancelled CANCELLED

Sandbox & Go Live Checklist

Use this checklist before moving from simulated payments to live checkout. The same REST endpoints work in both environments; the request mode and the complete client credential pair must change together.

Sandbox readiness

Validate the complete integration without calling a real provider or moving wallet balances.

  • Send mode=sandbox with matching ci_test_... and cs_test_... credentials.
  • Test successful, failed, pending, cancelled, insufficient-balance, and expired outcomes where supported.
  • Confirm checkout returns, reference-based status polling, webhook signatures, deduplication, and retry handling.
  • Use only documented simulator values; sandbox never calls production gateway processors.

Live readiness

Enable real payment processing only after merchant access and production configuration are complete.

  • Send mode=live with matching ci_live_... and cs_live_... credentials.
  • The Express merchant must be Approved and its owning user must be Active.
  • Use an Active fiat currency and only methods enabled by the administrator for Merchant payment.
  • Configure production gateway credentials and public HTTPS success, webhook, and cancel URLs.
Production launch checks

Required before live traffic

Credentials and modeUse the live client ID and secret together with mode=live. Never mix test and live prefixes.
Merchant accessVerify the Express merchant is Approved and the merchant owner remains Active.
Currency and methodsConfirm each fiat currency is Active and every requested method is enabled for Merchant payment.
Gateway readinessConfigure production credentials and merchant-payment fees for every external gateway offered at checkout.
Wallet flowMts payers need login, an eligible wallet, and enough balance. A missing merchant receiver wallet is created after successful settlement.
Secure merchant URLsUse public HTTPS success, webhook, and cancel URLs, and safely handle the two returned reference parameters.
Webhook receiverVerify every event HMAC with the matching client secret, reject stale timestamps, deduplicate delivery IDs, and return 2xx quickly.
Verification and operationsPoll status by the exact merchant reference, run webhook queue and scheduler or cron processing, and monitor failed delivery attempts.
Switch the complete environment together. Do not change only mode or one credential. Change mode, client ID, and client secret as one set, keep merchant_id out of the request, and complete a low-value live payment before opening general traffic.

Errors and limits

Every JSON response uses the existing GatePay response envelope. The HTTP status represents request handling; transaction outcomes returned from status verification still use HTTP 200.

HTTPMachine code examplesMeaning
401invalid_credentialsMissing or invalid credential pair.
403credential_mode_mismatchCredential mode mismatch or unavailable merchant access.
404transaction_not_foundNo transaction for this app and exact reference.
406not_acceptableAccept header does not allow JSON.
409reference_conflictReference exists with a changed payload.
415unsupported_media_typePOST request body is not JSON.
422validation_errorInvalid payload or unavailable payment configuration.
429rate_limit_exceededConfigured request limit was exceeded.
503sandbox_unavailableRequested sandbox service is unavailable.

Error response format

{
  "response": {
    "status": {
      "code": 422,
      "message": "The request payload is invalid."
    },
    "records": {
      "code": "validation_error",
      "errors": {
        "currency": ["The selected currency is invalid."]
      }
    }
  }
}
Admin-managed policies. The default rate limit is 60 requests per minute. New links use the current 15, 30, 45, or 60 minute expiry preference, while existing links retain their stored expiry.