API v1 · Stable

InPay Developer Documentation

Integrate InPay into your website or app. Accept UPI payments and send bank transfers via IFSC codes. India's professional payment gateway with INR settlement & USDT cash-out options.

Base URL
https://inpay.45.63.23.31.nip.io/api/v1
Currency
INR · India
Pay-in Fee
12% flat
Payout Fee
5% flat

Overview

InPay is a professional India-focused payment gateway built for developers. Every endpoint is RESTful, returns JSON, and uses Bearer token authentication. The platform supports 1 pay-in method (UPI — Unified Payments Interface) and 1 payout method (bank transfer via IFSC code). Settlements are available in USDT (min $2,000, $100 flat fee).

Pay-in Fee

12%

Deducted from gross

Payout Fee

5%

Added on top

Settlement Fee

$100 flat

Min $2,000 USDT

Quick Start

Three steps to your first payment:

  1. 1
  2. 2
    Generate an API key from Dashboard → API Keys → Create. Keys start with ip_live_
  3. 3
    Make your first request using the Bearer token header. Test balance first, then create a UPI pay-in:
test-balance.sh
curl https://inpay.45.63.23.31.nip.io/api/v1/balance \
  -H "Authorization: Bearer ip_live_<your_48_char_hex_key>"

Authentication

All API requests require a Bearer token. Generate keys from the dashboard under API Keys → Create. Each key is a 48-character hex string prefixed with ip_live_, giving 192 bits of entropy.

Keys are bound to your account

An API key can only access the balance & history of its own account. You can never withdraw funds from another user — your balance is checked atomically before every payout.

Authorization header

header
Authorization: Bearer ip_live_a1b2c3d4e5f6...48hex_chars_total

Sample authenticated request

check-balance.sh
curl https://inpay.45.63.23.31.nip.io/api/v1/balance \
  -H "Authorization: Bearer ip_live_<your_48_char_hex_key>"

API Endpoints Reference

Every endpoint is rooted at https://inpay.45.63.23.31.nip.io/api/v1.

MethodPathDescriptionAuth
GET/balanceGet current account balance, totals, currency
GET/methodsList all pay-in & payout methods + fee rates
POST/payinCreate a UPI pay-in — returns payment URL/QR
POST/payoutSend a bank transfer (balance checked atomically)
GET/transactionsList your pay-in & payout history

Deposit (Pay-in) Methods

InPay supports UPI — India's unified payment interface used by 400M+ users across 200+ banks.

Method IDLabelMinMaxFeeTime
upiUPI (Unified Payments Interface)₹500₹1,00,00012%Instant - 1 min

Preset amounts (INR)

UPI accepts the following preset amounts:

5001,0002,0005,00010,00020,00050,0001,00,000

Withdrawal (Payout) Methods

Send bank transfers using IFSC codes — works with any Indian bank (NEFT/IMPS rails). Balance is checked atomically before the transfer — if it fails, the debited amount is refunded instantly.

Method IDLabelMinMaxDestination FormatFee
bank
Bank Transfer (IFSC)
₹500₹1,00,000IFSC + accountNo + accountName
e.g. HDFC0001234 | 12345678901 | John Doe
5%
IFSC code format

IFSC is 11 characters: 4 letters (bank) + 0 + 6 alphanumeric (branch). Example: HDFC0001234. Account number must be 8-18 digits. Account holder name must match bank records.

Balance check is atomic

The server locks your balance in a database transaction before calling the payout provider. If the provider call fails for any reason, the full amount (incl. fee) is refunded automatically — no manual reconciliation needed.

Code Examples

Production-ready snippets in curl, JavaScript, and Python.

1 · Create Pay-in (UPI)

payin.sh
curl -X POST https://inpay.45.63.23.31.nip.io/api/v1/payin \
  -H "Authorization: Bearer ip_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500,
    "method": "upi",
    "payerEmail": "customer@example.com",
    "payerName": "Rahul Verma"
  }'
payin.js
// Create a UPI pay-in (returns payment URL + intent)
const res = await fetch("https://inpay.45.63.23.31.nip.io/api/v1/payin", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ip_live_<your_key>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 500,                       // INR
    method: "upi",                     // only UPI supported
    payerEmail: "customer@example.com",
    payerName: "Rahul Verma",
  }),
});

const data = await res.json();
if (!data.error) {
  console.log("Reference:", data.reference);
  console.log("Payment URL:", data.paymentUrl);
  console.log("QR / Intent:", data.qrCode);
  console.log("Fee:", data.methodFee, "Net:", data.amountNet);
  // Redirect user to data.paymentUrl to complete UPI payment
} else {
  console.error("Error:", data.error);
}
payin.py
import requests

