# MagicPay API v3.0

Complete merchant integration documentation

* Base URL: `https://gamio.site/api/v3`  (every endpoint also works with a .php suffix, e.g. https://gamio.site/api/v3/payin.php)
* Merchant ID (mchId): `YOUR_MERCHANT_ID`
* mchKey = API Key (pay-in), mchSecret = API Secret (pay-out / balance)
* Pay-in fee: 11% · Pay-out fee: 4% + ₹10

## Global rules

* Request method: JSON POST
* Header: Content-Type: application/json (form-encoded bodies are accepted too)
* Every request must include mchId (your Merchant ID) and sign
* Pay-in and Query Pay-in are signed with mchKey (API Key). Pay-out, Query Pay-out and Balance are signed with mchSecret (API Secret)
* Signature: MD5(sorted_params + &key=KEY).toUpperCase()
* Amounts are strings with two decimals, e.g. "500.00". Times are ISO-8601 in IST (UTC+05:30)
* Currency: INR (₹). USDT orders are priced in INR and paid in USDT (TRC20)

## All Endpoints

|  | URL | Signed with |  |
| --- | --- | --- | --- |
| POST | `https://gamio.site/api/v3/payin` | mchKey | Create a deposit order |
| POST | `https://gamio.site/api/v3/check-order-status` | mchKey | Query a deposit order |
| POST | `https://gamio.site/api/v3/payout` | mchSecret | Create a withdrawal |
| POST | `https://gamio.site/api/v3/check-order-status` | mchSecret | Query a withdrawal |
| POST | `https://gamio.site/api/v3/check-gateway-balance` | mchSecret | Check balance |

## Signature

1. Take every request parameter except sign; drop empty values.
2. Sort by parameter name (byte order).
3. Join as name=value with &, append &key=KEY.
4. MD5 the string and upper-case the hex digest.

Test vector:

```
amount=500.00&mchId=123456789&mchOrderNo=ORDER-1001&notifyUrl=https://merchant.example.com/webhook/reddypay&tradeType=INRUPI&key=TEST_KEY_0123456789abcdef
→ 618EB8435DBA875EB138FF5657E8FA6F
```

## Pay-in

`POST https://gamio.site/api/v3/payin`

| Param | Type | Required | Description |
| --- | --- | --- | --- |
| mchId | string | Yes | Your Merchant ID (also accepted as merchant_id) |
| mchOrderNo | string | Yes | Your own unique order number (1–100 chars: letters, digits and _ - . : # /). Repeating it returns the same order (idempotent). Also accepted as merchant_order_no |
| amount | string | Yes | Order amount in INR, 2 decimals, e.g. "500.00". Limits: see Overview |
| tradeType | string | No | INRUPI (default) or usdt. Also accepted as trade_type |
| notifyUrl | string | No | URL that receives our callback. Falls back to the callback URL saved in your panel. Also accepted as callback_url |
| returnUrl | string | No | Where the customer is sent after paying (also return_url) |
| extra | string | No | Free text (max 255 chars) echoed back in queries and callbacks |
| sign | string | Yes | Signature, see the Signature tab |

```json
{
    "code": 200,
    "success": true,
    "message": "Success",
    "data": {
        "orderNo": "RP2610011449406340360",
        "mchOrderNo": "ORDER-1001",
        "amount": "500.00",
        "fee": "55.00",
        "netAmount": "445.00",
        "paidAmount": null,
        "tradeType": "INRUPI",
        "status": "pending",
        "utr": null,
        "pay_url": "https://gamio.site/pay/48568a0be2cab05e6a49",
        "payUrl": "https://gamio.site/pay/48568a0be2cab05e6a49",
        "extra": "",
        "createdAt": "2026-10-01T14:49:40+05:30",
        "expiresAt": "2026-10-01T15:19:40+05:30",
        "paidAt": null
    }
}
```

## Query Pay-in

`POST https://gamio.site/api/v3/check-order-status`

| Param | Type | Required | Description |
| --- | --- | --- | --- |
| mchId | string | Yes | Your Merchant ID (also accepted as merchant_id) |
| mchOrderNo | string | No | Your order number (one of mchOrderNo / orderNo is required) |
| orderNo | string | No | Our order number returned by /payin |
| sign | string | Yes | Signature, see the Signature tab |

```json
{
    "code": 200,
    "success": true,
    "message": "Success",
    "data": {
        "status": "success",
        "paidAmount": "500.00",
        "utr": "627412345678",
        "paidAt": "2026-10-01T14:50:15+05:30",
        "type": "payin",
        "orderNo": "RP2610011449406340360",
        "mchOrderNo": "ORDER-1001",
        "amount": "500.00",
        "fee": "55.00",
        "netAmount": "445.00",
        "tradeType": "INRUPI",
        "pay_url": "https://gamio.site/pay/48568a0be2cab05e6a49",
        "payUrl": "https://gamio.site/pay/48568a0be2cab05e6a49",
        "extra": "",
        "createdAt": "2026-10-01T14:49:40+05:30",
        "expiresAt": "2026-10-01T15:19:40+05:30"
    }
}
```

## Pay-out

`POST https://gamio.site/api/v3/payout`

| Param | Type | Required | Description |
| --- | --- | --- | --- |
| mchId | string | Yes | Your Merchant ID (also accepted as merchant_id) |
| mchOrderNo | string | Yes | Your unique payout number (idempotent, same rules as pay-in) |
| amount | string | Yes | Amount the beneficiary receives, in INR with 2 decimals. Our fee is charged on top |
| payType | string | No | bank, upi or usdt. Detected from the destination fields when omitted |
| bankCode | string | No | Bank name exactly as in the Bank Codes tab (bank payouts) |
| accountName | string | No | Account holder name (bank payouts) |
| accountNumber | string | No | Bank account number, 6–20 digits (bank payouts) |
| ifsc | string | No | IFSC code, e.g. HDFC0001234 (bank payouts) |
| upiId | string | No | UPI ID such as name@bank (UPI payouts) |
| usdtAddress | string | No | TRC20 address starting with T (USDT payouts, needs USDT enabled for your account) |
| sign | string | Yes | Signature, see the Signature tab |

```json
{
    "code": 200,
    "success": true,
    "message": "Success",
    "data": {
        "orderNo": "WD26100112345678",
        "mchOrderNo": "PAYOUT-77",
        "amount": "1000.00",
        "fee": "75.00",
        "totalDebit": "1075.00",
        "status": "pending",
        "payType": "bank",
        "txid": null,
        "createdAt": "2026-10-01T15:01:02+05:30",
        "paidAt": null
    }
}
```

## Balance

`POST https://gamio.site/api/v3/check-gateway-balance`

| Param | Type | Required | Description |
| --- | --- | --- | --- |
| mchId | string | Yes | Your Merchant ID (also accepted as merchant_id) |
| sign | string | Yes | Signature, see the Signature tab |

```json
{
    "code": 200,
    "success": true,
    "message": "Success",
    "data": {
        "balance": "12450.00",
        "available": "12450.00",
        "frozen": "1075.00",
        "total": "13525.00",
        "currency": "INR"
    }
}
```

## Callback

We POST the following to your notifyUrl (JSON or form-encoded, see Basic Information). Verify sign with mchKey, reply with the text success.

| Field | Description |
| --- | --- |
| mchId | Your Merchant ID (alias merchant_id) |
| mchOrderNo | Your order number (alias merchant_order_no) |
| orderNo | Our order number (alias gateway_order_no) |
| amount | Order amount |
| paidAmount | Amount actually paid |
| fee | Our fee |
| netAmount | Credited to your wallet (amount − fee) |
| tradeType | INRUPI \| usdt |
| status | success \| failed |
| utr | Bank reference (UTR), when known |
| payTime | Payment time, ISO-8601 IST |
| extra | The extra value you sent |
| usdtAmount | USDT orders only: exact USDT amount |
| sign | Signature (MD5, uppercase) made with your mchKey |

```json
{
    "mchId": "123456789",
    "merchant_id": "123456789",
    "mchOrderNo": "ORDER-1001",
    "merchant_order_no": "ORDER-1001",
    "orderNo": "RP2610011449406340360",
    "gateway_order_no": "RP2610011449406340360",
    "amount": "500.00",
    "paidAmount": "500.00",
    "fee": "55.00",
    "netAmount": "445.00",
    "tradeType": "INRUPI",
    "status": "success",
    "utr": "627412345678",
    "payTime": "2026-10-01T14:50:15+05:30",
    "extra": "",
    "sign": "2B60E30809FDA5D9D5752EED2DAEB84E"
}
```

Retries: after 1 min, 5 min, 15 min, 1 h and 6 h until your server answers 2xx with the text success.

## Status values

| Status | Meaning |
| --- | --- |
| pending | Waiting for the customer. A payment made after expiry is still credited, and you get the success callback. |
| success | Paid and credited to your wallet (netAmount). Final. |
| failed | The payment failed or was rejected. Final unless the customer pays later. |
| expired | The customer did not pay in time (30 minutes by default). |
| processing | Payouts only: approved, the transfer is being made. |

## Errors

| HTTP | error | Meaning |
| --- | --- | --- |
| 400 | invalid_request | mchId or sign is missing, or the body could not be read |
| 401 | invalid_signature | Unknown merchant ID or wrong signature (the same answer for both, on purpose) |
| 401 | wrong_key_type | Signed with the wrong key: pay-in endpoints need mchKey, payout and balance need mchSecret |
| 403 | account_suspended | The merchant account is suspended |
| 403 | ip_not_allowed | Your server IP is not on the IP allow-list of the account |
| 403 | ip_whitelist_required | Payouts through the API need an IP allow-list |
| 404 | order_not_found | No order with that mchOrderNo / orderNo on your account |
| 405 | use_post | Use POST |
| 409 | duplicate_order | This mchOrderNo was already used with a different amount or trade type |
| 413 | payload_too_large | Body larger than 64 KB |
| 422 | missing_param / invalid_amount / invalid_mch_order_no | A parameter is missing or malformed, see message |
| 422 | amount_range | Amount outside your limits |
| 422 | method_not_allowed | INR or USDT is not enabled for your account |
| 422 | invalid_trade_type / invalid_pay_type / invalid_url | Unsupported value |
| 422 | insufficient_balance / daily_limit / bank_invalid / ifsc_invalid / upi_invalid / address_invalid | Payout rejected, see message (nothing was debited) |
| 429 | rate_limited / too_many_failures | Too many requests or failed signatures. Wait for Retry-After seconds |
| 500 | server_error | Our side failed; retry with the same mchOrderNo (safe, idempotent) |
| 503 | provider_unavailable / maintenance / rate_unavailable | No payment channel (or USDT rate) available, or maintenance. Retry shortly |

## Bank Codes

* State Bank of India (SBI)
* Punjab National Bank (PNB)
* Bank of Baroda
* Canara Bank
* Union Bank of India
* Bank of India
* Indian Bank
* Central Bank of India
* Indian Overseas Bank
* UCO Bank
* Bank of Maharashtra
* Punjab & Sind Bank
* HDFC Bank
* ICICI Bank
* Axis Bank
* Kotak Mahindra Bank
* IndusInd Bank
* Yes Bank
* IDFC FIRST Bank
* Federal Bank
* South Indian Bank
* RBL Bank
* Karur Vysya Bank
* Karnataka Bank
* City Union Bank
* Tamilnad Mercantile Bank
* DCB Bank
* Bandhan Bank
* CSB Bank
* Dhanlaxmi Bank
* Jammu & Kashmir Bank
* AU Small Finance Bank
* Equitas Small Finance Bank
* Ujjivan Small Finance Bank
* ESAF Small Finance Bank
* Suryoday Small Finance Bank
* Jana Small Finance Bank
* North East Small Finance Bank
* Unity Small Finance Bank
* Utkarsh Small Finance Bank
* Airtel Payments Bank
* India Post Payments Bank
* Fino Payments Bank
* Paytm Payments Bank
* NSDL Payments Bank
* Standard Chartered Bank
* HSBC Bank
* Citibank
* Deutsche Bank
* Other / Not Listed

## Legacy API v1 (payment links)

POST /api/v1/create-link.php and GET /api/v1/link-status.php, header X-Api-Key (or field api_key), sign = uppercase MD5 of the sorted params + &key=<API Secret>. Responses: {"ok":true,"data":{…}}.

## Changelog

* **v3.0** — First release of the v3 API: /payin, /check-order-status, /payout, /check-gateway-balance. USDT (TRC20) pay-in and payout. Our hosted checkout URL in every response. Retrying signed callbacks.
* **v1.x** — Legacy payment-link API (/api/v1/create-link.php, /link-status.php) stays available and unchanged; optional currency / trade_type were added.
