Skip to main content
POST
Submit verification details

Overview

A B2B services payment answers a short list: who the buyer is, which invoice this is, and the invoice itself. No identity document, no amount to declare, no tax. 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.
Send details keyed by the same codes that Get Verification Requirements and the VERIFICATION_NEEDED webhook use. There is nothing to map between them — the GET names an item under code, the event names the same string in action_required_fields, and this endpoint takes it back under that key.
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

VERIFICATION_NEEDED lists what the payment owes, as a flat array of codes in action_required_fields. While the payment is still unclassified that list is a legacy order-field check and can name product_description and hs_code, which this flow never asks for — classify the payment, then read the real set from Get Verification Requirements.
2

You classify it, if nothing has

A VBA credit arrives unclassified. Send business_model and purpose_code before anything else can be checked.
3

You upload the invoice

Upload Document returns a ref.
4

You send what you have

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

You read where the payment stands

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

Classify it first

A payment with no business_model and purpose_code on its order has no requirement set, so nothing else about it can be validated. Both travel together:
They can ride along with everything else in one call, but sending them first is the simplest thing to do.
business_model and purpose_code must travel together, and only once. Send one without the other and the call is refused naming the one you left out. Once set, sending either again is a 400Already set on the order; it cannot be changed here.
Which codes are B2B services? S0802, S0803, S1005, S1009, S1010, S1013, S1015, S1016, S1017, S1105, S1106 — all against business_model: "B2B". They share one requirement set. The code must also be one your settling entity is enabled for; a valid code you are not enabled for is rejected just like one that does not exist.

The complete body

Nine fields and one document. This is the whole of it:
S0802 — B2B services
The buyer here is the Indian remitter, not your customer abroad. These fields describe whoever in India paid you — the same party the credit came from. buyer_postal_code is stored on the order as an Indian PIN code, so send the remitter’s Indian address rather than your own overseas one.
No amount and no declaration key. The amount that settles is the credit itself, read from the payment, and no tax is collected on top — so there is no principal and no collected_tcs to send. The declaration is recorded by the act of filing a complete set rather than sent as a field. All three are 400s if you send them.

Values

Field values are strings.
An unknown key is a 400, not a silent drop. A misspelled invoice_number 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.

Documents

One entry, naming the invoice’s checklist code and the ref you got from Upload Document: Sending the same code twice in one call is a 400. Sending it again in a later call is fine — the newer ref replaces the earlier row.
One citation covers every invoice on the payment. The citation names the code, and this flow has exactly one document type per code, so all the payment’s invoices are filed when the set completes — not just the one whose ref you sent. Upload a second invoice and it goes with them; you do not cite it, and you cannot leave it out.
waiver_reason is not accepted on this flow. No B2B services item is waivable, so there is nothing to discharge with a reason instead of a file. Sending one is a 400 reading This document cannot be waived., keyed by the document’s code.
linked_payment_id and reason are ignored here. The shared request body accepts them, but they mark a payment as a top-up of an earlier one — an LRS concept. B2B services has none, so both are read and discarded rather than refused. Do not send them expecting a link.

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.
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 verification filed yet.
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:
Three values, not four. A complete set either files — in_review — or is refused with a 400 naming what to fix. There is no action_required here; do not write a branch for a value you will never receive.
A refusal never discards your details. Everything you sent is staged against the payment before the filing is attempted, so a 400 on the finalizing call costs you a re-send of the one thing that failed, not the whole set.

Completion

A complete B2B services set hands off to its own verification gateway, and in_review is what says it got there. That handoff is also what writes the staged values onto the order — which is why a second group of refusals only appears on the finalizing call.

Errors

Every refusal is a 400, whatever the reason — the code inside the envelope is what tells them apart, not the status.
Branch on code, not on message. 40359 is shared with the other verification flows; message names which one refused you, so a classified B2B services payment always reads Invalid B2B services request. The code is the stable part.Before the payment is classified there is no flow to name, and the wording is Invalid verification request. instead — the one case on this flow where the message is not the services one.Not every refusal is 40359. A few carry a code of their own, listed above — they are the specific ones, and they say more than the shared code does. Treat any code you do not recognise as a 400 you should not retry unchanged.
A 400 on the send carries details keyed by the offending code, so one call reports every problem at once:

Raised only by the call that files

A second group appears only when a complete set is filed, as the staged values are read for the gateway and written onto the order: Filing is also what writes the staged buyer and invoice fields onto the order, and the order validates them on write — which is where that PIN code is judged. invoice_number is unique per merchant, so a collision surfaces here too. Unlike the refusals above it does not answer under 40359 — it carries its own code:
invoice_number is unique per merchant across filed verifications. Re-using one from an earlier payment is refused here, not at the call that staged it — raise a new number and send that field again.These all 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.

Get Verification Requirements

What this payment is asked for, and what is already satisfied.

Upload Document

Upload the commercial invoice and keep its ref.

B2B Services Verification

The whole flow, in order.

List Settlement Documents

The step that opens once the payment settles.

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. {"remitter_pan": "ABCPK1234F", "buyer_city": "Bengaluru"}. Values are strings, numbers or booleans. Dates are YYYY-MM-DD; amounts (principal, collected_tcs) are decimal strings in rupees. 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