Skip to main content
POST
Submit verification details

Overview

An LRS payment answers a longer list than an ordinary one: the remitter’s verified identity, the LRS declarations, the TCS collected, and a set of documents that depends on the purpose code. This page is that list, and what happens once it is complete.
Same endpoint as Submit Payment Verification Details. One URL answers every verification ask — fields, documents, partial sends and the response shape all work identically. Only what a payment is asked for differs, and that is what this page covers. If you do not handle LRS payments, the other page is all you need.
Send details keyed by the same codes that Get Verification Requirements and the LRS_VERIFICATION_NEEDED webhook use. There is nothing to map between them — every one of those places names an item under code:
JSON only. fields is an object; documents is a list of {code, ref} naming files uploaded earlier through Upload Document. Files are never posted to this endpoint.

The loop

1

An event arrives

LRS_VERIFICATION_NEEDED lists what the payment owes — each entry a code and a sentence.
2

You upload any files

Upload Document returns a ref per file. Upload each as it arrives; nothing has to be held back.
3

You send what you have

Fields as a map, documents as {code, ref}. Partial is fine — later sends merge over earlier ones.
4

You read where the payment stands

The response says both: a status, and outstanding — the codes still owed after this write.

The body depends on the checklist

There is one endpoint and one envelope — fields, documents, finalize — but what belongs inside them is decided by the payment’s checklist, not by you. That checklist comes from the order’s business model and purpose code together. Sending a key it does not ask for is a 400. You never have to work out which set applies: GET the same path and it tells you, or read the codes off the event.
Declaring an LRS purpose code is what makes a payment an LRS one. Send business_model and purpose_code together in fields — see Submit Payment Verification Details for the rules that govern the pair — and if the code is one of the five below, the payment switches to LRS_VERIFICATION_NEEDED and starts being asked for everything on this page.Until the pair is set no checklist claims the payment, so nothing else can be validated. The pair may ride in the same call as the rest.
Complete bodies for every LRS purpose code, built from the live checklists:
The three travel codes take an identical body. They differ in what the remittance is for — other travel, medical treatment, pilgrimage — not in what you must collect.The education examples declare remitter_relation as PARENT, which is what makes relationship_declaration and the student_* fields owed. Declare SELF and they all drop out — as they have in the travel example, where the same conditional fields are called primary_person_*.The remitter’s name and the TCS are not fields here. The name is whatever Verify PAN recorded against the PAN you declare, and the TCS is the figure we quote — sending either back would only give us a second number to disagree with.

What differs, and what does not

Do not branch on the purpose code in your own integration. Read the checklist instead. The codes above are what the matrix asks for today; it is configuration, and a revision reaches you through the API without a release on your side — but only if you are reading it rather than reproducing it.

Values

Field values are strings, numbers or booleans.
An unknown key is a 400, not a silent drop. A misspelled remitter_pan that we quietly ignored would leave the payment waiting forever for a field you believe you sent. Every key is checked before any is written, so one typo cannot half-apply a call.
Omit a key rather than sending null or an empty string — a blank value is itself a 400, with the same reasoning. A boolean requirement is only satisfied by true; false reads as not yet answered.

Documents

Each entry names one code and exactly one of ref or waiver_reason. Sending both, or neither, is a 400. Sending the same code twice in one call is a 400. Sending it again in a later call is fine — the newer ref or waiver replaces the earlier row.

Linking a top-up

When a credit is a further payment against an earlier one — the buyer was short, or paid the TCS separately — say so on the call that files:
A reason without a linked_payment_id is a 400. The reverse is fine: a link with no reason is just an unlabelled link.Like finalize, these describe the send, not the payment. They are read by the call that actually files, and a call that only stages carries them nowhere — so send them with the call that completes the set.

Partial sends are merged

