curl --request GET \
--url https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/ \
--header 'X-API-Version: <api-key>' \
--header 'X-Client-ID: <api-key>' \
--header 'X-Client-Secret: <api-key>' \
--header 'X-Merchant-ID: <api-key>'import requests
url = "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/"
headers = {
"X-Client-ID": "<api-key>",
"X-Client-Secret": "<api-key>",
"X-Merchant-ID": "<api-key>",
"X-API-Version": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'X-Client-ID': '<api-key>',
'X-Client-Secret': '<api-key>',
'X-Merchant-ID': '<api-key>',
'X-API-Version': '<api-key>'
}
};
fetch('https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Version: <api-key>",
"X-Client-ID: <api-key>",
"X-Client-Secret: <api-key>",
"X-Merchant-ID: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Client-ID", "<api-key>")
req.Header.Add("X-Client-Secret", "<api-key>")
req.Header.Add("X-Merchant-ID", "<api-key>")
req.Header.Add("X-API-Version", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/")
.header("X-Client-ID", "<api-key>")
.header("X-Client-Secret", "<api-key>")
.header("X-Merchant-ID", "<api-key>")
.header("X-API-Version", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Client-ID"] = '<api-key>'
request["X-Client-Secret"] = '<api-key>'
request["X-Merchant-ID"] = '<api-key>'
request["X-API-Version"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Verification requirements",
"data": {
"payment_id": "PR6938527534",
"order_id": "OD3376378679",
"settlement_status": "ACTION_REQUIRED",
"business_model": "B2B",
"purpose_code": "S0802",
"fields": [
{
"code": "buyer_name",
"message": "Buyer / remitter name",
"satisfied": true,
"provided": true
},
{
"code": "buyer_address_line_1",
"message": "Buyer address line 1",
"satisfied": false,
"provided": false
},
{
"code": "buyer_city",
"message": "Buyer city",
"satisfied": false,
"provided": false
},
{
"code": "buyer_state",
"message": "Buyer state",
"satisfied": false,
"provided": false
},
{
"code": "buyer_postal_code",
"message": "Buyer PIN code",
"satisfied": false,
"provided": false
},
{
"code": "buyer_email",
"message": "Buyer email",
"satisfied": false,
"provided": false
},
{
"code": "buyer_phone",
"message": "Buyer phone",
"satisfied": false,
"provided": false
},
{
"code": "invoice_number",
"message": "Invoice number",
"satisfied": false,
"provided": false
},
{
"code": "invoice_date",
"message": "Invoice date",
"satisfied": false,
"provided": false
},
{
"code": "invoice_amount",
"message": "Invoice total in INR, as stated on the invoice",
"satisfied": false,
"provided": false
},
{
"code": "declaration",
"message": "The declaration the merchant affirms: the service was received and the invoice is genuine",
"satisfied": false,
"provided": false
}
],
"documents": [
{
"code": "invoice",
"message": "Commercial invoice",
"satisfied": false,
"provided": false
}
]
}
}Get Verification Requirements
Everything a B2B services payment is asked for — the eleven buyer and invoice fields, the commercial invoice, and which are already satisfied.
curl --request GET \
--url https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/ \
--header 'X-API-Version: <api-key>' \
--header 'X-Client-ID: <api-key>' \
--header 'X-Client-Secret: <api-key>' \
--header 'X-Merchant-ID: <api-key>'import requests
url = "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/"
headers = {
"X-Client-ID": "<api-key>",
"X-Client-Secret": "<api-key>",
"X-Merchant-ID": "<api-key>",
"X-API-Version": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {
'X-Client-ID': '<api-key>',
'X-Client-Secret': '<api-key>',
'X-Merchant-ID': '<api-key>',
'X-API-Version': '<api-key>'
}
};
fetch('https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Version: <api-key>",
"X-Client-ID: <api-key>",
"X-Client-Secret: <api-key>",
"X-Merchant-ID: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-Client-ID", "<api-key>")
req.Header.Add("X-Client-Secret", "<api-key>")
req.Header.Add("X-Merchant-ID", "<api-key>")
req.Header.Add("X-API-Version", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/")
.header("X-Client-ID", "<api-key>")
.header("X-Client-Secret", "<api-key>")
.header("X-Merchant-ID", "<api-key>")
.header("X-API-Version", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-pacb-uat.eximpe.com/pg/payments/{payment_id}/verification/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-Client-ID"] = '<api-key>'
request["X-Client-Secret"] = '<api-key>'
request["X-Merchant-ID"] = '<api-key>'
request["X-API-Version"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Verification requirements",
"data": {
"payment_id": "PR6938527534",
"order_id": "OD3376378679",
"settlement_status": "ACTION_REQUIRED",
"business_model": "B2B",
"purpose_code": "S0802",
"fields": [
{
"code": "buyer_name",
"message": "Buyer / remitter name",
"satisfied": true,
"provided": true
},
{
"code": "buyer_address_line_1",
"message": "Buyer address line 1",
"satisfied": false,
"provided": false
},
{
"code": "buyer_city",
"message": "Buyer city",
"satisfied": false,
"provided": false
},
{
"code": "buyer_state",
"message": "Buyer state",
"satisfied": false,
"provided": false
},
{
"code": "buyer_postal_code",
"message": "Buyer PIN code",
"satisfied": false,
"provided": false
},
{
"code": "buyer_email",
"message": "Buyer email",
"satisfied": false,
"provided": false
},
{
"code": "buyer_phone",
"message": "Buyer phone",
"satisfied": false,
"provided": false
},
{
"code": "invoice_number",
"message": "Invoice number",
"satisfied": false,
"provided": false
},
{
"code": "invoice_date",
"message": "Invoice date",
"satisfied": false,
"provided": false
},
{
"code": "invoice_amount",
"message": "Invoice total in INR, as stated on the invoice",
"satisfied": false,
"provided": false
},
{
"code": "declaration",
"message": "The declaration the merchant affirms: the service was received and the invoice is genuine",
"satisfied": false,
"provided": false
}
],
"documents": [
{
"code": "invoice",
"message": "Commercial invoice",
"satisfied": false,
"provided": false
}
]
}
}Overview
Returns the verification requirements for one B2B services payment: every field and document it is asked for, which are already satisfied, and which are still outstanding. The requirement set is chosen by two facts on the order — its business model and its purpose code. Until both are declared no set claims the payment, and this endpoint asks for them instead. TheVERIFICATION_NEEDED webhook lists what a payment is missing, as a flat array of codes in action_required_fields. This returns the whole set, each item an object carrying message, satisfied and provided. The codes are shared — an item the event names is an item you send back under the same key — but the shapes are not, so build your form from here rather than from the event.
VERIFICATION_NEEDED falls back to a legacy order-field check and can name product_description and hs_code — goods fields this flow never asks for. Ignore them, classify the payment, and read the real set from here.When to use it
You missed an event
settlement_status, which tells you whether sending anything is still possible.You need the whole set
You are resuming
You are building the form
fields and documents describe the whole set, satisfied or not, with a message per item safe to show a user. Filter on satisfied for what is still owed.Response
Two complete, unedited responses: a payment nothing has classified yet, and the same payment once it is classified as B2B services.{
"success": true,
"message": "Verification requirements",
"data": {
"payment_id": "PR6938527534",
"order_id": "OD3376378679",
"settlement_status": "ACTION_REQUIRED",
"business_model": null,
"purpose_code": null,
"fields": [
{ "code": "business_model", "message": "Business model (B2B or B2C)", "satisfied": false, "provided": false },
{ "code": "purpose_code", "message": "FEMA/FETERS purpose code for this order", "satisfied": false, "provided": false }
],
"documents": []
}
}
{
"success": true,
"message": "Verification requirements",
"data": {
"payment_id": "PR6938527534",
"order_id": "OD3376378679",
"settlement_status": "ACTION_REQUIRED",
"business_model": "B2B",
"purpose_code": "S0802",
"fields": [
{ "code": "buyer_name", "message": "Buyer / remitter name", "satisfied": true, "provided": true },
{ "code": "buyer_address_line_1", "message": "Buyer address line 1", "satisfied": false, "provided": false },
{ "code": "buyer_city", "message": "Buyer city", "satisfied": false, "provided": false },
{ "code": "buyer_state", "message": "Buyer state", "satisfied": false, "provided": false },
{ "code": "buyer_postal_code", "message": "Buyer PIN code", "satisfied": false, "provided": false },
{ "code": "buyer_email", "message": "Buyer email", "satisfied": false, "provided": false },
{ "code": "buyer_phone", "message": "Buyer phone", "satisfied": false, "provided": false },
{ "code": "invoice_number", "message": "Invoice number", "satisfied": false, "provided": false },
{ "code": "invoice_date", "message": "Invoice date", "satisfied": false, "provided": false }
],
"documents": [
{ "code": "invoice", "message": "Commercial invoice", "satisfied": false, "provided": false }
]
}
}
business_model and purpose_code come back null, and the two facts that would resolve them are listed as ordinary outstanding fields — same shape as any other entry. Send them back under those codes and the real requirement set appears on the next call. Classify before you upload anything, too: Upload Document is routed by the payment’s flow and refuses until the pair has landed.buyer_name reads satisfied: true in the second response because the credit carried it. The set accounts for what we already hold, so you only collect the rest.
Reading the response
The payment
payment_id in this endpoint’s own path.| Value | What it means for you |
|---|---|
ACTION_REQUIRED | The payment is waiting on you. Send what is outstanding. |
INFO_PENDING | The same, earlier in the flow — nothing has been filed yet. |
UNDER_REVIEW | Filed and with EximPe Ops. Sending is closed. |
VERIFIED · READY_FOR_SETTLEMENT · SETTLED | Past verification. Sending is closed. SETTLED is also when the post-settlement document step opens. |
EXPIRED · REJECTED · ON_HOLD | The payment did not proceed. Nothing you send reopens it. |
PAYMENT_PENDING · PAYMENT_FAILED | The money has not arrived, or did not arrive. There is nothing to verify yet; a services payment you can act on starts at the credit. |
SETTLEMENT_ERROR | Settlement was attempted and failed. Verification is behind it; this is an EximPe-side state, not something you clear by sending. |
NOT_APPLICABLE | Ops rejected the verification, or the payment carries no settlement workflow at all. Either way it will not settle and nothing you send reopens it. After a rejection a full refund is raised — follow that, not this endpoint. |
SETTLED or NOT_APPLICABLE; the rest are here so an unexpected value is a value you can look up rather than a surprise.Once the verification has been filed, staging closes: a POST to this path is refused rather than half-applied, because the staged rows are the record of what actually went to the gateway. Read this key before you send, and you will not collect a refusal you had no way to see coming.B2B for every services payment, or null while nothing has declared it.null while none is declared.The items
There is one list per kind, holding the whole set. There is no separate “missing” array — what is still owed is a filter:const outstanding = [...data.fields, ...data.documents].filter(i => !i.satisfied)
fields and documents carries code, message, satisfied and provided.
fields, or as a document’s code. See Submit Verification Details.400’s details keyed by the offending code. The same code also rides the VERIFICATION_NEEDED event that refusal raises, so the two agree.false is what “missing” means.It can go back to false on the invoice. If Ops rejects the invoice during review, the item is owed again and the payment is sent back for it. Upload a replacement and cite the new ref — re-sending the rejected one changes nothing.false/false is owed, true/true is done.optional, condition, waivable and one_of appear only when they apply, and no B2B services item is optional, conditional or waivable. Their absence is meaningful, not an omission.No status, deliberately
There is no rolled-up complete / incomplete on this response. “Every box is ticked” is not “the payment passed” — a complete set still goes to the gateway, and a gateway can refuse it. And the POST on this same URL already returns a status that means something else.
Fold your own roll-up when you want one:
const complete = [...data.fields, ...data.documents].every(i => i.satisfied)
settlement_status or the submit response.
GET never moves a payment; it reports the requirement set and what has been collected against it.Errors
Every refusal is a400; the code inside the envelope is what tells them apart.
error.code | When |
|---|---|
40360 | No such payment for this merchant. The same answer whether it does not exist or belongs to someone else, so the endpoint never confirms another merchant’s payment id. |
40359 | The payment is classified, but no requirement set covers that business model and purpose code. An unclassified payment is not this case: it answers 200, asking for the two classifying facts. |
What the B2B services set asks for
The exact set is always what this endpoint returns — this is a summary, and a revision lands there before it lands in any table. All eleven services purpose codes share one set:S0802, S0803, S1005, S1009, S1010, S1013, S1015, S1016, S1017, S1105, S1106, each against business_model: "B2B".
| Codes | |
|---|---|
| Fields | buyer_name, buyer_address_line_1, buyer_city, buyer_state, buyer_postal_code, buyer_email, buyer_phone, invoice_number, invoice_date, invoice_amount, declaration |
| Documents | invoice |
buyer_name is a plain value you send, so there is no step to clear before you can submit.invoice_amount is asked for, but it decides nothing. Send it in rupees; it is cross-checked against the credit and refused if the two are more than a paisa apart. What settles is still the credit itself, and no tax is collected on top — amount_to_be_settled remains an unknown key here, and sending it is a 400.hs_code. HS codes describe physical goods crossing a border. Services have none, and there is no field for one.Related
Submit Verification Details
Upload Document
ref.B2B Services Verification
List Settlement Documents
Authorizations
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.
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.
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.
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
UID of the payment the details are for.
Response
The payment's checklist and the current state of each item.
true
"Verification requirements"
What a payment needs and what it already has — the whole checklist, unlike the LRS_VERIFICATION_NEEDED webhook, which lists only what is outstanding. There is deliberately no rolled-up completion field: each item carries its own satisfied, and settlement_status reports where the payment itself stands.
Show child attributes
Show child attributes