API documentation

Take payments on your website with one API call and a redirect. Most integrations take about five minutes.

Get an API key

Overview#

Your server creates a payment, the customer pays on a hosted checkout page, and PayerFox tells your server when the money has arrived. You never handle card numbers, UPI or crypto wallets yourself.

  1. Step 1

    Your server

    POST /payments

  2. Step 2

    PayerFox API

    returns checkout_url

  3. Step 3

    Hosted checkout

    customer pays

  4. Step 4

    Your server

    gets payment.paid

Base URL
https://api.payerfox.com/api/v1
Authentication
Authorization: Bearer <API key>
Format
JSON in, JSON out. Every response has success plus data or code + message.
Webhook event
payment.paid

Authentication#

Every request (except checkout status) needs an API key in the Authorization header.

  • Create keys in Dashboard → API keys. Each key belongs to one website, so payments are filed under the right site automatically. There's no account ID to send.
  • pd_test_… keys are for testing, pd_live_… for real customers.
  • API keys can create and read payments. Refunds and settings stay in the dashboard.
Header
Authorization: Bearer pd_test_YOUR_API_KEY
Keep keys on your server. Anyone with a key can create payments for your site. If one leaks, revoke it in API keys.

Quick start#

Accept your first payment in about five minutes. Copy each block as you go.

  1. 1

    Get a test API key

    Create a test key and keep it in an environment variable on your server.

    Create API keyPAYERFOX_API_KEY=pd_test_…
  2. 2

    Create a payment from your server

    Only amount and currency are required. The example sends every field the API accepts — delete the ones you don't need.

    curl -X POST "https://api.payerfox.com/api/v1/payments" \
      -H "Authorization: Bearer pd_test_YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: ORDER-1001" \
      -d '{
      "amount": "499.00",
      "currency": "INR",
      "merchantOrderId": "ORDER-1001",
      "description": "Pro plan — 1 month",
      "orderItems": [
        {
          "name": "Pro plan — 1 month",
          "quantity": 1,
          "unitPrice": "499.00",
          "sku": "PRO-1M"
        }
      ],
      "customerName": "Asha Verma",
      "customerEmail": "asha@example.com",
      "customerPhone": "+919800000000",
      "successUrl": "https://yourstore.com/success",
      "cancelUrl": "https://yourstore.com/cancel",
      "ipnUrl": "https://yourstore.com/webhooks/payerfox",
      "tags": [
        "subscription"
      ],
      "meta": {
        "userId": "u_8812",
        "plan": "pro"
      }
    }'

    All accepted fields

    Details and limits →
    Required

    amountstringAmount as a decimal string, in the currency’s normal decimals.

    currencystringISO currency code (max 10), e.g. INR, USD, USDT.

    Order

    merchantOrderIdstringYour order ID (max 255). Returned as merchant_order_id in responses and webhooks so you can match the order.

    descriptionstringShown to the customer on checkout and in your dashboard.

    orderItemsarrayUp to 100 line items. Each: name (required, max 255), quantity (default 1), unitPrice, sku (max 80), currency. Shown on the payment and sent in webhooks as order_items.

    Customer

    customerNamestringCustomer name (max 200).

    customerEmailstringCustomer email (max 200). Searchable in the dashboard.

    customerPhonestringCustomer phone (max 40).

    Checkout

    successUrlurlWhere the customer returns after paying.

    cancelUrlurlWhere the customer returns if they cancel.

    ipnUrlurlWebhook URL for this payment only. PayerFox POSTs payment.paid here.

    gatewaystringPayment method code (e.g. paytm_upi_qr, binance_c2c, razorpay). Must be enabled for your website. Omit to let the customer choose on checkout.

    Extras

    tagsstring[]Labels on the payment. Use them to filter payments (GET /payments?tag=…) and to route the payment to the connected account that has the same tag.

    metaobjectAny extra JSON you want back, e.g. your user ID or plan. Returned as meta in responses and webhooks. Keys customer, customerName/Email/Phone and orderItems/items are read as the fields above instead.

  3. 3

    Send the customer to checkout_url

    The response contains data.checkout_url. Redirect the customer there. PayerFox shows your enabled payment methods, takes the payment, then sends the customer to your successUrl.

    Your frontend
    // after your server returns { checkoutUrl }
    window.location.href = checkoutUrl;
  4. 4

    Mark the order paid when the webhook arrives

    Pass ipnUrl (or add an endpoint in Settings → Webhooks). PayerFox POSTs this when the payment is paid. Fulfil the order using data.merchant_order_id.

    POST to your ipnUrl
    {
      "event": "payment.paid",
      "data": {
        "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
        "merchant_order_id": "ORDER-1001",
        "amount": "499.00",
        "currency": "INR",
        "status": "paid",
        "transaction_id": "T2610071042558"
      }
    }
    Full payload and signature check →
  5. 5

    Test it

    Try requests live in the playground below, or download the demo page and open it locally.

    Open playground

