curl --request PATCH \
--url https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/ \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Version: <api-key>' \
--header 'X-Client-ID: <api-key>' \
--header 'X-Client-Secret: <api-key>' \
--form document_type=INVOICE \
--form file=@example-fileimport requests
url = "https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = { "document_type": "INVOICE" }
headers = {
"X-Client-ID": "<api-key>",
"X-Client-Secret": "<api-key>",
"X-API-Version": "<api-key>"
}
response = requests.patch(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document_type', 'INVOICE');
form.append('file', 'invoice.pdf');
const options = {
method: 'PATCH',
headers: {
'X-Client-ID': '<api-key>',
'X-Client-Secret': '<api-key>',
'X-API-Version': '<api-key>'
}
};
options.body = form;
fetch('https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/', 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/partners/merchants/{merchant_id}/documents/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"X-API-Version: <api-key>",
"X-Client-ID: <api-key>",
"X-Client-Secret: <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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-Client-ID", "<api-key>")
req.Header.Add("X-Client-Secret", "<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.patch("https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/")
.header("X-Client-ID", "<api-key>")
.header("X-Client-Secret", "<api-key>")
.header("X-API-Version", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-Client-ID"] = '<api-key>'
request["X-Client-Secret"] = '<api-key>'
request["X-API-Version"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Invoice uploaded successfully",
"data": {
"detail": "Invoice uploaded successfully"
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_001",
"message": "Validation error",
"details": {
"document_type": [
"\"RECEIPT\" is not a valid choice."
]
}
}
}{
"success": false,
"error": {
"code": "ERR_AUTH_000",
"message": "Missing credentials",
"details": {
"authentication": "Missing credentials."
}
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_017",
"message": "Sub-Merchant endpoints are only available to IMPORT PSP accounts",
"details": {}
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_016",
"message": "Sub-Merchant not found",
"details": {}
}
}Upload Merchant Invoice
Attach an invoice file to one of your sub-merchants.
curl --request PATCH \
--url https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/ \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Version: <api-key>' \
--header 'X-Client-ID: <api-key>' \
--header 'X-Client-Secret: <api-key>' \
--form document_type=INVOICE \
--form file=@example-fileimport requests
url = "https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = { "document_type": "INVOICE" }
headers = {
"X-Client-ID": "<api-key>",
"X-Client-Secret": "<api-key>",
"X-API-Version": "<api-key>"
}
response = requests.patch(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document_type', 'INVOICE');
form.append('file', 'invoice.pdf');
const options = {
method: 'PATCH',
headers: {
'X-Client-ID': '<api-key>',
'X-Client-Secret': '<api-key>',
'X-API-Version': '<api-key>'
}
};
options.body = form;
fetch('https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/', 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/partners/merchants/{merchant_id}/documents/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"X-API-Version: <api-key>",
"X-Client-ID: <api-key>",
"X-Client-Secret: <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"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("X-Client-ID", "<api-key>")
req.Header.Add("X-Client-Secret", "<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.patch("https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/")
.header("X-Client-ID", "<api-key>")
.header("X-Client-Secret", "<api-key>")
.header("X-API-Version", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-pacb-uat.eximpe.com/partners/merchants/{merchant_id}/documents/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["X-Client-ID"] = '<api-key>'
request["X-Client-Secret"] = '<api-key>'
request["X-API-Version"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document_type\"\r\n\r\nINVOICE\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\ninvoice.pdf\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "Invoice uploaded successfully",
"data": {
"detail": "Invoice uploaded successfully"
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_001",
"message": "Validation error",
"details": {
"document_type": [
"\"RECEIPT\" is not a valid choice."
]
}
}
}{
"success": false,
"error": {
"code": "ERR_AUTH_000",
"message": "Missing credentials",
"details": {
"authentication": "Missing credentials."
}
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_017",
"message": "Sub-Merchant endpoints are only available to IMPORT PSP accounts",
"details": {}
}
}{
"success": false,
"error": {
"code": "ERR_MERCHANT_016",
"message": "Sub-Merchant not found",
"details": {}
}
}Overview
Attaches an invoice to a sub-merchant you have onboarded. The request ismultipart/form-data, not JSON. Uploading again replaces the stored invoice.
The upload is accepted in any status. The invoice is not returned by Get Merchant or List Merchants.
Path Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| merchant_id | string | Yes | The sub-merchant’s ID, as returned by Create Merchant, e.g. 6182929449. |
Request Parameters
| Name | Type | Required | Description | Constraints |
|---|---|---|---|---|
| document_type | string | Yes | The kind of document. | INVOICE. No other document type is accepted. |
| file | file | Yes | The invoice file. | One of pdf, jpg, jpeg, png, csv, xlsx or docx; the file’s content must match its extension. Up to 10 MB, with a file name of up to 100 characters. A PDF must not be password-protected and must pass EximPe’s security check. |
Response
{
"success": true,
"message": "Invoice uploaded successfully",
"data": {
"detail": "Invoice uploaded successfully"
}
}
{
"success": false,
"error": {
"code": "ERR_MERCHANT_001",
"message": "Validation error",
"details": {
"document_type": ["\"RECEIPT\" is not a valid choice."]
}
}
}
Errors
Errors use the standard envelope. For a400, details lists every problem, each field mapped to a list of messages; otherwise it is an empty object. See Create Merchant.
| Status | error.code | When | details |
|---|---|---|---|
400 | ERR_MERCHANT_001 | document_type or file is missing, document_type is not INVOICE, or the file breaks a rule above | Keyed by field, each with a list of reasons, e.g. {"document_type": ["\"RECEIPT\" is not a valid choice."]}. Fix it and upload again |
401 | ERR_AUTH_000, ERR_AUTH_001 | X-Client-ID or X-Client-Secret is missing or wrong | {"authentication": "Missing credentials."} or {"authentication": "Invalid credentials."} |
403 | ERR_AUTH_003 | Your account is not a PSP | {}. Only PSPs can manage sub-merchants |
403 | ERR_MERCHANT_017 | Your account is a PSP, but not set up for import collections | {}. Contact EximPe |
404 | ERR_MERCHANT_016 | No sub-merchant with this ID belongs to you, or it has been deleted | {}. Check the ID |
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.
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
The sub-merchant's ID.
Body
multipart/form-data with the document type and the file.
The invoice file: pdf, jpg, jpeg, png, csv, xlsx or docx, up to 10 MB, with a file name of up to 100 characters. The content must match the extension. A PDF must not be password-protected and must pass EximPe's security check.
Always INVOICE. No other document type is accepted.
INVOICE