res = requests.post("https://inpay.45.63.23.31.nip.io/api/v1/payin",
    headers={
        "Authorization": "Bearer ip_live_<your_key>",
        "Content-Type": "application/json",
    },
    json={
        "amount": 500,
        "method": "upi",
        "payerEmail": "customer@example.com",
        "payerName": "Rahul Verma",
    },
)
data = res.json()
if "error" not in data:
    print("Reference:", data["reference"])
    print("Payment URL:", data.get("paymentUrl"))
else:
    print("Error:", data.get("error"))

2 · Create Payout (Bank Transfer)

The server checks your balance before the transfer. If you don't have enough, you get a 400 error and nothing is debited.

payout.sh
curl -X POST https://inpay.45.63.23.31.nip.io/api/v1/payout \
  -H "Authorization: Bearer ip_live_<your_key>" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 2000,
    "method": "bank",
    "ifsc": "HDFC0001234",
    "accountNo": "12345678901",
    "accountName": "Rahul Verma"
  }'
payout.js
// Send ₹2,000 to a bank account — balance checked atomically first
const res = await fetch("https://inpay.45.63.23.31.nip.io/api/v1/payout", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ip_live_<your_key>",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    amount: 2000,                    // INR amount to send
    method: "bank",                  // only bank transfer supported
    ifsc: "HDFC0001234",             // 11-char IFSC: 4 bank + 0 + 6 branch
    accountNo: "12345678901",        // 8-18 digit account number
    accountName: "Rahul Verma",      // account holder name
  }),
});

const data = await res.json();
if (!data.error) {
  console.log("Payout reference:", data.reference);
  console.log("Amount:", data.amount);
  console.log("Fee:", data.fee, "Total debited:", data.totalDebited);
  console.log("New balance:", data.newBalance);
  console.log("Status:", data.status);   // processing | completed
} else {
  // Balance is auto-refunded on failure — no manual reconciliation needed
  console.error("Payout failed:", data.error);
}
payout.py
import requests

res = requests.post("https://inpay.45.63.23.31.nip.io/api/v1/payout",
    headers={
        "Authorization": "Bearer ip_live_<your_key>",
        "Content-Type": "application/json",
    },
    json={
        "amount": 2000,
        "method": "bank",
        "ifsc": "HDFC0001234",
        "accountNo": "12345678901",
        "accountName": "Rahul Verma",
    },
)
data = res.json()
if "error" not in data:
    print("Payout sent:", data["reference"])
    print("Fee:", data.get("fee"), "| Total debited:", data.get("totalDebited"))
else:
    print("Failed (balance auto-refunded):", data.get("error"))

3 · Check Balance

balance.sh
curl https://inpay.45.63.23.31.nip.io/api/v1/balance \
  -H "Authorization: Bearer ip_live_<your_key>"
balance.js
const res = await fetch("https://inpay.45.63.23.31.nip.io/api/v1/balance", {
  headers: { "Authorization": "Bearer ip_live_<your_key>" }
});
const data = await res.json();
// { balance: 50000, totalPaidIn: 200000, totalPaidOut: 75000, currency: "INR" }
console.log("Balance:", data.balance, data.currency);
balance.py
import requests
res = requests.get("https://inpay.45.63.23.31.nip.io/api/v1/balance",
    headers={"Authorization": "Bearer ip_live_<your_key>"})
print(res.json())
# {'balance': 50000, 'totalPaidIn': 200000, 'totalPaidOut': 75000, 'currency': 'INR'}

4 · List Methods

methods.sh
curl https://inpay.45.63.23.31.nip.io/api/v1/methods \
  -H "Authorization: Bearer ip_live_<your_key>"
methods.js
const res = await fetch("https://inpay.45.63.23.31.nip.io/api/v1/methods", {
  headers: { "Authorization": "Bearer ip_live_<your_key>" }
});
const data = await res.json();
console.log("Currency:", data.currency);
console.log("Pay-in rate:", data.fees?.payin);
console.log("Payout rate:", data.fees?.payout);
methods.py
import requests
res = requests.get("https://inpay.45.63.23.31.nip.io/api/v1/methods",
    headers={"Authorization": "Bearer ip_live_<your_key>"})
data = res.json()
print("Currency:", data.get("currency"))
print("Fees:", data.get("fees"))

5 · List Transactions

transactions.sh
curl "https://inpay.45.63.23.31.nip.io/api/v1/transactions?type=payin&limit=50" \
  -H "Authorization: Bearer ip_live_<your_key>"
transactions.js
const res = await fetch("https://inpay.45.63.23.31.nip.io/api/v1/transactions?type=payin&limit=50", {
  headers: { "Authorization": "Bearer ip_live_<your_key>" }
});
const data = await res.json();
// { payins: [...], payouts: [...] }  (filtered by ?type=payin|payout)
console.log("Pay-ins:", data.payins?.length || 0);
console.log("Payouts:", data.payouts?.length || 0);
transactions.py
import requests
res = requests.get("https://inpay.45.63.23.31.nip.io/api/v1/transactions?limit=50",
    headers={"Authorization": "Bearer ip_live_<your_key>"})