API endpoints#

Everything your server needs. All paths are relative to the base URL.

Create a payment

POSThttps://api.payerfox.com/api/v1/payments

Creates a payment and returns a hosted checkout_url. Send the customer there to pay.

Headers

  • AuthorizationstringRequired

    Bearer followed by your API key.

    e.g. Bearer pd_test_…

  • Content-TypestringRequired

    Always application/json for request bodies.

    e.g. application/json

  • Idempotency-KeystringOptional

    Recommended. Retrying with the same key returns the original payment instead of creating a second one. Use your order ID.

    e.g. ORDER-1001

Body — 14 fields

  • amountstringRequired

    Amount as a decimal string, in the currency’s normal decimals.

    e.g. "499.00"

  • currencystringRequired

    ISO currency code (max 10), e.g. INR, USD, USDT.

    e.g. "INR"

  • merchantOrderIdstringOptional

    Your order ID (max 255). Returned as merchant_order_id in responses and webhooks so you can match the order.

    e.g. "ORDER-1001"

  • descriptionstringOptional

    Shown to the customer on checkout and in your dashboard.

    e.g. "Pro plan — 1 month"

  • orderItemsarrayOptional

    Up to 100 line items. Each: name (required, max 255), quantity (default 1), unitPrice, sku (max 80), currency. Shown on the payment and sent in webhooks as order_items.

    e.g. [{ "name": "Pro plan", "quantity": 1, "unitPrice": "499.00", "sku": "PRO-1M" }]

  • customerNamestringOptional

    Customer name (max 200).

    e.g. "Asha Verma"

  • customerEmailstringOptional

    Customer email (max 200). Searchable in the dashboard.

    e.g. "asha@example.com"

  • customerPhonestringOptional

    Customer phone (max 40).

    e.g. "+919800000000"

  • successUrlurlOptional

    Where the customer returns after paying.

    e.g. "https://yourstore.com/success"

  • cancelUrlurlOptional

    Where the customer returns if they cancel.

    e.g. "https://yourstore.com/cancel"

  • ipnUrlurlOptional

    Webhook URL for this payment only. PayerFox POSTs payment.paid here.

    e.g. "https://yourstore.com/webhooks/payerfox"

  • gatewaystringOptional

    Payment method code (e.g. paytm_upi_qr, binance_c2c, razorpay). Must be enabled for your website. Omit to let the customer choose on checkout.

    e.g. "paytm_upi_qr"

  • tagsstring[]Optional

    Labels on the payment. Use them to filter payments (GET /payments?tag=…) and to route the payment to the connected account that has the same tag.

    e.g. ["subscription", "vip"]

  • metaobjectOptional

    Any extra JSON you want back, e.g. your user ID or plan. Returned as meta in responses and webhooks. Keys customer, customerName/Email/Phone and orderItems/items are read as the fields above instead.

    e.g. { "userId": "u_8812", "plan": "pro" }

Full request body example →

Request

curl -X POST "https://api.payerfox.com/api/v1/payments" \
  -H "Authorization: Bearer pd_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ORDER-1001" \
  -d '{
  "amount": "499.00",
  "currency": "INR",
  "merchantOrderId": "ORDER-1001",
  "description": "Pro plan — 1 month",
  "orderItems": [
    {
      "name": "Pro plan — 1 month",
      "quantity": 1,
      "unitPrice": "499.00",
      "sku": "PRO-1M"
    }
  ],
  "customerName": "Asha Verma",
  "customerEmail": "asha@example.com",
  "customerPhone": "+919800000000",
  "successUrl": "https://yourstore.com/success",
  "cancelUrl": "https://yourstore.com/cancel",
  "ipnUrl": "https://yourstore.com/webhooks/payerfox",
  "tags": [
    "subscription"
  ],
  "meta": {
    "userId": "u_8812",
    "plan": "pro"
  }
}'

