Draft · Sandbox documentation · Not for public release
PayPe Technologies · Coimbatore

Payments API

Accept UPI, cards and net banking on your website. PayPe handles the gateway integration, status reconciliation and refunds; you make three API calls.

Base URLs

Sandbox  https://api.paype.co.in

Production  https://api.paype.co.in  — same host, keyed by your credentials

What you need before starting

  • A PayPe merchant account — you receive a MER… merchant ID
  • Your website domain, registered with us (sent to the gateway on every charge)
  • A server that can make HTTPS requests and receive them

Two ways to integrate

Hosted checkout is a single link. No server code, no keys — send the customer to a PayPe page and we return them to yours. Start here.

Server APIs give you control over the amount, order ID and redirect target, and let you query status and issue refunds from your own backend.

Payment lifecycle

Every payment holds exactly one state. Two of them are final; one is not.

State transitions

CREATED PENDING
COMPLETED FAILED

COMPLETED and FAILED are terminal — they never change again. PENDING is not a result. A customer who closed their browser mid-payment leaves an order in PENDING, and it may still succeed at the bank. Never mark an order paid, and never ship goods, on anything but a terminal state.

The one mistake that costs money

Do not treat the browser redirect back to your site as confirmation. A customer can close the tab, lose signal, or press back. Confirm from the Order status endpoint or a webhook — those are the only sources of truth.

Quickstart

Take a test payment in about two minutes.

1. Send the customer to checkout

Replace the merchant ID with your own. This link works today, with no keys required.

Hosted checkout link
https://api.paype.co.in/?merchant=MER1783999043172

2. Customer pays

PayPe shows the payment page, the customer chooses UPI, card or net banking, and we return them to your result page with the order ID appended.

3. Confirm the result from your server

cURL
curl https://api.paype.co.in/api/order-status/PAYPE1783999272545
Response
{
  "state": "COMPLETED",
  "amount": 1000,
  "orderId": "OMO2607140912466357046693"
}

Read state at the root of the response. Nothing else decides whether the customer paid.

Amounts & identifiers

Amounts are in paise

Every amount in every request and response is an integer in paise. Sending 100 charges one rupee, not one hundred. Rounding errors here become refund disputes later, so convert once, in one place in your code.

14950

amount = Math.round(rupees × 100)

Order IDs

You may supply your own merchantOrderId, or let PayPe generate one. Either way it must be unique for every attempt, under 63 characters, and contain only letters, numbers, hyphens and underscores.

IdentifierIssued byExample
merchantOrderIdYou or PayPePAYPE1783999272545
orderIdGatewayOMO2607140912466357046693
merchantRefundIdPayPeREFUND1783997069495
utr / arnBank455226570184

Keep the bank reference — UTR for UPI, ARN or BRN for cards and net banking. It is what a bank asks for when a customer disputes a charge.

API keys Spec

Server-to-server calls will be authenticated with a key pair issued per merchant from your dashboard: a key ID you may expose, and a secret you must not.

Request headers
X-PayPe-Key-Id: pk_live_8f3ef32ad3fc
X-PayPe-Signature: HMAC-SHA256(body, secret)
Content-Type: application/json

Keeping the secret secret

  • Server side only. Never in browser JavaScript, mobile app binaries, or a repository.
  • Store it in your hosting platform's environment settings, not in a file you commit.
  • Rotate it from the dashboard if it is ever exposed. Old keys stop working immediately.
Before publishing these docs

Per-merchant keys are not implemented yet. Today the server APIs accept a merchantId with no signature, which is safe only while the endpoints are used by PayPe's own pages. Issue keys and verify the signature before any external merchant is given server API access.

Hosted checkout Live

The fastest integration, and the one with the least to get wrong. Link or redirect the customer to your PayPe checkout URL.

HTML
<a href="https://api.paype.co.in/?merchant=MER1783999043172">
  Pay with PayPe
