API documentation
Create a payment, send your customer to the checkout, and get told when it clears. One small REST API over HTTPS, JSON in and JSON out.
Overview
Every request goes to https://pay.gsmeye.com/api/v1/… with your API key in a header. A payment is created on your server, your customer pays on the hosted checkout, and the result reaches you by webhook and by the status endpoint.
Get an API key
Merchant dashboard → API Keys → Create. Turn on at least one gateway too.
Create a payment
POST the amount from your server. You get back a ref and a payment_url.
Redirect and confirm
Send the customer to payment_url. When the webhook arrives, confirm it with the status endpoint.
Authentication
Send your key in the X-API-Key header. Authorization: Bearer <key> is accepted as well. Keys start with gsmeye_; keep them on your server and never in browser code.
X-API-Key: gsmeye_your_api_key
Content-Type: application/json
Accept: application/json401.Create a payment
Creates a payment and returns the checkout link to send your customer to. The body can be JSON or form fields.
Body
| Field | Type | Description |
|---|---|---|
| amountrequired | number | Amount to charge, greater than 0. Example: 25.00. |
| currency | string | Currency code. Defaults to USDT. |
| gateway | string | A gateway code to force one method, or auto to let the customer choose on the checkout. Leave it out and the first active gateway on your plan is used. |
| webhook_url | url | Where to POST the result. See Webhooks. |
| return_url | url | Where the customer is sent back to after paying or canceling. |
| description | string | Shown on the checkout, e.g. Order #1042. |
| customer_name | string | Optional, shown in your dashboard. |
| customer_email | string | Optional, shown in your dashboard. |
| bdt_rate | number | Optional. Taka for one unit of currency. Bangla QR, bKash, Nagad and Rocket quote the customer in taka at this rate. |
Request
curl -X POST https://pay.gsmeye.com/api/v1/payment \
-H "X-API-Key: gsmeye_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"amount": "25.00",
"currency": "USDT",
"gateway": "auto",
"webhook_url": "https://yourapp.com/webhooks/gsmeye",
"return_url": "https://yourapp.com/thanks",
"description": "Order #1042"
}'$ch = curl_init('https://pay.gsmeye.com/api/v1/payment');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: gsmeye_your_api_key',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'amount' => '25.00',
'currency' => 'USDT',
'gateway' => 'auto',
'webhook_url' => 'https://yourapp.com/webhooks/gsmeye',
'return_url' => 'https://yourapp.com/thanks',
'description' => 'Order #1042',
]),
]);
$payment = json_decode(curl_exec($ch), true);
if ($payment['success'] ?? false) {
header('Location: ' . $payment['payment_url']);
exit;
}const res = await fetch('https://pay.gsmeye.com/api/v1/payment', {
method: 'POST',
headers: {
'X-API-Key': process.env.GSMEYE_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: '25.00',
currency: 'USDT',
gateway: 'auto',
webhook_url: 'https://yourapp.com/webhooks/gsmeye',
return_url: 'https://yourapp.com/thanks',
description: 'Order #1042',
}),
});
const payment = await res.json();
if (payment.success) redirect(payment.payment_url);Response
{
"success": true,
"ref": "GX4F1A9C2B7E",
"payment_url": "https://pay.gsmeye.com/pay/GX4F1A9C2B7E",
"amount": "25.00000000",
"currency": "USDT",
"status": "initiated",
"created_at": "2026-10-23 18:40:12"
}Get a payment
The current state of one payment. Use it to confirm a webhook before you deliver anything.
curl https://pay.gsmeye.com/api/v1/payment/GX4F1A9C2B7E \
-H "X-API-Key: gsmeye_your_api_key"{
"success": true,
"ref": "GX4F1A9C2B7E",
"amount": "25.00000000",
"currency": "USDT",
"payment_note": null,
"gateway": "trc20usdt",
"gateway_trx_id": "9f3a2c…c21e",
"status": "completed",
"webhook_status": "success",
"customer_name": "Rahim",
"customer_email": "rahim@example.com",
"payment_url": "https://pay.gsmeye.com/pay/GX4F1A9C2B7E",
"return_url": "https://yourapp.com/thanks",
"created_at": "2026-10-23 18:40:12",
"updated_at": "2026-10-23 18:41:03"
}List payments
Your payments, newest first.
| Query | Type | Description |
|---|---|---|
| status | string | Only this status. |
| page | integer | Page number, from 1. |
| per_page | integer | Results per page, 1–100. Default 20. |
curl "https://pay.gsmeye.com/api/v1/payments?status=completed&per_page=50" \
-H "X-API-Key: gsmeye_your_api_key"{
"success": true,
"data": [
{
"ref": "GX4F1A9C2B7E",
"amount": "25.00000000",
"currency": "USDT",
"status": "completed",
"payment_note": null,
"gateway": "trc20usdt",
"payment_url": "https://pay.gsmeye.com/pay/GX4F1A9C2B7E",
"created_at": "2026-10-23 18:40:12"
}
],
"pagination": { "total": 1, "page": 1, "per_page": 50, "last_page": 1 }
}Cancel a payment
Closes a payment that has not been paid yet, so its checkout stops accepting money. A payment that is already completed, failed or canceled answers 409.
curl -X POST https://pay.gsmeye.com/api/v1/payment/GX4F1A9C2B7E/cancel \
-H "X-API-Key: gsmeye_your_api_key"{
"success": true,
"ref": "GX4F1A9C2B7E",
"status": "canceled"
}Webhooks
When a payment is completed, a POST with a JSON body is sent to the webhook_url you gave when creating it. Answer with any 2xx status within 10 seconds; the result is recorded and shown in your dashboard.
{
"ref": "GX4F1A9C2B7E",
"status": "completed",
"amount": "25.00000000",
"currency": "USDT",
"gateway": "trc20usdt",
"gateway_trx": "9f3a2c…c21e",
"created_at": "2026-10-23 18:40:12"
}ref from it, fetch Get a payment with your API key, and deliver only when that answer says completed with the amount you expect.Handling it
$event = json_decode(file_get_contents('php://input'), true);
$ref = preg_replace('/[^A-Z0-9]/', '', $event['ref'] ?? '');
// Ask the API, not the webhook body, whether it was paid.
$ch = curl_init('https://pay.gsmeye.com/api/v1/payment/' . $ref);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: gsmeye_your_api_key'],
]);
$payment = json_decode(curl_exec($ch), true);
$order = findOrderByPaymentRef($ref); // your own lookup
if (($payment['status'] ?? '') === 'completed'
&& $order && !$order->paid
&& (float) $payment['amount'] === (float) $order->total) {
markOrderPaid($order);
}
http_response_code(200);app.post('/webhooks/gsmeye', express.json(), async (req, res) => {
const ref = String(req.body.ref || '').replace(/[^A-Z0-9]/g, '');
// Ask the API, not the webhook body, whether it was paid.
const r = await fetch('https://pay.gsmeye.com/api/v1/payment/' + ref, {
headers: { 'X-API-Key': process.env.GSMEYE_API_KEY },
});
const payment = await r.json();
const order = await findOrderByPaymentRef(ref);
if (payment.status === 'completed' && order && !order.paid
&& Number(payment.amount) === Number(order.total)) {
await markOrderPaid(order);
}
res.sendStatus(200);
});Laravel
The same two calls with Laravel's HTTP client.
GSMEYE_API_KEY=gsmeye_your_api_key
GSMEYE_BASE_URL=https://pay.gsmeye.com'gsmeye' => [
'key' => env('GSMEYE_API_KEY'),
'url' => env('GSMEYE_BASE_URL'),
],use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class PaymentController extends Controller
{
public function checkout(Order $order)
{
$response = Http::withHeaders(['X-API-Key' => config('services.gsmeye.key')])
->post(config('services.gsmeye.url') . '/api/v1/payment', [
'amount' => $order->total,
'currency' => 'USDT',
'gateway' => 'auto',
'webhook_url' => route('payments.webhook'),
'return_url' => route('orders.show', $order),
'description' => "Order #{$order->id}",
]);
if (! $response->json('success')) {
return back()->withErrors($response->json('message', 'Payment could not be started.'));
}
$order->update(['payment_ref' => $response->json('ref')]);
return redirect()->away($response->json('payment_url'));
}
public function webhook(Request $request)
{
$order = Order::where('payment_ref', $request->input('ref'))->first();
// Ask the API, not the webhook body, whether it was paid.
$payment = Http::withHeaders(['X-API-Key' => config('services.gsmeye.key')])
->get(config('services.gsmeye.url') . '/api/v1/payment/' . $order?->payment_ref)
->json();
if ($order && ! $order->paid
&& ($payment['status'] ?? null) === 'completed'
&& (float) $payment['amount'] === (float) $order->total) {
$order->markPaid();
}
return response()->noContent();
}
}Statuses
| Status | Meaning |
|---|---|
| initiated | Created; the customer has not paid yet. |
| pending | A payment was seen and is waiting to be confirmed. |
| completed | Paid and verified. The only status to deliver on. |
| failed | The payment did not go through. |
| canceled | Closed by you, by the customer, or by the checkout timing out. |
Gateway codes
Values for the gateway field. Only gateways that are on your plan and turned on in your dashboard can be used.
| Code | Gateway | Customer pays in |
|---|---|---|
| auto | Customer chooses on the checkout | — |
| binancec2c | USDT | |
| trc20usdt | USDT | |
| bep20usdt | USDT | |
| banglaqr | Bangla QR | BDT |
| bkashpersonal | bKash Personal | BDT |
| nagadpersonal | BDT | |
| rocketpersonal | Rocket Personal | BDT |
| bkashlive | bKash Checkout | BDT |
Errors
Errors come back as {"success": false, "message": "…"} with one of these status codes.
| Code | When |
|---|---|
| 401 | Missing or invalid API key, inactive account, or expired plan. |
| 403 | The requested gateway is not on your plan. |
| 404 | No payment with that ref on your account, or an unknown endpoint. |
| 409 | The payment can no longer be canceled. |
| 422 | A field is missing or invalid, e.g. amount or webhook_url. |
| 503 | No active gateway is set up for your plan, or the requested one is turned off. |
Bangla QR
bKash Personal
Rocket Personal