Response

{
  "success": true,
  "data": {
    "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
    "number": 1042,
    "merchant_order_id": "ORDER-1001",
    "external_order_id": null,
    "gateway": null,
    "website_id": "3d6f0a12-8c4b-4e1a-9b77-51c2d0e4f9aa",
    "amount": "499.00",
    "currency": "INR",
    "order_amount": "499.00",
    "order_currency": "INR",
    "charge_amount": null,
    "charge_currency": null,
    "status": "pending",
    "description": "Pro plan — 1 month",
    "tags": [
      "subscription"
    ],
    "source": "website",
    "checkout_url": "https://pay.example.com/checkout/q3k9x2m7ab",
    "transaction_id": null,
    "paid_at": null,
    "expires_at": "2026-10-07T10:30:00.000Z",
    "created_at": "2026-10-07T10:00:00.000Z",
    "customer_name": "Asha Verma",
    "customer_email": "asha@example.com",
    "customer_phone": "+919800000000",
    "order_items": [
      {
        "name": "Pro plan — 1 month",
        "quantity": 1,
        "unit_price": "499.00",
        "sku": "PRO-1M",
        "currency": null
      }
    ],
    "meta": {
      "userId": "u_8812",
      "plan": "pro"
    }
  }
}

Retrieve a payment

GEThttps://api.payerfox.com/api/v1/payments/{id}

Returns one payment with its current status. Use it to double-check a webhook before fulfilling an order.

Headers

  • AuthorizationstringRequired

    Bearer followed by your API key.

    e.g. Bearer pd_test_…

Path parameters

  • iduuidRequired

    The payment id returned when you created it.

    e.g. 7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f

Request

curl -X GET "https://api.payerfox.com/api/v1/payments/7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f" \
  -H "Authorization: Bearer pd_test_YOUR_API_KEY"

Response

{
  "success": true,
  "data": {
    "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
    "number": 1042,
    "merchant_order_id": "ORDER-1001",
    "external_order_id": null,
    "gateway": null,
    "website_id": "3d6f0a12-8c4b-4e1a-9b77-51c2d0e4f9aa",
    "amount": "499.00",
    "currency": "INR",
    "order_amount": "499.00",
    "order_currency": "INR",
    "charge_amount": null,
    "charge_currency": null,
    "status": "paid",
    "description": "Pro plan — 1 month",
    "tags": [
      "subscription"
    ],
    "source": "website",
    "checkout_url": "https://pay.example.com/checkout/q3k9x2m7ab",
    "transaction_id": "T2610071042558",
    "paid_at": "2026-10-07T10:04:12.000Z",
    "expires_at": "2026-10-07T10:30:00.000Z",
    "created_at": "2026-10-07T10:00:00.000Z",
    "customer_name": "Asha Verma",
    "customer_email": "asha@example.com",
    "customer_phone": "+919800000000",
    "order_items": [
      {
        "name": "Pro plan — 1 month",
        "quantity": 1,
        "unit_price": "499.00",
        "sku": "PRO-1M",
        "currency": null
      }
    ],
    "meta": {
      "userId": "u_8812",
      "plan": "pro"
    }
  }
}

List payments

GEThttps://api.payerfox.com/api/v1/payments

Paginated list, newest first, with optional filters.

Headers

  • AuthorizationstringRequired

    Bearer followed by your API key.

    e.g. Bearer pd_test_…

