Complete API reference for integrating with payeer
Every merchant account has three credentials in Merchant Settings. Use them on your server — never in browser or mobile client code.
Your merchant account identifier. Send it as the appid parameter when you create orders and query orders.
Your secret signing key. It is not sent as a request parameter. Use it only on your server to:
sign field for /api/createorder (see Signature)notify_url (see Callback Notification)A separate query credential used with your App ID for read-only order lookups via GET /api/order. Pass it as the key query parameter together with appid.
Follow these steps to accept your first payment. Start in the Sandbox Playground with test credentials before using live keys.
All endpoints are relative to your gateway origin (this deployment: https://payeer.online):
POST https://payeer.online/api/createorder — JSON API (recommended for server-side checkout)GET …/api/createorder?… — hosted HTML checkout page (fastest to try; polls status and redirects to return_url)GET …/api/order — query order status| Mode | When to use | What you get |
|---|---|---|
| POST JSON | Production checkout on your site or app backend | JSON with redirectUrl / selectUrl — redirect the payer yourself |
| GET link | Quick test or simple “Pay now” link | HTML payment page (QR, polling, auto-redirect to return_url) |
notify_url on each order. The saved URL is used for paid-order webhooks (see Callback Notification). If both are empty, no webhook is sent.POST /api/createorder (JSON) or open GET /api/createorder (hosted page) with appid, clientip, action=createorder, amount, currency, paymentMethod, and sign. Set clientip to the public IP of the machine making the request (see Authentication).redirectUrl or selectUrl (whichever is present). selectUrl means an extra step (pick a payment method or crypto) before paying; nextAction describes that step. If both are absent, use /payment/{paymentId} on this gateway.success (see Callback Notification).return_url with the {paymentId} placeholder (see
Create Order), for example
https://yoursite.com/success?paymentId={paymentId}.
After payment, the customer is redirected to your page and {paymentId} is replaced with the real order ID.
Read the paymentId query parameter from that URL, then call
Query Order on your server to sync the latest status before showing a success message:
GET /api/order?action=order&appid=YOUR_APPID&key=YOUR_KEY&paymentId=PAYMENT_ID_FROM_URL.
Use the response fields status / status_str to update your local order.
Webhooks remain the authoritative async notification; this pattern is for immediate confirmation when the payer lands on your return page.
Minimal server-side flow after you compute sign (see Signature):
// 1. Create order (run on your server; replace YOUR_* placeholders)
const res = await fetch('https://payeer.online/api/createorder', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ appid, clientip, action: 'createorder', amount: 100, currency: 'CNY',
paymentMethod: 'alipay', clientOrderId: 'ORDER-001', return_url, notify_url, sign, sign_type: 'MD5' })
});
const { data } = await res.json();
// 2. Redirect payer to checkout
const checkoutUrl = data.redirectUrl || data.selectUrl || `/payment/${data.paymentId}`;
// response.redirect(checkoutUrl) — your framework
// 3. Webhook handler (express example)
app.post('/api/notify', express.json(), (req, res) => {
const expected = signStr(req.body, process.env.API_KEY); // same algorithm as #signature
if (expected !== req.body.sign) return res.status(400).send('invalid sign');
// update your order if req.body.status_str === 'paid'
res.status(200).send('success'); // must be the string "success"
});
See API Credentials for your appid. Create-order requests also require clientip — the public IP of the client making the HTTP request (usually your backend server’s egress IP, or the payer’s IP when you proxy from the browser).
clientip must match the request IP. If they differ, /api/createorder returns HTTP 403 with Request IP does not match clientip. Behind a reverse proxy, ensure your server forwards the real client IP and pass that same value in clientip.
All API requests that create or modify data require signature verification to ensure data integrity and prevent tampering.
The signature is calculated using all request parameters (except sign and sign_type) and your API key (stored securely on the server).
sign and sign_typekey=value pairs with &| Parameter | Type | Required | Description |
|---|---|---|---|
sign |
string | Required | MD5 signature of all parameters (calculated using your API key) |
sign_type |
string | Optional | Signature type, currently only MD5 is supported (default: MD5) |
/api/createorder (not a nested JSON object). Empty strings are included; omit only null / undefined fields.
createorder)Given API Key 42ba8e8f-7cbb-4bf9-ba2a-57904f3d9451 and these parameters (before adding sign):
Signing plaintext (sorted key=value, joined with &), then append API Key and MD5:
action=createorder&amount=100&appid=YOUR_APPID&clientOrderId=YOUR_ORDER_ID_123&clientip=127.0.0.1¤cy=CNY&description=Test order¬ify_url=https://example.com/api/notify&paymentMethod=alipay&return_url=https://example.com/payment/success?paymentId={paymentId}42ba8e8f-7cbb-4bf9-ba2a-57904f3d9451
sign = 9bb303e3116d862fbeb23bd8a8a8b07d
sign_type is sent in the request but excluded from the signature. Numeric amount in JSON is signed as sent (e.g. 100, not 100.00).
Calculate sign on your server using the same flat parameters you send in the request:
import hashlib
API_KEY = 'YOUR_API_KEY'
def sign_createorder(params: dict) -> str:
filtered = {
k: v for k, v in params.items()
if k not in ('sign', 'sign_type') and v is not None
}
plain = '&'.join(f'{k}={filtered[k]}' for k in sorted(filtered))
return hashlib.md5((plain + API_KEY).encode('utf-8')).hexdigest().lower()
payload = {
'appid': 'YOUR_APPID',
'clientip': '127.0.0.1',
'action': 'createorder',
'amount': 100,
'currency': 'CNY',
'paymentMethod': 'alipay',
'description': 'Test order',
'clientOrderId': 'YOUR_ORDER_ID_123',
'return_url': 'https://example.com/payment/success?paymentId={paymentId}',
'notify_url': 'https://example.com/api/notify',
}
payload['sign'] = sign_createorder(payload)
payload['sign_type'] = 'MD5'
const crypto = require('crypto');
const API_KEY = 'YOUR_API_KEY';
function signCreateorder(params) {
const filtered = {};
for (const [k, v] of Object.entries(params)) {
if (k === 'sign' || k === 'sign_type') continue;
if (v === null || v === undefined) continue;
filtered[k] = v;
}
const plain = Object.keys(filtered).sort()
.map((k) => `${k}=${filtered[k]}`)
.join('&');
return crypto.createHash('md5').update(plain + API_KEY).digest('hex').toLowerCase();
}
const payload = {
appid: 'YOUR_APPID',
clientip: '127.0.0.1',
action: 'createorder',
amount: 100,
currency: 'CNY',
paymentMethod: 'alipay',
description: 'Test order',
clientOrderId: 'YOUR_ORDER_ID_123',
return_url: 'https://example.com/payment/success?paymentId={paymentId}',
notify_url: 'https://example.com/api/notify',
};
payload.sign = signCreateorder(payload);
payload.sign_type = 'MD5';
<?php
$apiKey = 'YOUR_API_KEY';
function sign_createorder(array $params, string $apiKey): string {
unset($params['sign'], $params['sign_type']);
$params = array_filter($params, fn($v) => $v !== null);
ksort($params);
$plain = implode('&', array_map(
fn($k) => $k . '=' . $params[$k],
array_keys($params)
));
return md5($plain . $apiKey);
}
$payload = [
'appid' => 'YOUR_APPID',
'clientip' => '127.0.0.1',
'action' => 'createorder',
'amount' => 100,
'currency' => 'CNY',
'paymentMethod' => 'alipay',
'description' => 'Test order',
'clientOrderId' => 'YOUR_ORDER_ID_123',
'return_url' => 'https://example.com/payment/success?paymentId={paymentId}',
'notify_url' => 'https://example.com/api/notify',
];
$payload['sign'] = sign_createorder($payload, $apiKey);
$payload['sign_type'] = 'MD5';
Create a payment order. The response includes checkout URLs (redirectUrl / selectUrl) and/or a QR image URL depending on the payment method.
Send a JSON body with Content-Type: application/json. Returns JSON with checkout URLs for your server to redirect the payer.
| Parameter | Type | Required | Description |
|---|---|---|---|
appid |
string | Required | Your application ID |
clientip |
string | Required | Your client IP address |
action |
string | Required | Must be createorder |
amount |
number | Required | Order amount (e.g., 100.00) |
currency |
string | Required | Currency code: CNY, USD, or BDT (use BDT with eps or paystation) |
paymentMethod |
string | Required | Payment method (see Payment Methods section) |
sign |
string | Required | MD5 signature (see Signature section) |
sign_type |
string | Optional | Signature type (default: MD5) |
description |
string | Optional | Order description |
customerName |
string | Optional | Customer name |
customerEmail |
string | Optional | Customer email |
customerPhone |
string | Optional | Customer phone number |
freekassaSystemId |
integer | Optional | When paymentMethod=freekassa: FreeKassa payment system ID (i). Omit to defer: response includes selectUrl and nextAction=freekassa_select for payer to choose method and FX quote. If set, initializes FreeKassa immediately. Confirm later via POST /api/freekassa/confirm. |
allowedPaymentMethods |
string | Optional | When paymentMethod=select: comma-separated gateway codes to show on the payer selection page (e.g. alipay,wxpay,freekassa). Omit to show all methods enabled for the order currency and merchant account. USD orders include balance (logged-in customer account balance) by default; exclude with e.g. allowedPaymentMethods=alipay,wxpay. Included in signature. |
lang |
string | Optional | Locale for the payer selection page UI (e.g. en, zh, es). Default en. When not en, selectUrl uses a locale path prefix (e.g. /zh/payment/{orderId}?step=select). Included in signature when provided. |
return_url |
string | Optional | Return URL after payment completion (will redirect automatically if provided). You can use {paymentId} placeholder in the URL, which will be automatically replaced with the actual payment ID when redirecting. Example: https://example.com/success?paymentId={paymentId} |
notify_url |
string | Optional | Webhook URL for this order. If omitted, the default callback URL from Merchant Settings is used. If both are empty, no webhook is sent for that order. |
clientOrderId |
string | Optional | Client's own order identifier. Saved and returned in responses. When provided, duplicate create requests for the same merchant while the order is still pending or ready return the existing order (idempotent; safe to refresh the GET payment link). After paid, failed, or cancelled, a new order may be created with the same clientOrderId. |
clientip parameter must match the actual request IP address, otherwise the request will be rejected (403 error).{paymentId} placeholder in return_url. The system will automatically replace it with the actual payment ID when redirecting after payment completion.notify_url overrides Settings; otherwise the Settings default is stored on the order. Webhooks are only sent when the saved URL is non-empty.clientOrderId: Repeating POST or refreshing the GET payment URL with the same clientOrderId does not create another order while status is pending or ready.
data)| Field | Description |
|---|---|
paymentId / orderId |
Gateway order identifier (same value). Use for Query Order and return_url placeholder. |
redirectUrl |
URL to send the payer to pay immediately (gateway page, external PSP, or hosted checkout). |
selectUrl |
Present when the payer must choose a method first (paymentMethod=select, deferred FreeKassa/NOWPayments). Often equals redirectUrl in that case. |
nextAction |
Hint when selectUrl is used: e.g. payment_method_select, freekassa_select, nowpayments_select. |
qrImageUrl |
QR code image URL when applicable (may be null for redirect-only methods). |
status / statusString |
Order state — see Order Status. Balance payments may return paid immediately. |
Redirect rule: redirectUrl || selectUrl || /payment/{paymentId}.
sign and sign_type) and your API key. See the Signature section for details.
Create a new payment order and receive an HTML payment page. The page will automatically poll the order status every 4 seconds, timeout after 3 minutes, and automatically redirect to return_url when payment is completed.
Note: All parameters are passed as query parameters (URL parameters). Parameters are the same as POST request above.
| Parameter | Type | Required | Description |
|---|---|---|---|
appid |
string | Required | Your application ID |
clientip |
string | Required | Your client IP address |
action |
string | Required | Must be createorder |
amount |
number | Required | Order amount (e.g., 100.00) |
currency |
string | Required | Currency code: CNY, USD, or BDT (use BDT with eps or paystation) |
paymentMethod |
string | Required | Payment method (see Payment Methods section) |
sign |
string | Required | MD5 signature (see Signature section) |
sign_type |
string | Optional | Signature type (default: MD5) |
description |
string | Optional | Order description |
customerName |
string | Optional | Customer name |
customerEmail |
string | Optional | Customer email |
customerPhone |
string | Optional | Customer phone number |
freekassaSystemId |
integer | Optional | When paymentMethod=freekassa: FreeKassa payment system ID (i). Omit to defer: response includes selectUrl and nextAction=freekassa_select for payer to choose method and FX quote. If set, initializes FreeKassa immediately. Confirm later via POST /api/freekassa/confirm. |
allowedPaymentMethods |
string | Optional | When paymentMethod=select: comma-separated gateway codes to show on the payer selection page (e.g. alipay,wxpay,freekassa). Omit to show all methods enabled for the order currency and merchant account. USD orders include balance (logged-in customer account balance) by default; exclude with e.g. allowedPaymentMethods=alipay,wxpay. Included in signature. |
lang |
string | Optional | Locale for the payer selection page UI (e.g. en, zh, es). Default en. When not en, selectUrl uses a locale path prefix (e.g. /zh/payment/{orderId}?step=select). Included in signature when provided. |
return_url |
string | Optional | Return URL after payment completion (page will automatically redirect after 1 second if payment succeeds). You can use {paymentId} placeholder in the URL, which will be automatically replaced with the actual payment ID when redirecting. Example: https://example.com/success?paymentId={paymentId} |
notify_url |
string | Optional | Webhook URL for this order. If omitted, the default callback URL from Merchant Settings is used. If both are empty, no webhook is sent. |
clientOrderId |
string | Optional | Client's own order identifier. Saved and returned in responses. When provided, duplicate create requests for the same merchant while the order is still pending or ready return the existing order (idempotent; safe to refresh the GET payment link). After paid, failed, or cancelled, a new order may be created with the same clientOrderId. |
GET /api/createorder?appid=YOUR_APPID&clientip=127.0.0.1&action=createorder&amount=100¤cy=CNY&paymentMethod=alipay&description=Test+order&clientOrderId=YOUR_ORDER_ID_123&return_url=https%3A%2F%2Fexample.com%2Fsuccess%3FpaymentId%3D%7BpaymentId%7D¬ify_url=https://example.com/api/notify&sign=CALCULATED_SIGNATURE&sign_type=MD5
clientip parameter must match the actual request IP address, otherwise the request will be rejected (403 error).{paymentId} placeholder in return_url. The system will automatically replace it with the actual payment ID when redirecting after payment completion.notify_url overrides Settings; otherwise the Settings default is stored on the order.clientOrderId: Refreshing this payment URL (or repeating the request) with the same clientOrderId does not create another order while status is pending or ready.Returns an HTML payment page that includes:
return_url when payment is completedreturn_url when payment is completed (after 1 second delay)sign and sign_type) and your API key. See the Signature section for details.
Query single order details or list multiple orders.
Typical use: after the payer returns via return_url with paymentId={paymentId}, call this endpoint with the resolved paymentId to sync order status on your success page (see Quick Integration step 7).
| Parameter | Type | Required | Description |
|---|---|---|---|
appid |
string | Required | Your application ID |
key |
string | Required | Your key (UUID format) |
action |
string | Required | order (single) or orders (list) |
paymentId |
string | Required if action=order | Payment ID to query |
page |
number | Optional | Page number (default: 1, only for action=orders) |
limit |
number | Optional | Items per page (max: 50, default: 10, only for action=orders) |
GET /api/order?action=order&appid=YOUR_APPID&key=YOUR_KEY&paymentId=abc123def456
When an order status changes to paid, the system will automatically send a callback notification to your specified URL.
notify_url when creating an order to override the per-order webhook URLThe system sends a POST request to your callback URL with the following parameters:
| Parameter | Type | Description |
|---|---|---|
paymentId |
string | Unique payment identifier |
amount |
string | Order amount (as string, e.g., "2.2") |
currency |
string | Currency code: CNY, USD, or BDT (use BDT with eps or paystation) |
status |
string | Order status code: "2" (paid) |
status_str |
string | Order status string: "paid" |
paymentMethod |
string | Payment method used: alipay, wxpay, crypto, eps, or paystation |
description |
string | Order description (if provided) |
completedTime |
string | Payment completion time in ISO 8601 format (e.g., "2025-12-01T02:32:05.877Z") |
createdAt |
string | Order creation time in ISO 8601 format (e.g., "2025-12-01T02:31:43.997Z") |
clientOrderId |
string | Client order ID (if provided when creating the order) |
sign |
string | MD5 signature for verifying the callback authenticity |
sign_type |
string | Signature type: MD5 |
You must verify the callback signature to ensure the request is authentic. The signature is calculated using the same algorithm as API requests:
sign and sign_typekey=value pairs with &sign parameterYour callback endpoint must return a specific response to acknowledge successful receipt:
"success" (case-insensitive). The response body must be exactly "success" (e.g., "success", "SUCCESS", or "Success"). Any other response will be considered a failure and trigger retry."success" (case-insensitive) will trigger retry"success"Examples of successful responses:
"success" ✓"SUCCESS" ✓"Success" ✓Examples of failed responses (will trigger retry):
{"code": 1, "message": "success"} ✗ (not the string "success")"ok" ✗ (not "success")"received" ✗ (not "success")The system implements an automatic retry mechanism for failed callbacks:
"success" (case-insensitive)"success" (case-insensitive), no further callbacks will be sent for that order"success" immediately after receiving and validating the callback, then process the order asynchronously if needed"success" (case-insensitive) for successful processingOrders have the following status values:
| Code | String | Description |
|---|---|---|
0 |
pending |
Order created, saved locally |
1 |
ready |
Order sent to payment provider, QR code generated |
2 |
paid |
Payment completed successfully |
3 |
failed |
Payment failed |
4 |
cancelled |
Order cancelled |
Supported payment methods and their currency compatibility:
| Method | Code | Supported Currencies | Description |
|---|---|---|---|
| Alipay | alipay |
CNY, USD | Alipay mobile payment |
| WeChat Pay | wxpay |
CNY, USD | WeChat mobile payment |
| Heleket (Crypto) | heleket |
USD | Redirect to Heleket payment page. Webhook: POST /api/gatewaynotification/heleket/webhook. |
| Credit / Debit Card | eps |
BDT, USD | Supports Credit / Debit Card payment. |
| Credit / Debit Card | paystation |
BDT, USD | PayStation (Bangladesh): card and local methods via PayStation checkout. USD orders are charged in BDT at the configured USD→BDT rate. |
| FreeKassa | freekassa |
RUB, USD, EUR, UAH, KZT | Two-step flow: createorder without freekassaSystemId returns selectUrl; payer picks method on gateway page (FX quote if needed), then POST /api/freekassa/confirm. List IDs: /api/freekassa/currencies. Notify: /api/gatewaynotification/freekassa/notify (respond YES). |
| NOWPayments (Crypto) | nowpayments |
USD, EUR, GBP, BRL, NZD | Two-step flow: createorder returns selectUrl; payer chooses crypto on gateway page (min-amount check via NOWPayments API), then confirm creates invoice with pay_currency. IPN: POST /api/gatewaynotification/nowpayments/ipn with x-nowpayments-sig verification. |
| Balance | balance |
CNY, USD | Pay from merchant account balance. Instant settlement; no redirect or QR code. Response includes paidWithBalance: true and status=2 (paid). |
| Payer choice (multi-gateway) | select |
CNY, USD, BDT, EUR, GBP, BRL, NZD | Deferred flow: createorder with paymentMethod=select returns selectUrl and nextAction=payment_method_select. Optional lang (default en) sets the payer selection page locale and URL prefix (e.g. /zh/payment/{orderId}?step=select). Payer sees order amount and each method's min/max limits, then POST ?step=confirm with paymentMethod. USD orders also offer balance: payer must log in at /merchant/login; funds are deducted from the payer's platform balance and credited to the merchant. Optional allowedPaymentMethods restricts the list. FreeKassa / NOWPayments still use their secondary selection pages after confirm. |
alipay, wxpay, and balancealipay, wxpay, eps, paystation, freekassa, heleket, nowpayments, and balanceeps and paystationfreekassa onlyfreekassa and nowpaymentsnowpayments onlyCommon error codes and their meanings:
| Code | Description |
|---|---|
| 400 | Bad Request - Invalid parameters or business logic error |
| 401 | Unauthorized - Invalid appid or apikey |
| 403 | Forbidden — clientip does not match the request IP, or the merchant account is disabled |
| 429 | Too Many Requests - Rate limit exceeded |
| 500 | Internal Server Error - Server-side error |