Skip to content

How to Accept Payments via Redirect to Provider's Page

You need to accept payments without handling card data on your side — the user enters card details directly on the provider’s page. You are implementing a Redirect flow: Gateway creates a payment session with the provider and returns a URL for redirection.

Difference from H2H: Card data is not transmitted through Gateway — user enters it directly on the provider’s page. What you’ll need: Provider’s API key and public key, specification of their endpoints (pay, callback, status), test account.


Incoming request contains only user and payment information:

{
"method_name": "pay",
"params": {
"customer": {
"email": "user@example.com",
"first_name": "Ivan",
"last_name": "Ivanov",
"country": "US",
"ip": "192.168.1.1"
}
},
"payment": {
"token": "tok_xxxx",
"gateway_amount": 10000,
"gateway_currency": "USD",
"product": "Premium Plan",
"order_number": "ORD-001"
},
"settings": {
"api_key": "provider_api_token",
"public_key": "provider_public_key",
"sandbox": false
},
"processing_url": "https://merchant.com/processing",
"callback_url": "https://merchant.com/callback"
}

Full request structure is described in Basic Contracts.

Send amount, currency, user data, and return URL (processing_url) to provider. Provider will create a payment page and return a URL for redirection.

{
"result": true,
"status": "pending",
"gateway_token": "session_12345",
"amount": 10000,
"currency": "USD",
"redirect_request": {
"url": "https://provider.com/payment_page",
"type": "get_with_processing",
"params": {}
},
"logs": [...]
}
Type Description
"get_with_processing" GET redirect + show processing page (most commonly used)
"post_iframes" POST to iframe
"get" Simple GET redirect
"post" Auto-submit POST form

More details about redirect_request format — in Basic Contracts (section 3).


2. Implement Callback Handling (POST /callback)

Section titled “2. Implement Callback Handling (POST /callback)”

After payment, provider sends webhook to your Gateway’s POST /callback:

  1. Validate provider’s signature (method depends on provider — JWT, RSA, HMAC)
  2. Normalize status (approved / declined)
  3. Send result to Business, signing with JWT key settings.sign_key

Full callback and JWT instruction — in Callbacks & JWT.


For cases when callback doesn’t arrive, implement a status check endpoint:

{
"method_name": "status",
"payment": {
"token": "tok_xxxx",
"gateway_token": "session_12345"
},
"settings": {
"api_key": "provider_api_token"
}
}

Detailed specification — in Status and Payout.


  1. Create endpoint POST /pay
  2. Extract payment.gateway_amount / 100, payment.token, settings
  3. Create session with provider
  4. Get payment page URL from provider
  5. Return status: "pending" + redirect_request with URL and type
  6. Form logs
  7. Implement POST /callback with signature validation (see Callbacks & JWT)
  8. Implement POST /status for status check (see Status and Payout)

app.post("/pay", async (req, res) => {
const body = req.body;
const amount = body.payment.gateway_amount / 100;
const apiKey = body.settings.api_key;
// 1. Formulate request to provider (without card!)
const providerPayload = {
amount,
currency: body.payment.gateway_currency,
externalPaymentId: body.payment.token,
returnUrl: body.processing_url,
senderName: body.params?.customer?.first_name,
senderCountry: body.params?.customer?.country,
};
// 2. Send request
const providerRes = await fetch("https://api.provider.com/v1/payments", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(providerPayload),
});
const data = await providerRes.json();
// 3. Return redirect_request with payment page URL
res.status(200).json({
result: true,
status: "pending",
gateway_token: data.paymentId,
amount: body.payment.gateway_amount,
currency: body.payment.gateway_currency,
redirect_request: {
url: data.redirectUrl,
type: "get_with_processing",
params: {},
},
logs: [
{
request: { body: providerPayload },
status: providerRes.status,
response: data,
kind: "pay",
duration: 0.5,
},
],
});
});