</a>
Query parameterDescription
merchant required Your merchant ID. Determines which account the payment settles to, and which domain is declared to the gateway.

If your account is suspended, checkout refuses the payment before the customer reaches the gateway. An unknown merchant ID is rejected the same way.

Create payment Live

POST /api/create-payment Live

Creates an order and returns the gateway URL to send the customer to. The order is recorded as PENDING and tracked until it reaches a terminal state.

Body

FieldTypeDescription
amount requirednumberAmount in rupees. Converted to paise server side.
merchantIdstringYour MER… ID. Omit only for PayPe's own test page.
Request
curl -X POST https://api.paype.co.in/api/create-payment \
  -H 'Content-Type: application/json' \
  -d '{"amount": 149.50, "merchantId": "MER1783999043172"}'
201 Response
{
  "merchantOrderId": "PAYPE1783999272545",
  "redirectUrl": "https://mercury.phonepe.com/transact/…"
}

Send the customer to redirectUrl. Store merchantOrderId against your own order record — you need it to check status and to refund.

Order status Live

GET /api/order-status/{merchantOrderId} Live

Returns the current state of an order. Safe to call as often as you need; this is the endpoint to trust when deciding whether a customer has paid.

200 Response
{
  "state": "COMPLETED",
  "amount": 14950,
  "orderId": "OMO2607140912466357046693",
  "paymentDetails": [
    {
      "paymentMode": "UPI_QR",
      "state": "COMPLETED",
      "rail": { "utr": "455226570184" }
    }
  ]
}
Read the root state

Use the top-level state. The entries inside paymentDetails describe individual attempts — a customer may fail once on a card and then succeed on UPI, and only the root state accounts for that.

Treat unknown fields as normal. New payment methods add new keys, and a parser that rejects anything unexpected will break on the day we add one.

Refund Live

POST /api/refund Live

Refunds all or part of a completed payment. Partial refunds may be issued repeatedly until the original amount is exhausted.

Body

FieldTypeDescription
merchantOrderId requiredstringThe order being refunded.
amount requirednumberAmount in rupees, up to the refundable balance.
Request
curl -X POST https://api.paype.co.in/api/refund \
  -H 'Content-Type: application/json' \
  -d '{"merchantOrderId": "PAYPE1783999272545", "amount": 50}'
200 Response
{
  "merchantRefundId": "REFUND1783997069495",
  "amount": 5000,
  "state": "PENDING"
}

What gets checked first

Three conditions are verified against PayPe's own records before any money moves:

ConditionIf it fails
The order exists404 Order not found in our records
The order is COMPLETED400 Only COMPLETED orders can be refunded
Refunds so far + this one ≤ original400 Refund exceeds refundable balance

The balance error returns the arithmetic — original amount, already refunded, and remaining — so you can show the customer an accurate figure rather than a generic failure.

Refund status Live

GET /api/refund-status/{merchantRefundId} Live

Refunds start PENDING and usually settle within seconds, though bank processing can take longer. Poll this endpoint, or wait for the refund webhook.

200 Response
{
  "state": "COMPLETED",
  "amount": 5000,
  "originalMerchantOrderId": "PAYPE1783999272545",
  "splitInstruments": [
    { "rail": { "utr": "455226570184" } }
  ]
}

Give the customer the UTR or ARN once the refund completes. It answers the "where is my money" question better than a date ever does.

Webhooks Spec

Rather than polling, register an HTTPS endpoint and PayPe will notify you when a payment or refund reaches a terminal state.

EventSent when
payment.completedA payment succeeded
payment.failedA payment failed or expired
refund.completedA refund reached the customer
refund.failedA refund could not be processed
Payload
{
  "event": "payment.completed",
  "payload": {
    "merchantOrderId": "PAYPE1783999272545",
    "state": "COMPLETED",
    "amount": 14950
  }
}

Verify every webhook before trusting it

