Sandbox · test data only · no real payments are processed
Payrapyd
OpenAPI reference

Accept payments with Payrapyd

Your server talks to the Payrapyd API; your customer pays on a hosted page. You never see or store card or UPI details. All amounts are integer strings in paise (₹1,250.50 = "125050").

  1. Create an order on your server.
  2. Send the customer to the hosted checkout page.
  3. When they come back, ask the API for the order's status, and also listen for webhooks.
  4. Fulfil only when the status is succeeded.

Base URL: https://sandbox-api.payrapyd.com · Machine-readable reference: openapi.json (import it into Postman or any OpenAPI tool).

1. API keys

Create a key in the dashboard (merchant page → API keys). Send it on every request as a bearer token. Test keys start with pyd_test_ and only ever reach the payment simulator: no real money moves.

curl https://sandbox-api.payrapyd.com/v1/whoami -H "Authorization: Bearer $PAYRAPYD_KEY"

Keep keys on your server only: never in a browser, app or repository. If a key leaks, revoke it in the dashboard and create a new one.

2. Create an order and send the customer to checkout

curl -X POST https://sandbox-api.payrapyd.com/v1/orders \
  -H "Authorization: Bearer $PAYRAPYD_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-INV-1001" \
  -d '{"amount":"125050","currency":"INR","merchantOrderRef":"INV-1001",
       "returnUrl":"https://shop.example/payment/return"}'

Then get the hosted checkout URL and redirect the customer to it (full page, not an iframe):

curl -X POST https://sandbox-api.payrapyd.com/v1/orders/pay_…/checkout-sessions \
  -H "Authorization: Bearer $PAYRAPYD_KEY"
# → { "checkoutUrl": "https://…", "expiresAt": "…", "attemptId": "att_…" }

3. Confirm the result

The customer comes back to your returnUrl with ?payrapyd_order_id=pay_…. The return never tells you whether they paid: anyone can type that URL. Always ask the API:

curl https://sandbox-api.payrapyd.com/v1/orders/pay_… -H "Authorization: Bearer $PAYRAPYD_KEY"
# "status": "succeeded" → fulfil · "pending" → show "processing", check again or wait for the webhook
# "failed" / "expired" → let the customer try again with a new order

Statuses: created → pending → succeeded | failed | expired, then partially_refunded → refunded. Only the payment provider's confirmation can make an order succeed.

4. Webhooks

Register an https endpoint (dashboard → merchant → Webhooks, or POST /v1/webhook-endpoints) and keep the signing secret it shows once. Events: order.succeeded, order.failed, order.expired, refund.succeeded, refund.failed.

Verify every delivery before trusting it, using the raw request body:

// Node.js (Express): app.post('/payrapyd/webhooks', express.raw({ type: 'application/json' }), handler)
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  const given = String(parts.v1 ?? '');
  return given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}

function handler(req, res) {
  if (!verify(req.body.toString('utf8'), req.get('Payrapyd-Signature') ?? '', process.env.PAYRAPYD_WEBHOOK_SECRET)) {
    return res.sendStatus(400);
  }
  const event = JSON.parse(req.body);
  // De-duplicate on event.id (also in the Payrapyd-Event-Id header), then do the work.
  res.sendStatus(200);
}

5. Refunds

curl -X POST https://sandbox-api.payrapyd.com/v1/orders/pay_…/refunds \
  -H "Authorization: Bearer $PAYRAPYD_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: refund-INV-1001-1" \
  -d '{"amount":"25050","reason":"item returned"}'

Partial refunds are allowed; together they can never exceed what was paid. A refund is final only when the provider confirms it (refund.succeeded webhook, or GET /v1/refunds/rfd_…).

6. Retries, idempotency and errors

7. Testing in the sandbox