Query parameters

  • statusstringOptional

    created, pending, paid, failed, expired, cancelled or refunded.

    e.g. paid

  • qstringOptional

    Search by order ID, payment number, email or transaction ID.

    e.g. ORDER-1001

  • gatewaystringOptional

    Payment method code.

    e.g. paytm_upi_qr

  • currencystringOptional

    Currency code.

    e.g. INR

  • tagstringOptional

    Only payments with this tag.

    e.g. subscription

  • fromdateOptional

    Created on or after (YYYY-MM-DD).

    e.g. 2026-10-01

  • todateOptional

    Created on or before (YYYY-MM-DD).

    e.g. 2026-10-07

  • pagenumberOptional

    Page number, default 1.

    e.g. 1

  • perPagenumberOptional

    Items per page, default 20.

    e.g. 20

Request

curl -X GET "https://api.payerfox.com/api/v1/payments?status=paid&perPage=20" \
  -H "Authorization: Bearer pd_test_YOUR_API_KEY"

Response

{
  "success": true,
  "data": {
    "items": [
      {
        "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
        "number": 1042,
        "merchant_order_id": "ORDER-1001",
        "external_order_id": null,
        "gateway": null,
        "website_id": "3d6f0a12-8c4b-4e1a-9b77-51c2d0e4f9aa",
        "amount": "499.00",
        "currency": "INR",
        "order_amount": "499.00",
        "order_currency": "INR",
        "charge_amount": null,
        "charge_currency": null,
        "status": "paid",
        "description": "Pro plan — 1 month",
        "tags": [
          "subscription"
        ],
        "source": "website",
        "checkout_url": "https://pay.example.com/checkout/q3k9x2m7ab",
        "transaction_id": "T2610071042558",
        "paid_at": "2026-10-07T10:04:12.000Z",
        "expires_at": "2026-10-07T10:30:00.000Z",
        "created_at": "2026-10-07T10:00:00.000Z",
        "customer_name": "Asha Verma",
        "customer_email": "asha@example.com",
        "customer_phone": "+919800000000",
        "order_items": [
          {
            "name": "Pro plan — 1 month",
            "quantity": 1,
            "unit_price": "499.00",
            "sku": "PRO-1M",
            "currency": null
          }
        ],
        "meta": {
          "userId": "u_8812",
          "plan": "pro"
        }
      }
    ],
    "total": 1,
    "page": 1,
    "perPage": 20,
    "totalPages": 1
  }
}

Check checkout status

Public — no API key
GEThttps://api.payerfox.com/api/v1/checkout/{token}/status

Public, no API key. The token is the last part of checkout_url. Safe to poll from your frontend while the customer pays.

Path parameters

  • tokenstringRequired

    Last path segment of checkout_url.

    e.g. q3k9x2m7ab

Request

curl -X GET "https://api.payerfox.com/api/v1/checkout/q3k9x2m7ab/status"

Response

{
  "success": true,
  "data": {
    "status": "paid",
    "success_url": "https://yourstore.com/success",
    "transaction_id": "T2610071042558",
    "expires_at": "2026-10-07T10:30:00.000Z"
  }
}

Request parameters#

Every field you can send when creating a payment. Field names are camelCase in requests; responses use snake_case.

  • amountstringRequired

    Amount as a decimal string, in the currency’s normal decimals.

    e.g. "499.00"

  • currencystringRequired

    ISO currency code (max 10), e.g. INR, USD, USDT.

    e.g. "INR"

  • merchantOrderIdstringOptional

    Your order ID (max 255). Returned as merchant_order_id in responses and webhooks so you can match the order.

    e.g. "ORDER-1001"

  • descriptionstringOptional

    Shown to the customer on checkout and in your dashboard.

    e.g. "Pro plan — 1 month"

  • orderItemsarrayOptional

    Up to 100 line items. Each: name (required, max 255), quantity (default 1), unitPrice, sku (max 80), currency. Shown on the payment and sent in webhooks as order_items.

    e.g. [{ "name": "Pro plan", "quantity": 1, "unitPrice": "499.00", "sku": "PRO-1M" }]

  • customerNamestringOptional

    Customer name (max 200).

    e.g. "Asha Verma"

  • customerEmailstringOptional

    Customer email (max 200). Searchable in the dashboard.

    e.g. "asha@example.com"

  • customerPhonestringOptional

    Customer phone (max 40).

    e.g. "+919800000000"

  • successUrlurlOptional

    Where the customer returns after paying.

    e.g. "https://yourstore.com/success"

  • cancelUrlurlOptional

    Where the customer returns if they cancel.

    e.g. "https://yourstore.com/cancel"

  • ipnUrlurlOptional

    Webhook URL for this payment only. PayerFox POSTs payment.paid here.

    e.g. "https://yourstore.com/webhooks/payerfox"

  • gatewaystringOptional

    Payment method code (e.g. paytm_upi_qr, binance_c2c, razorpay). Must be enabled for your website. Omit to let the customer choose on checkout.

    e.g. "paytm_upi_qr"

  • tagsstring[]Optional

    Labels on the payment. Use them to filter payments (GET /payments?tag=…) and to route the payment to the connected account that has the same tag.

    e.g. ["subscription", "vip"]

  • metaobjectOptional

    Any extra JSON you want back, e.g. your user ID or plan. Returned as meta in responses and webhooks. Keys customer, customerName/Email/Phone and orderItems/items are read as the fields above instead.

    e.g. { "userId": "u_8812", "plan": "pro" }

