curl --request POST \
--url https://api.ebrc.in/api/v1/platform-customers \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer"
}
'import requests
url = "https://api.ebrc.in/api/v1/platform-customers"
payload = {
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Rohan Mehta',
email: 'finance@suryatextiles.example.com',
type: 'customer'
})
};
fetch('https://api.ebrc.in/api/v1/platform-customers', 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.ebrc.in/api/v1/platform-customers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Rohan Mehta',
'email' => 'finance@suryatextiles.example.com',
'type' => 'customer'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <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.ebrc.in/api/v1/platform-customers"
payload := strings.NewReader("{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ebrc.in/api/v1/platform-customers")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ebrc.in/api/v1/platform-customers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"email": "jsmith@example.com",
"type": "customer",
"companyName": "<string>",
"iec": "<string>",
"address": "<string>",
"platformId": "<string>",
"mode": "test",
"isActive": true,
"hasDgftCredentials": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}Create Customer
Create a platform customer, the exporter entity you generate eBRCs for. Returns the platformCustomerId used in every later IRM and certificate generation call.
curl --request POST \
--url https://api.ebrc.in/api/v1/platform-customers \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer"
}
'import requests
url = "https://api.ebrc.in/api/v1/platform-customers"
payload = {
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer"
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'Rohan Mehta',
email: 'finance@suryatextiles.example.com',
type: 'customer'
})
};
fetch('https://api.ebrc.in/api/v1/platform-customers', 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.ebrc.in/api/v1/platform-customers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Rohan Mehta',
'email' => 'finance@suryatextiles.example.com',
'type' => 'customer'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <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.ebrc.in/api/v1/platform-customers"
payload := strings.NewReader("{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.ebrc.in/api/v1/platform-customers")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.ebrc.in/api/v1/platform-customers")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"Rohan Mehta\",\n \"email\": \"finance@suryatextiles.example.com\",\n \"type\": \"customer\"\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"email": "jsmith@example.com",
"type": "customer",
"companyName": "<string>",
"iec": "<string>",
"address": "<string>",
"platformId": "<string>",
"mode": "test",
"isActive": true,
"hasDgftCredentials": true,
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}{
"code": "<string>",
"message": "<string>"
}id is the platformCustomerId you pass to every IRM and generation endpoint.
Onboarding is two calls, not one
A client you have only created cannot file. Creation always returnsisActive: false, whatever you send in the body. The client becomes active only when its DGFT credentials are verified against the DGFT portal by Validate Customer.
Create the client
POST /platform-customers stores the exporter’s profile and returns its id. The client is inactive and has no DGFT connection.Validate the DGFT credentials
POST /platform-customers/{id}/check-dgft-credentials performs a real login against the DGFT portal. On success the DGFT connection is stored and isActive flips to true.dgftUsername and dgftPassword to this endpoint stores them but does not verify them, does not create the DGFT connection, and does not activate the client. You must still call Validate Customer. The eBRC console behaves the same way: it collects the credentials on the onboarding form and verifies them in a second step.Request example
curl --location 'https://api.ebrc.in/api/v1/platform-customers' \
--header 'Content-Type: application/json' \
--header 'x-api-key: <YOUR_API_KEY>' \
--data-raw '{
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer",
"companyName": "Surya Textile Exports Pvt Ltd",
"iec": "AAECS1234F",
"address": "Tiruppur, Tamil Nadu"
}'
Request fields
| Field | Required | Notes |
|---|---|---|
name | Yes | Contact or trade name for the exporter. |
email | Yes | Contact email. Unique per platform account, per mode. |
type | Yes | Always "customer". |
companyName | No | The exporter’s registered legal name. Required in the eBRC console. |
iec | No | Importer Exporter Code, exactly 10 alphanumeric characters, stored uppercase. Required in the eBRC console. See below. |
address | No | Free text. The eBRC console no longer collects this field, so a client onboarded through the console has no address on file. |
dgftUsername | No | Stored unverified. See the warning above. Unique per platform account, per mode. |
dgftPassword | No | Stored unverified, encrypted at rest, never returned. |
400, with one exception: id, platformId, isActive, createdAt and updatedAt are still accepted for backward compatibility and silently ignored. Do not send them. In particular, isActive: true in the body does nothing.
About the IEC
The Importer Exporter Code is the 10 character identifier DGFT issues to every Indian exporter. It is the number DGFT itself keys an exporter’s remittances and certificates on, so recording it against the client makes reconciliation between your records, ours and DGFT’s unambiguous. The API acceptsiec in any case, trims surrounding whitespace and stores it uppercase. The format is validated: exactly 10 letters and digits, no spaces or punctuation.
It is optional here so existing integrations keep working, and required in the eBRC console. Send it anyway. A client with no IEC on file is materially harder to support when a filing is queried.
Response example
Returns201 with the client in the data field of the standard envelope:
{
"success": true,
"data": {
"id": "ee849a90-7a28-49b4-8cb2-8e31041650a2",
"name": "Rohan Mehta",
"email": "finance@suryatextiles.example.com",
"type": "customer",
"companyName": "Surya Textile Exports Pvt Ltd",
"iec": "AAECS1234F",
"address": "Tiruppur, Tamil Nadu",
"platformId": "1f0c9a52-3b41-4d78-9e26-7a8b5c4d3e2f",
"mode": "live",
"isActive": false,
"hasDgftCredentials": false,
"createdAt": "2026-07-22T10:15:04.874Z",
"updatedAt": "2026-07-22T10:15:04.874Z"
},
"statusCode": 201,
"timestamp": "2026-07-22T10:15:04.901Z"
}
null. Read them back with Get Customer by Id, where an unset field comes back as null.
The client object
Every endpoint in this section returns this object.| Field | Notes |
|---|---|
id | UUID. This is the platformCustomerId for every later call. |
name, email, type | As supplied. |
companyName, iec, address | As supplied, with iec uppercased. |
platformId | Your platform account. |
mode | test or live, fixed at creation and never editable. Returned by create, update and validate; omitted by the list and get endpoints. |
isActive | false until DGFT credentials verify. |
hasDgftCredentials | Derived: true once DGFT credentials are on file. Branch on this, not on the credential fields. |
dgftApiStatus | Present once credentials are on file. Whether they can be used yet: state is ready or activation_pending; while pending, activatesAt says when. sharedCredentialsLikely is true when the exporter already held DGFT API credentials before you linked them. See the 24-hour activation. |
createdAt, updatedAt | ISO 8601 UTC. |
dev_ key creates test clients, a prod_ key creates live clients, and mode headers are ignored when a key is present. The same email can therefore exist twice under your account, once in test and once in live. Those are two different clients with two different ids. See Environments.Errors
400Validation failedwitherrors: ["email: email must be an email"]when the email fails format validation.400Validation failedwitherrors: ["iec: iec must be exactly 10 alphanumeric characters (Importer Exporter Code)"]when the IEC is not 10 letters and digits.400Validation failedwitherrors: ["<field>: property <field> should not exist"]for any property outside the table above.400User with email already existswhen that email is already on your account in this mode. The same email in the other mode, or under another platform, is not a conflict.400DGFT username already in usewhen thedgftUsernameyou sent is already linked to another of your clients in this mode.401No API key provided, orInvalid API keywhen the key is unknown or revoked. See authentication errors.403Only platform users can access this resource, orMaster Platform Agreement not signed yet. Bothdev_andprod_keys require a signed agreement before issuance.
Next steps
- Validate the customer’s DGFT credentials. This step is required, not optional.
- Fetch their IRMs once the client is active.
- Walk the whole flow in the Quick Start.
Authorizations
Body
Unique per platform account, per mode.
customer The exporter's registered legal name. Optional here, required by the eBRC console.
Importer Exporter Code: exactly 10 alphanumeric characters, accepted in any case and stored uppercase. Optional here, required by the eBRC console.
10^[A-Za-z0-9]{10}$Free text. Not collected by the eBRC console.
Optional. Stored WITHOUT verification and unique per platform account, per mode. You must still call check-dgft-credentials.
Optional. Stored WITHOUT verification, encrypted at rest, never returned.
Response
Client created, inactive until DGFT credentials are validated
Unique identifier of the platform customer. This is the platformCustomerId used in every later call.
customer The exporter's registered legal name. Required by the eBRC console, optional on this API.
Importer Exporter Code: exactly 10 alphanumeric characters, stored uppercase. Required by the eBRC console, optional on this API.
10^[A-Za-z0-9]{10}$Free text. Not collected by the eBRC console, so console-onboarded clients have none.
Platform account that owns this client
Fixed at creation from the API key prefix and never editable. Returned by create, update and validate; omitted by the list and get endpoints.
test, live Always false at creation. Becomes true only when DGFT credentials are verified by POST /platform-customers/{id}/check-dgft-credentials.
Derived: true once DGFT credentials are on file. Branch on this; the raw DGFT credential fields are not part of the response contract and the password is never returned on any surface.
Not returned by GET /platform-customers (list).