Sethara Pay API: integration guide

Integration guide and API reference for Sethara Pay. Start with "Getting started", then create a payment and handle callbacks.

Getting started

Environments

Base URL
Sandbox https://beta.setharapay.io
Production https://api.setharapay.io

Create API keys in the merchant cabinet (https://admin.setharapay.io, Settings). Every request carries the key in Authorization: Bearer <key> or X-Api-Key: <key>. Requests are accepted only from the IP addresses allow-listed for the key. Keys can be rotated in the cabinet at any time; the previous key keeps working until you revoke it.

All amounts are strings with two decimals in INR. Timestamps are ISO 8601 in UTC.

Create a payment

Call POST /intake or POST /release with the order amount, your own order reference and the webhook URL that will receive status updates.

{
  "book_sum": "1250.00",
  "book_ccy": "INR",
  "trace_key": "order-2026-000123",
  "ping_url": "https://merchant.example/hooks/payments",
  "leg_type": "p2p_leg"
}

Payment lifecycle

A payment moves through the states below. Poll GET /{id}/status (no more often than every 5 seconds) or, better, rely on the callback and use polling only as a fallback.

State Meaning Next step
booked awaiting the payer intermediate, keep polling or wait for the callback
in_clearing the payer is completing the transfer; awaiting the payer intermediate, keep polling or wait for the callback
settled awaiting the payer; funds received intermediate, keep polling or wait for the callback
declined not completed; the payment window closed final
voided not completed final
recalled returned to the payer; awaiting the payer; disputed intermediate, keep polling or wait for the callback

Only final states are stable. Never treat an intermediate state as paid. clear_sum is the amount actually received and clear_at the time the funds were confirmed.

Callbacks

Every state change is delivered with POST to the ping_url of the payment. The body has the same shape as the status response.

Each delivery carries X-Webhook-Signature: t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of the string <t>.<raw request body> computed with the webhook secret issued to you at onboarding (keep it out of your client-side code). Recompute it over the raw body exactly as received, compare in constant time and reject deliveries whose t is older than five minutes. If no webhook secret was issued for your account, the header is absent and you must fetch the payment state with the status endpoint before acting on a callback.

Respond with any 2xx status within 10 seconds. Any other response or a timeout is retried with increasing delays for about 32 hours, so your handler must be idempotent: the same event can arrive more than once. Process by book_id and the state, not by delivery order.

Payer confirmation and receipts

On the hosted payment page the payer completes the transfer in a UPI app or by bank transfer and then confirms it either with the 12-digit bank reference (UTR) or by uploading a receipt. Sethara Pay matches the confirmation against the incoming funds; the payment stays in an intermediate state until the match is complete and then moves to a final state, which you receive through the callback.

If you collect the bank reference yourself, submit it with POST /confirm-leg together with book_id. A reference that does not match, was already used or belongs to a different amount ends the payment with a final failure state and halt_note explaining why; the payer is offered to upload a receipt or to contact support on the page.

Errors

Errors are returned with an HTTP status and a stable code. Use the code, not the message, in your logic.

Code HTTP Message
SE_SHORT_OF_FUNDS 402 The payer does not hold enough balance to book this movement.
SE_NO_SUCH_BOOKING 404 No movement is booked under the reference you sent.
SE_BOOKING_HELD 423 This movement is held while an adjustment clears.
SE_SUM_OFF_SCALE 422 The amount sits outside the band allowed on this leg.
SE_TRACE_KEY_SEEN 409 A movement already exists for this trace key.
SE_CCY_NOT_OPEN 422 This account clears in INR only.
SE_LEG_SILENT 502 The upstream leg returned nothing; retry in a moment.
SE_LEG_UNKNOWN 422 The requested leg is not wired for this account.
SE_LEG_ASLEEP 503 The leg is temporarily out of service.
SE_ROUTE_CLOSED 422 No open route matches this movement.
SE_ACCOUNT_BARRED 403 This merchant account is barred from booking movements.
SE_SUM_BELOW_FLOOR 422 The amount is under the floor set for this leg.
SE_SUM_ABOVE_CEILING 422 The amount is over the ceiling set for this leg.
SE_LEDGER_FAULT 500 The clearing ledger could not record this movement.
SE_LEDGER_BUSY 503 The clearing ledger is busy; retry shortly.
SE_TARIFF_FAULT 500 The tariff for this movement could not be resolved.
SE_ALREADY_CLEARED 409 This movement has already cleared and cannot change.
SE_DAY_CAP_HIT 429 The daily booking cap for this account is reached.
SE_REGION_CLOSED 403 Movements from this region are not accepted on this account.
SE_TOO_MANY_BOOKINGS 429 Too many movements booked in a short window; slow down.
SE_FROM_ACCT_BAD 422 The counterparty account failed validation.
SE_FROM_LABEL_BAD 422 The counterparty name failed validation.
SE_BACK_URL_BAD 422 The return address is not a valid https URL.
SE_LEG_SATURATED 429 The leg is at capacity; try again in a minute.
SE_PAGE_KIND_BAD 422 The requested payment page variant does not exist.
SE_STATE_MISMATCH 409 The movement is not in a state that allows this call.
SE_CLEARING_FAULT 500 Clearing failed on our side; the movement was not booked.
SE_LEG_KEYS_BAD 422 The leg credentials supplied are incomplete or wrong.
SE_ADJUSTMENT_BAD 422 The adjustment requested is not valid for this movement.
SE_PING_URL_BAD 422 The webhook address is missing, private or not https.
SE_EDGE_FAULT 500 The clearing edge could not be reached.
SE_BOOK_TIMEOUT 500 Booking timed out before the leg answered.
SE_PAYLOAD_BAD 422 The request body did not pass validation.
SE_UNMAPPED_FAULT 500 The upstream leg failed in a way we do not recognise.
SE_BOOKING_FAULT 500 The movement could not be booked. Please retry or contact support.

Validation problems (missing fields, wrong types) come back as 400 with a list of fields. 401 means the key or the source IP is not accepted. 5xx responses are safe to retry with the same trace_key.

Sandbox and testing

Use the sandbox base URL with sandbox keys from https://beta-admin.setharapay.io. Payments there never move real money: the payment page lets you complete or fail a payment on demand, so you can test every state, the callback signature and your retry handling. Check that your endpoint answers 2xx and that repeated deliveries do not create duplicate orders.

Reconciliation

The merchant cabinet provides a settlement report (CSV or XLSX) for any period with the bank reference of every payment, gross amount, fees and net amount. Match the report against your bank statement by the bank reference. Payouts show the same breakdown per settlement.

API reference

Machine-readable OpenAPI: openapi.json next to this guide. Endpoints: /intake, /release, /{id}/status, /confirm-leg.