Send three fields today and two tomorrow and you have sent five. Nothing you sent earlier is wiped by a later call, and a field’s newest value wins. This is deliberate: nobody collects a passport scan, a visa and a letter of admission in the same instant.
finalize defaults to true. It applies only to a complete set and never forces an incomplete one through, so a partial send is accepted either way — you do not have to set it. Pass finalize: false when you have sent everything but do not want the payment’s verification completed yet, and the details are recorded without going to the verification gateway.
That tolerance ends once the verification has been filed. A payment whose settlement_status is UNDER_REVIEW, VERIFIED, READY_FOR_SETTLEMENT or SETTLED refuses further sends — the staged rows are the record of what went to the gateway, and a later edit would leave them disagreeing with what was actually filed. GET the same path to read settlement_status before you send.

The response

Three keys, whatever you sent — and a fourth, refusal, on the one response that has something more to say: a complete set the gateway refused.
string
required
Lower-case, always one of four. The first two answer is the checklist satisfied; the second two answer what did the gateway do, and only appear on a call that actually filed.
array
required
The codes still owed after this write — the same codes you would get by filtering the GET on satisfied: false. Empty when nothing is.This is the list, not a pointer to one. You do not need a second call to learn what is left.
object
Why the gateway refused a set the checklist called complete. Present only alongside status: action_required — absent from every other response, so read it as a key that may not be there rather than one that is sometimes null.Where outstanding says what the checklist still wants, this says what the gateway did. They answer different questions, and the handoff only runs once the checklist is satisfied — so a refusal always arrives with outstanding empty.reason is one of:
The two name verdicts are one problem, not two. PAN_NAME_MISMATCH and SENDER_NAME_MISMATCH compare the same pair — the buyer name on the order against the name the PAN is registered to. Only the judge differs: the verification vendor reaches the first, our own fuzzy match the second, which is why a name can clear one and fail the other. Build one remediation, not two: correct whichever of the two names is wrong, and send again.
missing names gateway tokens: purpose_code, remitter.pan, declarations, primary_person, tcs, outstanding (a shortfall), and documents.<type> for each document still wanted — documents.passport, documents.offer_letter, and so on.The purpose-code and PAN verdicts are reached before anything else is looked at, so each carries exactly one entry in missing and outstanding_cents: 0. Only SENDER_NAME_MISMATCH and a null reason can carry a shortfall, or more than one entry.
refusal is a shortcut, not the record. The same verdict always arrives as LRS_VERIFICATION_NEEDED, translated into the checklist codes you send under. An integration driven by events needs nothing from here; this exists so a caller holding the response does not have to wait for the webhook to learn why.
action_required never means your details were discarded. Everything that reached us is held against the payment, whether the call ended in a refusal, a vendor outage or a half-finished set. You re-send the one thing that failed, not the whole set.

outstanding is empty and status is action_required

That pair is not a contradiction — it is the most important thing this response says. The checklist is satisfied; the gateway refused. Supplying a PAN is not the same as it verifying, and no requirement list has anything to say about that. The verdict arrives as LRS_VERIFICATION_NEEDED, same event type and same shape as any other, with the conclusion folded into the relevant entry’s message — a shortfall’s rupee figure, a PAN that would not verify, a sender who is not the account holder. This same response says it too, in refusal — the verdict, what the gateway still wants, and any shortfall in paise. Read that if you would rather not wait for the event.

Completion

finalize defaults to true and applies only to a complete set. It never forces an incomplete one through. Pass finalize: false to stage details without triggering verification — useful when you know more is coming, and the response then reads complete because the checklist is satisfied even though nothing was filed. When a complete set is filed it runs through the verification gateway — PAN verification, the sender-to-account-holder match, the TCS recomputation and the exactly-once LRS counter posting. in_review means all of that passed.
A complete LRS set is always filed. Sending the last outstanding item triggers verification on that same call, so the response answers in_review or action_required rather than complete. You only see complete here if you held the filing back with finalize: false.

When the handoff itself does not happen