Anyone can send a POST to your endpoint. Compute the expected signature from your webhook secret and compare — reject with 401 if it does not match.

Node.js
// req.rawBody is the unparsed request body
const expected = crypto
  .createHmac("sha256", process.env.PAYPE_WEBHOOK_SECRET)
  .update(req.rawBody)
  .digest("hex");

if (req.headers["x-paype-signature"] !== expected) {
  return res.status(401).json({ error: "unauthorized" });
}

// Verified. Use payload.state, and reply 200 quickly.
res.status(200).json({ received: true });

Rules for your handler

  • Reply 200 fast. Do slow work afterwards. Timeouts trigger retries.
  • Expect duplicates. The same event may arrive twice. Check whether you have already processed that order before acting on it.
  • Read the root state, and identify the event from event.
  • Webhooks are not a guarantee. Networks fail. Keep Order status as your fallback.
Before publishing these docs

Merchant-facing webhooks are not built yet. PayPe currently receives webhooks from the gateway but does not forward events to merchants. Needed: a webhook URL and secret per merchant, a signed delivery, and a retry schedule.

Reconciliation Live

PayPe chases every PENDING order on your behalf until it resolves, so an abandoned checkout still ends up with a correct final state in your dashboard.

Polling schedule per pending order

every 3s for the first 30 seconds
every 6s for the next minute
every 10s for the next minute
every 30s for the next minute
every 60s until the order expires at 20 minutes

Polling stops the moment a terminal state arrives, whether from the status API or a webhook. Nothing is polled after it is settled.

You do not need to build this yourself. It runs inside PayPe.

Errors

Errors return a JSON body with an error field describing what happened and, where useful, the values involved.

StatusMeaningWhat to do
400Invalid request — bad amount, missing field, refund over balanceFix the request. Do not retry unchanged.
401Signature missing or wrongCheck the key and how you sign the body.
403Merchant suspendedContact PayPe. Payments are blocked until reactivated.
404Unknown merchant, order or refundCheck the identifier.
502Gateway rejected or was unreachableRetry with the same order ID, then check status.
503PayPe could not verify records — refunds are blocked rather than riskedRetry shortly.
Why 503 blocks refunds

If PayPe cannot read the refund history for an order, it cannot know how much is left to refund — so it refuses instead of guessing. A failed refund is recoverable; an over-refund is money gone.

Test in sandbox

Sandbox behaves like production but moves no real money. Use it to exercise every path before you go live — especially the ones you hope never happen.

Cases to cover

ScenarioExpected result
Successful UPI paymentOrder reaches COMPLETED
Failed card paymentOrder reaches FAILED, nothing shipped
Customer closes the tab mid-paymentOrder stays PENDING, then resolves by reconciliation
Full refundRefund COMPLETED, balance now zero
Partial refund, twiceBoth succeed while the total stays within the original
Refund more than the balanceRejected with the arithmetic returned
Duplicate webhookYour handler processes the order once
Sandbox credentials

Test merchant IDs and keys are issued from your PayPe dashboard. Never put live credentials in documentation, support tickets, or chat messages.

Going live

  1. Confirm your domain is registered against your merchant account.
  2. Swap sandbox keys for live keys in your server environment.
  3. Point your webhook URL at your production endpoint and verify signatures there.
  4. Run one real payment of ₹1 and refund it, end to end.

Roadmap

Documented here so you can plan. These are not available yet — do not build against them.

Planned

Payouts

Send money to a bank account or UPI ID. Needed for marketplace sellers, refunds outside the original payment, and vendor disbursement.

Planned

Virtual accounts

A dedicated account number or UPI ID per customer, so incoming transfers reconcile automatically against an invoice.

Planned

Static QR

A printable QR for counters and storefronts, with the collection appearing in your dashboard.

Planned

Settlement reports

Daily settlement files showing gross collection, fees, refunds and the net amount credited to your bank.