LINK4PAY Payment Gateway is a fast REST API with Bearer authentication: create a payment, send your customer to the hosted checkout (card · Apple Pay · Google Pay) or pass the card yourself, then capture, refund or void. Saved cards, webhooks and idempotent requests built in.
One lightweight page with Card, Apple Pay and Google Pay. Create a payment, redirect, receive the result.
Every customer-initiated card payment is authenticated — frictionless when the issuer allows, challenge otherwise.
Authorize now and capture later, refund fully or partially, cancel authorizations — one call each.
Cards stored encrypted with AWS KMS, merchant initiated payments, signed webhooks and idempotent requests.
Exchange your apiKey / apiSecret for an access token, create a payment
without paymentMethod and send the customer to the returned checkoutUrl.
The full reference with every field, response and example is below.
# 1. access token (1 hour)
TOKEN=$(curl -s 'https://pgt.link4pay.com/v2/auth/token' \
-H 'Content-Type: application/json' \
-d '{"apiKey": "YOUR_API_KEY", "apiSecret": "YOUR_API_SECRET"}' | jq -r .access_token)
# 2. payment with the hosted checkout (card, Apple Pay, Google Pay)
curl -s 'https://pgt.link4pay.com/v2/payments' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"amount": "12.00",
"currency": "EUR",
"reference": "order-00001",
"description": "Order #00001",
"customer": {"id": "cust-42", "email": "[email protected]"},
"returnUrl": "https://www.google.com/search?q=payment+return",
"webhookUrl": "https://www.google.com/search?q=webhook"
}'
# -> {"reference": "order-00001", "status": "pending", "checkoutUrl": "https://pgt.link4pay.com/checkout/…", ...}
const base = 'https://pgt.link4pay.com';
const { access_token } = await (await fetch(`${base}/v2/auth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: process.env.L4P_KEY, apiSecret: process.env.L4P_SECRET })
})).json();
const payment = await (await fetch(`${base}/v2/payments`, {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: '12.00', currency: 'EUR', reference: 'order-00001',
customer: { id: 'cust-42', email: '[email protected]' },
returnUrl: 'https://www.google.com/search?q=payment+return',
webhookUrl: 'https://www.google.com/search?q=webhook'
})
})).json();
res.redirect(payment.checkoutUrl); // customer pays on the hosted checkout
import os, requests
base = 'https://pgt.link4pay.com'
token = requests.post(f'{base}/v2/auth/token', json={
'apiKey': os.environ['L4P_KEY'], 'apiSecret': os.environ['L4P_SECRET']}, timeout=15).json()['access_token']
payment = requests.post(f'{base}/v2/payments',
json={
'amount': '12.00', 'currency': 'EUR', 'reference': 'order-00001',
'customer': {'id': 'cust-42', 'email': '[email protected]'},
'returnUrl': 'https://www.google.com/search?q=payment+return',
'webhookUrl': 'https://www.google.com/search?q=webhook',
}, timeout=15).json()
print(payment['status'], payment['checkoutUrl']) # pending, https://…/checkout/…
$base = 'https://pgt.link4pay.com';
$http = new \GuzzleHttp\Client(['base_uri' => $base, 'timeout' => 15]);
$token = json_decode($http->post('/v2/auth/token', ['json' => [
'apiKey' => getenv('L4P_KEY'), 'apiSecret' => getenv('L4P_SECRET')]])->getBody(), true)['access_token'];
$payment = json_decode($http->post('/v2/payments', [
'json' => [
'amount' => '12.00', 'currency' => 'EUR', 'reference' => 'order-00001',
'customer' => ['id' => 'cust-42', 'email' => '[email protected]'],
'returnUrl' => 'https://www.google.com/search?q=payment+return',
'webhookUrl' => 'https://www.google.com/search?q=webhook',
]])->getBody(), true);
header('Location: ' . $payment['checkoutUrl']);
base := "https://pgt.link4pay.com"
// 1. access token
creds, _ := json.Marshal(map[string]string{"apiKey": os.Getenv("L4P_KEY"), "apiSecret": os.Getenv("L4P_SECRET")})
resp, err := http.Post(base+"/v2/auth/token", "application/json", bytes.NewReader(creds))
if err != nil { log.Fatal(err) }
var tok struct{ AccessToken string `json:"access_token"` }
json.NewDecoder(resp.Body).Decode(&tok)
resp.Body.Close()
// 2. payment with the hosted checkout
body, _ := json.Marshal(map[string]any{
"amount": "12.00", "currency": "EUR", "reference": "order-00001",
"customer": map[string]string{"id": "cust-42", "email": "[email protected]"},
"returnUrl": "https://www.google.com/search?q=payment+return",
"webhookUrl": "https://www.google.com/search?q=webhook",
})
req, _ := http.NewRequest("POST", base+"/v2/payments", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+tok.AccessToken)
req.Header.Set("Content-Type", "application/json")
resp, err = http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer resp.Body.Close()
var payment struct{ Status, CheckoutUrl string }
json.NewDecoder(resp.Body).Decode(&payment)
http.Redirect(w, r, payment.CheckoutUrl, http.StatusFound) // customer pays on the hosted checkout
require 'net/http'
require 'json'
base = 'https://pgt.link4pay.com'
# 1. access token
res = Net::HTTP.post(URI("#{base}/v2/auth/token"),
{ apiKey: ENV['L4P_KEY'], apiSecret: ENV['L4P_SECRET'] }.to_json,
'Content-Type' => 'application/json')
token = JSON.parse(res.body)['access_token']
# 2. payment with the hosted checkout
res = Net::HTTP.post(URI("#{base}/v2/payments"),
{ amount: '12.00', currency: 'EUR', reference: 'order-00001',
customer: { id: 'cust-42', email: '[email protected]' },
returnUrl: 'https://www.google.com/search?q=payment+return',
webhookUrl: 'https://www.google.com/search?q=webhook' }.to_json,
'Authorization' => "Bearer #{token}", 'Content-Type' => 'application/json',
payment = JSON.parse(res.body)
redirect_to payment['checkoutUrl'] # customer pays on the hosted checkout
4111 1010 1111 1003
Stage test card: any name, any future date, CVV 987 — frictionless success. The full table (success · fail · challenge) is in the Testing section below.
Call the API from your server only — never expose apiSecret or access tokens in a browser or mobile app.