A complete set can fail to reach a verdict at all:
An error is not a lost send. Everything staged before the handoff is held against the payment, so a failed dependency costs you a repeat of the same request rather than a re-collection of the details.Only the last row answers 200. A refusal the gateway actually reached is a successful call that reports action_required and always arrives as an event too; an error response means the handoff never got that far.
Details are stored before verification is attempted and are never discarded by it.

Errors

Every refusal is answered in the standard error envelope. Every refusal is a 400, whatever the reason — the code inside the envelope is what tells them apart, not the status. A 400 on the send carries details keyed by the offending code, so one call reports every problem at once:
A second group is raised only by the call that files a complete set, as the staged values are read for the gateway. They name the same codes:
These arrive on the finalizing call rather than the call that staged the value, because nothing reads a date as a date — or writes anything to the order — until the set is complete. Your details are still saved — fix the named code and re-send only that.

Where each value goes

Most fields flow into the verification and settlement record. Two are collected but held rather than forwarded, and it is worth knowing which:

Submit Payment Verification Details

The same endpoint, for a payment that is not an LRS one.

Get Verification Requirements

What this payment needs, and what it already has.

Upload Document

Upload a file and reference it by ref.

LRS_VERIFICATION_NEEDED

The event that tells you a payment owes details — and the one that reports a refusal.

Quote LRS Amount

TCS and the all-in total, before the buyer transfers.

Authorizations

X-Client-ID
string
header
required

Client Application ID - Your unique application identifier used to authenticate API requests. You can find your Client ID in the Developer Settings section of the merchant dashboard.

X-Client-Secret
string
header
required

Client Secret Key - Your secret key used alongside the Client ID for secure authentication. Keep this confidential and never expose it in client-side code. Available in the Developer Settings section of the merchant dashboard.

X-Merchant-ID
string
header
required

Merchant Identifier - The unique ID for the merchant account. This is required for PSP (Payment Service Provider) merchants who manage multiple merchant accounts. You can find merchant IDs in the Merchant Management section of the dashboard.

X-API-Version
string
header
required

API Version - Specifies which version of the API to use (e.g., '1.X.X', '2.X.X', or '3.X.X'). This header allows you to control which API version your integration uses. Default version information is available in the Developer Settings.

Path Parameters

payment_id
string
required

UID of the payment the details are for.

Body

application/json
fields
object

Answers keyed by checklist code, e.g. {"buyer_city": "Bengaluru", "invoice_number": "INV-2026-0041"}. Values are strings, numbers or booleans. Dates are YYYY-MM-DD; invoice_amount is a decimal string in rupees and declaration is a boolean. An unknown key is a 400 rather than a silent drop — a typo you never hear about would leave the payment waiting forever for a field you believe you sent. Omit a key rather than sending null or an empty string; a blank value is also a 400.

Example:
documents
object[]

Documents by reference, or waivers. Each entry names exactly one of ref and waiver_reason; sending both, neither, or the same code twice in one call is a 400.

finalize
boolean
default:true

Whether to run a complete set through the payment's verification gateway — the LRS gateway on an LRS payment, the B2B-services one on a services payment. Never forces an incomplete set through.

linked_payment_id
string | null

The earlier payment this one tops up — the buyer was short, or paid the TCS separately. Resolved against your own payments; a link that cannot be resolved is refused. Read by the call that files, so send it with the call that completes the set. LRS only: a B2B-services payment has no top-up concept and ignores this key rather than refusing it.

Example:

"PR6938527534"

reason
enum<string> | null

Why the two payments are linked; an audit label on the link. REMAINING_AMOUNT — covering a principal shortfall. TCS_PAYMENT — paying the TCS separately. Only valid together with linked_payment_id. LRS only, like linked_payment_id: ignored on a B2B-services payment.

Available options:
REMAINING_AMOUNT,
TCS_PAYMENT
Example:

"REMAINING_AMOUNT"

Response

Details received. The body says where the payment now stands and what is still owed.

success
boolean
Example:

true

message
string
Example:

"Verification details received"

data
object