data = res.json()
print(f"Pay-ins: {len(data.get('payins', []))}, Payouts: {len(data.get('payouts', []))}")

6 · Handle Webhook

webhook.js (Express)
// Express.js webhook handler — verifies payment status from InPay
import express from "express";
const app = express();
app.use(express.json());

app.post("/webhooks/inpay", (req, res) => {
  const event = req.body;
  // Verify status is "completed" (not just "pending")
  if (event.status === "completed" || event.status === "success") {
    const reference = event.reference;       // PIN-XXXX-XXXX
    const amount    = event.amountGross;     // gross INR
    const net       = event.amountNet;       // net after 12% fee
    const method    = event.method;          // upi

    // IDEMPOTENCY: webhooks can be delivered multiple times.
    // Always check if you already processed this reference before
    // crediting the user. Use a unique constraint on 'reference'.
    fulfillOrder(reference, amount, net);
  }
  // Always return 200 quickly so InPay doesn't retry
  res.status(200).json({ received: true });
});

app.listen(3000);
webhook.py (Flask)
# Flask webhook handler — verifies payment status from InPay
from flask import Flask, request, jsonify
app = Flask(__name__)

@app.post("/webhooks/inpay")
def webhook():
    event = request.json
    status = event.get("status")
    if status in ("completed", "success"):
        reference = event["reference"]
        amount    = event["amountGross"]
        net       = event["amountNet"]
        method    = event["method"]

        # IDEMPOTENCY: check if reference already processed
        fulfill_order(reference, amount, net)
    # Always return 200 quickly
    return jsonify({"received": True}), 200

app.run(port=5000)

Webhooks

InPay sends a POST webhook to your configured notify_url when a UPI pay-in is confirmed. Configure your webhook URL via the dashboard or contact support.

Payload shape

webhook-payload.json
{
  "event": "payin.completed",
  "reference": "PIN-LX7K2P-9F3A21",
  "status": "completed",            // also accept "success"
  "amountGross": 500,               // gross INR before fee
  "amountNet": 440,                 // net after 12% fee
  "fee": 60,
  "method": "upi",
  "currency": "INR",
  "mchOrderNo": "MCH...",           // Airpays order number
  "timestamp": "2026-08-24T17:30:58.000Z",
  "signature": "sha256=..."         // HMAC of payload body
}

Verification

  • Only fulfill orders when status === "completed" or "success"
  • Ignore pending & failed events
  • Return HTTP 200 within 5 seconds — otherwise we retry
  • Webhooks may be delivered multiple times — implement idempotency by deduplicating on reference
  • Retries happen at: 1m, 5m, 30m, 2h, 12h, 24h

Security

Atomic balance check

Balance is locked & decremented in a DB transaction before the bank payout call. Failures auto-refund.

Server-side fee calc

12% pay-in & 5% payout fees computed on the server. Clients cannot fake or override them.

192-bit entropy keys

API keys are 48-char hex (192 bits). Brute-forcing is computationally infeasible.

HTTPS-only

All API traffic is TLS 1.3 encrypted. Plain HTTP is rejected at the edge.

Rate limiting

60/min general, 10/min pay-in, 5/min payout. Exceeding returns 429.

IFSC + account validation

IFSC code (11 chars, 4-letter bank + 0 + 6 alphanumeric) & account number (8-18 digits) validated server-side.

Error Codes

All errors return JSON: { "error": "message" }

StatusNameDescription
400BAD_REQUESTMalformed JSON, invalid amount, or unsupported method
401UNAUTHORIZEDMissing or invalid API key (must start with ip_live_)
400INVALID_AMOUNTAmount out of range (₹500 - ₹1,00,000) or wrong method
400INVALID_IFSCIFSC code format wrong (expected HDFC0000001 — 4 letters + 0 + 6 alphanum)
400INVALID_ACCOUNTBank account number invalid (8-18 digits)
400INSUFFICIENT_BALANCENot enough balance for payout (auto-refunded if debited)
403FORBIDDENAPI key disabled or method not enabled for your account
429RATE_LIMITEDToo many requests — 60/min general, 10/min payin, 5/min payout
500INTERNAL_ERRORServer error — balance refunded automatically if mid-payout
503PROVIDER_DOWNAirpays (UPI) / bank payout provider temporarily down

InPay API v1 · India · INR · https://inpay.45.63.23.31.nip.io

Need help? Contact support from your dashboard. API keys never expire — rotate from the dashboard anytime.