Full request body — every field
{
  "amount": "499.00",
  "currency": "INR",
  "merchantOrderId": "ORDER-1001",
  "description": "Pro plan — 1 month",
  "orderItems": [
    {
      "name": "Pro plan — 1 month",
      "quantity": 1,
      "unitPrice": "499.00",
      "sku": "PRO-1M"
    }
  ],
  "customerName": "Asha Verma",
  "customerEmail": "asha@example.com",
  "customerPhone": "+919800000000",
  "successUrl": "https://yourstore.com/success",
  "cancelUrl": "https://yourstore.com/cancel",
  "ipnUrl": "https://yourstore.com/webhooks/payerfox",
  "tags": [
    "subscription"
  ],
  "meta": {
    "userId": "u_8812",
    "plan": "pro"
  },
  "gateway": "paytm_upi_qr"
}

tags — labels such as ["subscription"]. Filter with GET /payments?tag=subscription, and a payment tagged like one of your connected accounts is routed to that account.

meta — any JSON object you want back, e.g. { "userId": "u_8812" }. It comes back unchanged as meta in responses and webhooks. You can also nest customer or orderItems inside it; those are read as the regular fields.

Send Idempotency-Key (your order ID works well). If a network error makes you retry, you get the same payment back instead of a duplicate.

Response examples#

Successful calls return { success: true, data }. Payment endpoints return the payment object below.

Payment object
{
  "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
  "number": 1042,
  "merchant_order_id": "ORDER-1001",
  "external_order_id": null,
  "gateway": null,
  "website_id": "3d6f0a12-8c4b-4e1a-9b77-51c2d0e4f9aa",
  "amount": "499.00",
  "currency": "INR",
  "order_amount": "499.00",
  "order_currency": "INR",
  "charge_amount": null,
  "charge_currency": null,
  "status": "pending",
  "description": "Pro plan — 1 month",
  "tags": [
    "subscription"
  ],
  "source": "website",
  "checkout_url": "https://pay.example.com/checkout/q3k9x2m7ab",
  "transaction_id": null,
  "paid_at": null,
  "expires_at": "2026-10-07T10:30:00.000Z",
  "created_at": "2026-10-07T10:00:00.000Z",
  "customer_name": "Asha Verma",
  "customer_email": "asha@example.com",
  "customer_phone": "+919800000000",
  "order_items": [
    {
      "name": "Pro plan — 1 month",
      "quantity": 1,
      "unit_price": "499.00",
      "sku": "PRO-1M",
      "currency": null
    }
  ],
  "meta": {
    "userId": "u_8812",
    "plan": "pro"
  }
}

Fields you'll use most

id
PayerFox payment id. Store it with your order.
status
Where the payment is (see lifecycle).
checkout_url
Send the customer here to pay.
merchant_order_id
The order ID you sent.
amount / currency
What you asked for.
charge_amount / charge_currency
What the customer was actually charged, when a method converts currency (e.g. INR → USDT).
transaction_id
The gateway’s reference once paid.
expires_at
Checkout link expiry. Use payment-link to renew.

Status lifecycle

created→pending→paid→refunded

A pending payment can also end as expired, failed or cancelled. Only paid means you have the money.

Webhooks#

PayerFox POSTs a payment.paid event to your server the moment a payment succeeds. Use it to fulfil orders — don't rely on the customer returning to your success page.

Two ways to receive them

Per payment

Pass ipnUrl when creating the payment. Simple; not signed, so confirm with Retrieve a payment before fulfilling.

Webhook endpoint

Add a URL in Dashboard → Webhooks. Gets every payment, signed with your whsec_… secret. Recommended.

Headers we send

  • X-PayerFox-EventstringRequired

    The event name.

    e.g. payment.paid

  • X-PayerFox-SignaturestringOptional

    sha256=<hex HMAC of the raw body with your secret>. Webhook endpoints only.

    e.g. sha256=5f2b…

  • X-PayerFox-Delivery-AttemptnumberRequired

    1 for the first try, higher on retries.

    e.g. 1

Retries

Reply with any 2xx within 15 seconds. Otherwise we retry after 30 s, 1 min, 5 min, 15 min, 1 h, 4 h, 12 h, 24 h — 9 attempts in all. You can see every delivery in Settings → Webhooks.

Make your handler idempotent: the same event can arrive more than once. Use data.id to ignore repeats, and check amount matches your order.
payment.paid payload
{
  "event": "payment.paid",
  "data": {
    "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
    "number": 1042,
    "merchant_order_id": "ORDER-1001",
    "external_order_id": null,
    "payerfox_order_id": "PF-1042",
    "amount": "499.00",
    "currency": "INR",
    "order_amount": "499.00",
    "order_currency": "INR",
    "charge_amount": null,
    "charge_currency": null,
    "status": "paid",
    "transaction_id": "T2610071042558",
    "paid_at": "2026-10-07T10:04:12.000Z",
    "description": "Pro plan — 1 month",
    "customer_name": "Asha Verma",
    "customer_email": "asha@example.com",
    "customer_phone": "+919800000000",
    "order_items": [
      {
        "name": "Pro plan — 1 month",
        "quantity": 1,
        "unit_price": "499.00",
        "sku": "PRO-1M",
        "currency": null
      }
    ],
    "meta": {
      "userId": "u_8812",
      "plan": "pro"
    }
  }
}

Verify the signature

import crypto from 'node:crypto';
import express from 'express';
const app = express();

// Use the raw body: the signature is computed over the exact bytes PayerFox sent.
app.post('/webhooks/payerfox', express.raw({ type: 'application/json' }), async (req, res) => {
  const secret = process.env.PAYERFOX_WEBHOOK_SECRET; // whsec_… from Settings → Webhooks
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(req.body).digest('hex');
  const received = req.get('X-PayerFox-Signature') ?? '';
  const valid =
    received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
  if (!valid) return res.sendStatus(401);

  const { event, data } = JSON.parse(req.body.toString('utf8'));
  if (event === 'payment.paid') {
    await markOrderPaid(data.merchant_order_id, data); // make this idempotent (use data.id)
  }
  res.sendStatus(200); // reply fast; do slow work after
});

Error handling#

Errors use normal HTTP status codes and always have the same shape, so one handler covers every endpoint.

Error response
{
  "success": false,
  "code": "BAD_REQUEST",
  "message": "amount must be a number string"
}
Branch on code, show message to your team. Retry only 429 and 5xx, with backoff and the same Idempotency-Key.
StatusCodeMeaningWhat to do
400BAD_REQUESTA field is missing or invalid. The message lists which.Fix the request; do not retry unchanged.
400GATEWAY_DISABLEDThe gateway you passed is not enabled for this website.Enable it in Payment methods or omit gateway.
400CURRENCY_UNSUPPORTEDThe payment method cannot take this currency.Use a supported currency or another method.
400GATEWAY_ACCOUNT_NOT_FOUNDNo connected account matches the amount or tags.Check account min/max amounts and tags.
400WALLET_INSUFFICIENTFree plan: the wallet cannot cover the platform fee.Top up the wallet in Billing.
400PAYMENT_NOT_PENDINGThe action needs a pending payment.Create a new payment.
401UNAUTHORIZEDAPI key missing, wrong or revoked.Send Authorization: Bearer <key>.
403FORBIDDENThe key is not allowed to do this (e.g. refunds need a team member).Use the dashboard for that action.
404PAYMENT_NOT_FOUNDUnknown id, or it belongs to another business.Check the id you stored.
429RATE_LIMITEDToo many requests in a short time.Wait and retry with backoff.
500INTERNAL_ERRORSomething went wrong on our side.Retry with the same Idempotency-Key.

Demo / playground#

Pick an endpoint, fill in the fields and watch the request build itself. Add a test key to send it for real.

1Request

2API call

curl -X POST "https://api.payerfox.com/api/v1/payments" \
  -H "Authorization: Bearer pd_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ORDER-1001" \
  -d '{
  "amount": "499.00",
  "currency": "INR",
  "merchantOrderId": "ORDER-1001",
  "description": "Pro plan — 1 month",
  "customerName": "Asha Verma",
  "customerEmail": "asha@example.com",
  "customerPhone": "+919800000000",
  "successUrl": "https://yourstore.com/success",
  "cancelUrl": "https://yourstore.com/cancel",
  "ipnUrl": "https://yourstore.com/webhooks/payerfox",
  "orderItems": [
    {
      "name": "Pro plan — 1 month",
      "quantity": 1,
      "unitPrice": "499.00",
      "sku": "PRO-1M"
    }
  ],
  "tags": [
    "subscription"
  ],
  "meta": {
    "userId": "u_8812",
    "plan": "pro"
  }
}'

Sending creates a real payment. Use a test key (pd_test_…).

3Response

Example
200 OK — example
{
  "success": true,
  "data": {
    "id": "7f1c2e9a-0b3d-4c5e-9f10-2a3b4c5d6e7f",
    "number": 1042,
    "merchant_order_id": "ORDER-1001",
    "external_order_id": null,
    "gateway": null,
    "website_id": "3d6f0a12-8c4b-4e1a-9b77-51c2d0e4f9aa",
    "amount": "499.00",
    "currency": "INR",
    "order_amount": "499.00",
    "order_currency": "INR",
    "charge_amount": null,
    "charge_currency": null,
    "status": "pending",
    "description": "Pro plan — 1 month",
    "tags": [
      "subscription"
    ],
    "source": "website",
    "checkout_url": "https://pay.example.com/checkout/q3k9x2m7ab",
    "transaction_id": null,
    "paid_at": null,
    "expires_at": "2026-10-07T10:30:00.000Z",
    "created_at": "2026-10-07T10:00:00.000Z",
    "customer_name": "Asha Verma",
    "customer_email": "asha@example.com",
    "customer_phone": "+919800000000",
    "order_items": [
      {
        "name": "Pro plan — 1 month",
        "quantity": 1,
        "unit_price": "499.00",
        "sku": "PRO-1M",
        "currency": null
      }
    ],
    "meta": {
      "userId": "u_8812",
      "plan": "pro"
    }
  }
}
Error example (400)

A required field is missing or invalid.

400 — error
{
  "success": false,
  "code": "BAD_REQUEST",
  "message": "amount must be a number string"
}

Live demo store

The downloadable demo, running right here. Click Pay to walk through create payment → checkout → confirmation.

Loading demo…

Download demo#

One HTML file, no build step. Open it in a browser and it works straight away in demo mode.

Open in new tab
  1. 1Open the file in your browser — demo mode shows the full flow without any setup.
  2. 2Open it in an editor and paste a test key into CONFIG.API_KEY. The API URL is already filled in for you.
  3. 3Switch to “Live test” and pay. Then copy the Node.js or PHP version at the bottom of the file into your server.
The only part you edit — top of the file
const CONFIG = {
  API_URL: 'https://api.payerfox.com/api/v1',      // already set for you
  API_KEY: 'pd_test_YOUR_TEST_KEY',   // ← paste a test key
  // Account / website: nothing to set — the key belongs to one website.
  GATEWAY: '',                        // optional method code, e.g. 'paytm_upi_qr'
  CURRENCY: 'INR',
  SUCCESS_URL: 'https://example.com/order/success',
  CANCEL_URL: 'https://example.com/order/cancel',
  IPN_URL: '',                        // optional webhook URL
};