# Country Codes Source: https://docs.ebrc.in/annexure/country-codes ISO 3166-1 alpha-3 country codes returned in the remitterCountry field on IRM records, with all 249 codes by region, alpha-2 equivalents, and the look-alike codes that are easy to confuse. Every IRM record carries the country of the remitting party in the `remitterCountry` field, as an ISO 3166-1 **alpha-3** code: three letters, for example `ARE` for the United Arab Emirates and `SGP` for Singapore. This annexure lists all 249 codes assigned by the ISO 3166 Maintenance Agency. `remitterCountry` is **alpha-3, not alpha-2**. The value for the United Arab Emirates is `ARE`, not `AE`. Matching on two-letter codes will silently miss every record. ## Commonly seen codes The counterparty countries that appear most often on Indian export remittances. | Alpha-3 | Alpha-2 | Country | | ------- | ------- | ---------------------------------------------------- | | `USA` | US | United States of America | | `ARE` | AE | United Arab Emirates | | `CHN` | CN | China | | `GBR` | GB | United Kingdom of Great Britain and Northern Ireland | | `SGP` | SG | Singapore | | `HKG` | HK | Hong Kong | | `DEU` | DE | Germany | | `NLD` | NL | Netherlands, Kingdom of the | | `BGD` | BD | Bangladesh | | `SAU` | SA | Saudi Arabia | | `AUS` | AU | Australia | | `JPN` | JP | Japan | | `FRA` | FR | France | | `ITA` | IT | Italy | | `BEL` | BE | Belgium | | `KOR` | KR | Korea, Republic of | | `ZAF` | ZA | South Africa | | `CAN` | CA | Canada | | `ESP` | ES | Spain | | `VNM` | VN | Viet Nam | | `MYS` | MY | Malaysia | | `IDN` | ID | Indonesia | | `TUR` | TR | Türkiye | | `QAT` | QA | Qatar | | `CHE` | CH | Switzerland | | `NPL` | NP | Nepal | | `LKA` | LK | Sri Lanka | | `BRA` | BR | Brazil | | `MEX` | MX | Mexico | ## Codes that are easy to confuse Several alpha-3 codes are near-neighbours of each other, or of an unrelated country's alpha-2 code. These are the ones worth a second look when you map `remitterCountry` onto your own country master. | Code | Country | Not to be confused with | | ----- | -------------------------- | ---------------------------------------------------- | | `ARE` | United Arab Emirates | `ARG` Argentina, `ARM` Armenia | | `AUS` | Australia | `AUT` Austria | | `IND` | India | `IDN` Indonesia | | `IRL` | Ireland | `IRN` Iran, `IRQ` Iraq | | `CHE` | Switzerland | `CHN` China, `CHL` Chile | | `SGP` | Singapore | `SVN` Slovenia, `SVK` Slovakia, `SWE` Sweden | | `KOR` | Korea, Republic of (South) | `PRK` Korea, Democratic People's Republic of (North) | | `NER` | Niger | `NGA` Nigeria | | `MLI` | Mali | `MLT` Malta | | `ZAF` | South Africa | `SAU` Saudi Arabia | | `GBR` | United Kingdom | not `UK` — that code does not exist in ISO 3166-1 | | `DEU` | Germany | not `GER`, which is an Olympic code, not an ISO one | | `NLD` | Netherlands | not `HOL` | | `CHE` | Switzerland | not `SUI` or `SWI` | ## Full list by region Regions follow the UN M49 grouping that ISO publishes alongside 3166-1. Codes are sorted alphabetically within each region. | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | -------------------------------------- | | `AFG` | AF | 004 | Afghanistan | | `ARE` | AE | 784 | United Arab Emirates | | `ARM` | AM | 051 | Armenia | | `AZE` | AZ | 031 | Azerbaijan | | `BGD` | BD | 050 | Bangladesh | | `BHR` | BH | 048 | Bahrain | | `BRN` | BN | 096 | Brunei Darussalam | | `BTN` | BT | 064 | Bhutan | | `CHN` | CN | 156 | China | | `CYP` | CY | 196 | Cyprus | | `GEO` | GE | 268 | Georgia | | `HKG` | HK | 344 | Hong Kong | | `IDN` | ID | 360 | Indonesia | | `IND` | IN | 356 | India | | `IRN` | IR | 364 | Iran, Islamic Republic of | | `IRQ` | IQ | 368 | Iraq | | `ISR` | IL | 376 | Israel | | `JOR` | JO | 400 | Jordan | | `JPN` | JP | 392 | Japan | | `KAZ` | KZ | 398 | Kazakhstan | | `KGZ` | KG | 417 | Kyrgyzstan | | `KHM` | KH | 116 | Cambodia | | `KOR` | KR | 410 | Korea, Republic of | | `KWT` | KW | 414 | Kuwait | | `LAO` | LA | 418 | Lao People's Democratic Republic | | `LBN` | LB | 422 | Lebanon | | `LKA` | LK | 144 | Sri Lanka | | `MAC` | MO | 446 | Macao | | `MDV` | MV | 462 | Maldives | | `MMR` | MM | 104 | Myanmar | | `MNG` | MN | 496 | Mongolia | | `MYS` | MY | 458 | Malaysia | | `NPL` | NP | 524 | Nepal | | `OMN` | OM | 512 | Oman | | `PAK` | PK | 586 | Pakistan | | `PHL` | PH | 608 | Philippines | | `PRK` | KP | 408 | Korea, Democratic People's Republic of | | `PSE` | PS | 275 | Palestine, State of | | `QAT` | QA | 634 | Qatar | | `SAU` | SA | 682 | Saudi Arabia | | `SGP` | SG | 702 | Singapore | | `SYR` | SY | 760 | Syrian Arab Republic | | `THA` | TH | 764 | Thailand | | `TJK` | TJ | 762 | Tajikistan | | `TKM` | TM | 795 | Turkmenistan | | `TLS` | TL | 626 | Timor-Leste | | `TUR` | TR | 792 | Türkiye | | `TWN` | TW | 158 | Taiwan, Province of China | | `UZB` | UZ | 860 | Uzbekistan | | `VNM` | VN | 704 | Viet Nam | | `YEM` | YE | 887 | Yemen | | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | ---------------------------------------------------- | | `ALA` | AX | 248 | Åland Islands | | `ALB` | AL | 008 | Albania | | `AND` | AD | 020 | Andorra | | `AUT` | AT | 040 | Austria | | `BEL` | BE | 056 | Belgium | | `BGR` | BG | 100 | Bulgaria | | `BIH` | BA | 070 | Bosnia and Herzegovina | | `BLR` | BY | 112 | Belarus | | `CHE` | CH | 756 | Switzerland | | `CZE` | CZ | 203 | Czechia | | `DEU` | DE | 276 | Germany | | `DNK` | DK | 208 | Denmark | | `ESP` | ES | 724 | Spain | | `EST` | EE | 233 | Estonia | | `FIN` | FI | 246 | Finland | | `FRA` | FR | 250 | France | | `FRO` | FO | 234 | Faroe Islands | | `GBR` | GB | 826 | United Kingdom of Great Britain and Northern Ireland | | `GGY` | GG | 831 | Guernsey | | `GIB` | GI | 292 | Gibraltar | | `GRC` | GR | 300 | Greece | | `HRV` | HR | 191 | Croatia | | `HUN` | HU | 348 | Hungary | | `IMN` | IM | 833 | Isle of Man | | `IRL` | IE | 372 | Ireland | | `ISL` | IS | 352 | Iceland | | `ITA` | IT | 380 | Italy | | `JEY` | JE | 832 | Jersey | | `LIE` | LI | 438 | Liechtenstein | | `LTU` | LT | 440 | Lithuania | | `LUX` | LU | 442 | Luxembourg | | `LVA` | LV | 428 | Latvia | | `MCO` | MC | 492 | Monaco | | `MDA` | MD | 498 | Moldova, Republic of | | `MKD` | MK | 807 | North Macedonia | | `MLT` | MT | 470 | Malta | | `MNE` | ME | 499 | Montenegro | | `NLD` | NL | 528 | Netherlands, Kingdom of the | | `NOR` | NO | 578 | Norway | | `POL` | PL | 616 | Poland | | `PRT` | PT | 620 | Portugal | | `ROU` | RO | 642 | Romania | | `RUS` | RU | 643 | Russian Federation | | `SJM` | SJ | 744 | Svalbard and Jan Mayen | | `SMR` | SM | 674 | San Marino | | `SRB` | RS | 688 | Serbia | | `SVK` | SK | 703 | Slovakia | | `SVN` | SI | 705 | Slovenia | | `SWE` | SE | 752 | Sweden | | `UKR` | UA | 804 | Ukraine | | `VAT` | VA | 336 | Holy See | | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | -------------------------------------------- | | `AGO` | AO | 024 | Angola | | `ATF` | TF | 260 | French Southern Territories | | `BDI` | BI | 108 | Burundi | | `BEN` | BJ | 204 | Benin | | `BFA` | BF | 854 | Burkina Faso | | `BWA` | BW | 072 | Botswana | | `CAF` | CF | 140 | Central African Republic | | `CIV` | CI | 384 | Côte d'Ivoire | | `CMR` | CM | 120 | Cameroon | | `COD` | CD | 180 | Congo, Democratic Republic of the | | `COG` | CG | 178 | Congo | | `COM` | KM | 174 | Comoros | | `CPV` | CV | 132 | Cabo Verde | | `DJI` | DJ | 262 | Djibouti | | `DZA` | DZ | 012 | Algeria | | `EGY` | EG | 818 | Egypt | | `ERI` | ER | 232 | Eritrea | | `ESH` | EH | 732 | Western Sahara | | `ETH` | ET | 231 | Ethiopia | | `GAB` | GA | 266 | Gabon | | `GHA` | GH | 288 | Ghana | | `GIN` | GN | 324 | Guinea | | `GMB` | GM | 270 | Gambia | | `GNB` | GW | 624 | Guinea-Bissau | | `GNQ` | GQ | 226 | Equatorial Guinea | | `IOT` | IO | 086 | British Indian Ocean Territory | | `KEN` | KE | 404 | Kenya | | `LBR` | LR | 430 | Liberia | | `LBY` | LY | 434 | Libya | | `LSO` | LS | 426 | Lesotho | | `MAR` | MA | 504 | Morocco | | `MDG` | MG | 450 | Madagascar | | `MLI` | ML | 466 | Mali | | `MOZ` | MZ | 508 | Mozambique | | `MRT` | MR | 478 | Mauritania | | `MUS` | MU | 480 | Mauritius | | `MWI` | MW | 454 | Malawi | | `MYT` | YT | 175 | Mayotte | | `NAM` | NA | 516 | Namibia | | `NER` | NE | 562 | Niger | | `NGA` | NG | 566 | Nigeria | | `REU` | RE | 638 | Réunion | | `RWA` | RW | 646 | Rwanda | | `SDN` | SD | 729 | Sudan | | `SEN` | SN | 686 | Senegal | | `SHN` | SH | 654 | Saint Helena, Ascension and Tristan da Cunha | | `SLE` | SL | 694 | Sierra Leone | | `SOM` | SO | 706 | Somalia | | `SSD` | SS | 728 | South Sudan | | `STP` | ST | 678 | Sao Tome and Principe | | `SWZ` | SZ | 748 | Eswatini | | `SYC` | SC | 690 | Seychelles | | `TCD` | TD | 148 | Chad | | `TGO` | TG | 768 | Togo | | `TUN` | TN | 788 | Tunisia | | `TZA` | TZ | 834 | Tanzania, United Republic of | | `UGA` | UG | 800 | Uganda | | `ZAF` | ZA | 710 | South Africa | | `ZMB` | ZM | 894 | Zambia | | `ZWE` | ZW | 716 | Zimbabwe | | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | -------------------------------------------- | | `ABW` | AW | 533 | Aruba | | `AIA` | AI | 660 | Anguilla | | `ARG` | AR | 032 | Argentina | | `ATG` | AG | 028 | Antigua and Barbuda | | `BES` | BQ | 535 | Bonaire, Sint Eustatius and Saba | | `BHS` | BS | 044 | Bahamas | | `BLM` | BL | 652 | Saint Barthélemy | | `BLZ` | BZ | 084 | Belize | | `BMU` | BM | 060 | Bermuda | | `BOL` | BO | 068 | Bolivia, Plurinational State of | | `BRA` | BR | 076 | Brazil | | `BRB` | BB | 052 | Barbados | | `BVT` | BV | 074 | Bouvet Island | | `CAN` | CA | 124 | Canada | | `CHL` | CL | 152 | Chile | | `COL` | CO | 170 | Colombia | | `CRI` | CR | 188 | Costa Rica | | `CUB` | CU | 192 | Cuba | | `CUW` | CW | 531 | Curaçao | | `CYM` | KY | 136 | Cayman Islands | | `DMA` | DM | 212 | Dominica | | `DOM` | DO | 214 | Dominican Republic | | `ECU` | EC | 218 | Ecuador | | `FLK` | FK | 238 | Falkland Islands (Malvinas) | | `GLP` | GP | 312 | Guadeloupe | | `GRD` | GD | 308 | Grenada | | `GRL` | GL | 304 | Greenland | | `GTM` | GT | 320 | Guatemala | | `GUF` | GF | 254 | French Guiana | | `GUY` | GY | 328 | Guyana | | `HND` | HN | 340 | Honduras | | `HTI` | HT | 332 | Haiti | | `JAM` | JM | 388 | Jamaica | | `KNA` | KN | 659 | Saint Kitts and Nevis | | `LCA` | LC | 662 | Saint Lucia | | `MAF` | MF | 663 | Saint Martin (French part) | | `MEX` | MX | 484 | Mexico | | `MSR` | MS | 500 | Montserrat | | `MTQ` | MQ | 474 | Martinique | | `NIC` | NI | 558 | Nicaragua | | `PAN` | PA | 591 | Panama | | `PER` | PE | 604 | Peru | | `PRI` | PR | 630 | Puerto Rico | | `PRY` | PY | 600 | Paraguay | | `SGS` | GS | 239 | South Georgia and the South Sandwich Islands | | `SLV` | SV | 222 | El Salvador | | `SPM` | PM | 666 | Saint Pierre and Miquelon | | `SUR` | SR | 740 | Suriname | | `SXM` | SX | 534 | Sint Maarten (Dutch part) | | `TCA` | TC | 796 | Turks and Caicos Islands | | `TTO` | TT | 780 | Trinidad and Tobago | | `URY` | UY | 858 | Uruguay | | `USA` | US | 840 | United States of America | | `VCT` | VC | 670 | Saint Vincent and the Grenadines | | `VEN` | VE | 862 | Venezuela, Bolivarian Republic of | | `VGB` | VG | 092 | Virgin Islands (British) | | `VIR` | VI | 850 | Virgin Islands (U.S.) | | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | ------------------------------------ | | `ASM` | AS | 016 | American Samoa | | `AUS` | AU | 036 | Australia | | `CCK` | CC | 166 | Cocos (Keeling) Islands | | `COK` | CK | 184 | Cook Islands | | `CXR` | CX | 162 | Christmas Island | | `FJI` | FJ | 242 | Fiji | | `FSM` | FM | 583 | Micronesia, Federated States of | | `GUM` | GU | 316 | Guam | | `HMD` | HM | 334 | Heard Island and McDonald Islands | | `KIR` | KI | 296 | Kiribati | | `MHL` | MH | 584 | Marshall Islands | | `MNP` | MP | 580 | Northern Mariana Islands | | `NCL` | NC | 540 | New Caledonia | | `NFK` | NF | 574 | Norfolk Island | | `NIU` | NU | 570 | Niue | | `NRU` | NR | 520 | Nauru | | `NZL` | NZ | 554 | New Zealand | | `PCN` | PN | 612 | Pitcairn | | `PLW` | PW | 585 | Palau | | `PNG` | PG | 598 | Papua New Guinea | | `PYF` | PF | 258 | French Polynesia | | `SLB` | SB | 090 | Solomon Islands | | `TKL` | TK | 772 | Tokelau | | `TON` | TO | 776 | Tonga | | `TUV` | TV | 798 | Tuvalu | | `UMI` | UM | 581 | United States Minor Outlying Islands | | `VUT` | VU | 548 | Vanuatu | | `WLF` | WF | 876 | Wallis and Futuna | | `WSM` | WS | 882 | Samoa | | Alpha-3 | Alpha-2 | Numeric | Country | | ------- | ------- | ------- | ---------- | | `ATA` | AQ | 010 | Antarctica | ## Machine-readable list ```json Country Codes theme={"dark"} { "ABW": "Aruba", "AFG": "Afghanistan", "AGO": "Angola", "AIA": "Anguilla", "ALA": "Åland Islands", "ALB": "Albania", "AND": "Andorra", "ARE": "United Arab Emirates", "ARG": "Argentina", "ARM": "Armenia", "ASM": "American Samoa", "ATA": "Antarctica", "ATF": "French Southern Territories", "ATG": "Antigua and Barbuda", "AUS": "Australia", "AUT": "Austria", "AZE": "Azerbaijan", "BDI": "Burundi", "BEL": "Belgium", "BEN": "Benin", "BES": "Bonaire, Sint Eustatius and Saba", "BFA": "Burkina Faso", "BGD": "Bangladesh", "BGR": "Bulgaria", "BHR": "Bahrain", "BHS": "Bahamas", "BIH": "Bosnia and Herzegovina", "BLM": "Saint Barthélemy", "BLR": "Belarus", "BLZ": "Belize", "BMU": "Bermuda", "BOL": "Bolivia, Plurinational State of", "BRA": "Brazil", "BRB": "Barbados", "BRN": "Brunei Darussalam", "BTN": "Bhutan", "BVT": "Bouvet Island", "BWA": "Botswana", "CAF": "Central African Republic", "CAN": "Canada", "CCK": "Cocos (Keeling) Islands", "CHE": "Switzerland", "CHL": "Chile", "CHN": "China", "CIV": "Côte d'Ivoire", "CMR": "Cameroon", "COD": "Congo, Democratic Republic of the", "COG": "Congo", "COK": "Cook Islands", "COL": "Colombia", "COM": "Comoros", "CPV": "Cabo Verde", "CRI": "Costa Rica", "CUB": "Cuba", "CUW": "Curaçao", "CXR": "Christmas Island", "CYM": "Cayman Islands", "CYP": "Cyprus", "CZE": "Czechia", "DEU": "Germany", "DJI": "Djibouti", "DMA": "Dominica", "DNK": "Denmark", "DOM": "Dominican Republic", "DZA": "Algeria", "ECU": "Ecuador", "EGY": "Egypt", "ERI": "Eritrea", "ESH": "Western Sahara", "ESP": "Spain", "EST": "Estonia", "ETH": "Ethiopia", "FIN": "Finland", "FJI": "Fiji", "FLK": "Falkland Islands (Malvinas)", "FRA": "France", "FRO": "Faroe Islands", "FSM": "Micronesia, Federated States of", "GAB": "Gabon", "GBR": "United Kingdom of Great Britain and Northern Ireland", "GEO": "Georgia", "GGY": "Guernsey", "GHA": "Ghana", "GIB": "Gibraltar", "GIN": "Guinea", "GLP": "Guadeloupe", "GMB": "Gambia", "GNB": "Guinea-Bissau", "GNQ": "Equatorial Guinea", "GRC": "Greece", "GRD": "Grenada", "GRL": "Greenland", "GTM": "Guatemala", "GUF": "French Guiana", "GUM": "Guam", "GUY": "Guyana", "HKG": "Hong Kong", "HMD": "Heard Island and McDonald Islands", "HND": "Honduras", "HRV": "Croatia", "HTI": "Haiti", "HUN": "Hungary", "IDN": "Indonesia", "IMN": "Isle of Man", "IND": "India", "IOT": "British Indian Ocean Territory", "IRL": "Ireland", "IRN": "Iran, Islamic Republic of", "IRQ": "Iraq", "ISL": "Iceland", "ISR": "Israel", "ITA": "Italy", "JAM": "Jamaica", "JEY": "Jersey", "JOR": "Jordan", "JPN": "Japan", "KAZ": "Kazakhstan", "KEN": "Kenya", "KGZ": "Kyrgyzstan", "KHM": "Cambodia", "KIR": "Kiribati", "KNA": "Saint Kitts and Nevis", "KOR": "Korea, Republic of", "KWT": "Kuwait", "LAO": "Lao People's Democratic Republic", "LBN": "Lebanon", "LBR": "Liberia", "LBY": "Libya", "LCA": "Saint Lucia", "LIE": "Liechtenstein", "LKA": "Sri Lanka", "LSO": "Lesotho", "LTU": "Lithuania", "LUX": "Luxembourg", "LVA": "Latvia", "MAC": "Macao", "MAF": "Saint Martin (French part)", "MAR": "Morocco", "MCO": "Monaco", "MDA": "Moldova, Republic of", "MDG": "Madagascar", "MDV": "Maldives", "MEX": "Mexico", "MHL": "Marshall Islands", "MKD": "North Macedonia", "MLI": "Mali", "MLT": "Malta", "MMR": "Myanmar", "MNE": "Montenegro", "MNG": "Mongolia", "MNP": "Northern Mariana Islands", "MOZ": "Mozambique", "MRT": "Mauritania", "MSR": "Montserrat", "MTQ": "Martinique", "MUS": "Mauritius", "MWI": "Malawi", "MYS": "Malaysia", "MYT": "Mayotte", "NAM": "Namibia", "NCL": "New Caledonia", "NER": "Niger", "NFK": "Norfolk Island", "NGA": "Nigeria", "NIC": "Nicaragua", "NIU": "Niue", "NLD": "Netherlands, Kingdom of the", "NOR": "Norway", "NPL": "Nepal", "NRU": "Nauru", "NZL": "New Zealand", "OMN": "Oman", "PAK": "Pakistan", "PAN": "Panama", "PCN": "Pitcairn", "PER": "Peru", "PHL": "Philippines", "PLW": "Palau", "PNG": "Papua New Guinea", "POL": "Poland", "PRI": "Puerto Rico", "PRK": "Korea, Democratic People's Republic of", "PRT": "Portugal", "PRY": "Paraguay", "PSE": "Palestine, State of", "PYF": "French Polynesia", "QAT": "Qatar", "REU": "Réunion", "ROU": "Romania", "RUS": "Russian Federation", "RWA": "Rwanda", "SAU": "Saudi Arabia", "SDN": "Sudan", "SEN": "Senegal", "SGP": "Singapore", "SGS": "South Georgia and the South Sandwich Islands", "SHN": "Saint Helena, Ascension and Tristan da Cunha", "SJM": "Svalbard and Jan Mayen", "SLB": "Solomon Islands", "SLE": "Sierra Leone", "SLV": "El Salvador", "SMR": "San Marino", "SOM": "Somalia", "SPM": "Saint Pierre and Miquelon", "SRB": "Serbia", "SSD": "South Sudan", "STP": "Sao Tome and Principe", "SUR": "Suriname", "SVK": "Slovakia", "SVN": "Slovenia", "SWE": "Sweden", "SWZ": "Eswatini", "SXM": "Sint Maarten (Dutch part)", "SYC": "Seychelles", "SYR": "Syrian Arab Republic", "TCA": "Turks and Caicos Islands", "TCD": "Chad", "TGO": "Togo", "THA": "Thailand", "TJK": "Tajikistan", "TKL": "Tokelau", "TKM": "Turkmenistan", "TLS": "Timor-Leste", "TON": "Tonga", "TTO": "Trinidad and Tobago", "TUN": "Tunisia", "TUR": "Türkiye", "TUV": "Tuvalu", "TWN": "Taiwan, Province of China", "TZA": "Tanzania, United Republic of", "UGA": "Uganda", "UKR": "Ukraine", "UMI": "United States Minor Outlying Islands", "URY": "Uruguay", "USA": "United States of America", "UZB": "Uzbekistan", "VAT": "Holy See", "VCT": "Saint Vincent and the Grenadines", "VEN": "Venezuela, Bolivarian Republic of", "VGB": "Virgin Islands (British)", "VIR": "Virgin Islands (U.S.)", "VNM": "Viet Nam", "VUT": "Vanuatu", "WLF": "Wallis and Futuna", "WSM": "Samoa", "YEM": "Yemen", "ZAF": "South Africa", "ZMB": "Zambia", "ZWE": "Zimbabwe" } ``` ## Usage guidelines * Alpha-3 codes are exactly three uppercase letters (`string(3)`) * Alpha-2 is the two-letter form of the same standard, listed above for cross-referencing with systems that use it; it is **not** what `remitterCountry` returns * Numeric-3 is the UN M49 numeric form, listed for reference; it is language-independent and stable across renamings * Country names are reproduced exactly as ISO publishes them, so some read formally, for example `KOR` is "Korea, Republic of" and `VNM` is "Viet Nam" * `remitterCountry` is **read-only reference data**. It originates from the remitting bank's advice, reaches us through DGFT, and is stored exactly as received — you never send it * When DGFT returns an IRM with no country on it, the field is stored as the literal string `UNKNOWN`. Treat `UNKNOWN` as "not supplied", not as a country code * Do not assume the code is present in the ISO list before you look it up. Fall back to displaying the raw value rather than dropping the record * The remitter's country is independent of the remittance currency. A remitter in `ARE` routinely settles in `USD`; see [Currency Codes](/annexure/currency-codes) * ISO 3166-1 is amended over time. Codes are withdrawn when a country ceases to exist or renames, and withdrawn codes are not reassigned for at least 50 years * Historical remittances can therefore carry a code that is no longer current. Keep withdrawn codes in your lookup rather than rejecting them * User-assigned codes (`AAA`-`AAZ`, `QMA`-`QZZ`, `XAA`-`XZZ`, `ZZA`-`ZZZ`) are never issued by ISO and should not appear in this field ## Used by * `remitterCountry` on every IRM record returned by [Fetch IRM List](/api-reference/irm/post) and [List Saved IRMs](/api-reference/irm/list) * The Remitter Country column in the IRM Excel export Source: [ISO 3166 Country Codes](https://www.iso.org/iso-3166-country-codes.html), maintained by the ISO 3166 Maintenance Agency · Last reviewed: 17 August 2026 # Currency Codes Source: https://docs.ebrc.in/annexure/currency-codes ISO 4217 currency codes accepted in eBRC and IRM requests for the irmFCC and sbCumInvoiceFCC fields, including historical currencies kept for older remittances. Complete list of currency codes used in foreign exchange transactions. These codes follow the ISO 4217 standard and identify the currency of a transaction in fields such as `irmFCC` and `sbCumInvoiceFCC`. ```json Currency Codes theme={"dark"} { "USD": "US Dollars", "DEM": "Deutsch Mark", "SGD": "Singapore Dollar", "CHF": "Swiss Franc", "GBP": "Pound Sterling", "JPY": "Japanese Yen", "HKD": "Hong Kong Dollar", "EUR": "EURO", "ITL": "Italian Lira", "FRF": "French Franc", "AUD": "Australian Dollar", "SEK": "Swedish Kroner", "CAD": "Canadian Dollar", "BEF": "Belgian Franc", "DKK": "Danish Kroner", "FIM": "Finish Markka", "NOK": "Norwegian Kroner", "ATS": "Austrian Schilling", "INR": "Indian Rupees", "NLG": "Dutch Guilder", "ACU": "Asian Clearing Union Dollar", "NZD": "New Zealand Dollar", "BHD": "Bahraini Dinar", "SAR": "Saudi Arabian Riyal", "ZAR": "South African Rand", "AED": "UAE Dirham", "KES": "Kenya Shilling", "KWD": "Kuwaiti Dinar", "THB": "Thai Bhat", "CNY": "Chinese Yuan", "EGP": "Egyptian Pound", "IDR": "Indonesian Rupiah", "KRW": "Korean Won", "MYR": "Malaysian Ringgi", "OMR": "Omani Rial", "QAR": "Qatari Riyal", "RUB": "Russian Ruble", "AFA": "Afghani", "ALL": "Lek", "DZD": "Algeria Dinar", "AON": "Kwanza", "ARS": "Argentina Peso", "AMD": "Dram", "ILS": "New Shekel", "JMD": "Jamaica Dollar", "JOD": "Jordan Dinar", "KZT": "Tenge", "KPW": "Won (North Korea)", "LAK": "New Kip", "LBP": "Lebanon Pound", "LSL": "Maluti", "LRD": "Liberia Dollar", "LYD": "Libya Dinar", "LTL": "Litas", "MGF": "Madagascar Franc", "MWK": "Kwacha", "MVR": "Rufiya", "MRO": "Ouguiya", "MUR": "Mauritius Rupee", "MXN": "Peso (Mexico)", "MNT": "Tugrik", "MAD": "Morocco Dirham", "BSD": "Bahama Dollar", "BDT": "Taka", "BBD": "Barbados Dollar", "BYB": "Belarus Rouble", "BZD": "Belize Dollar", "XOF": "West African CFA franc", "BMD": "Bermuda Dollar", "BOB": "Boliviano", "BWP": "Pula", "BRL": "Real", "BND": "Brunei Dollar", "BGL": "Lev", "MMK": "Kyat", "BIF": "Burundi Franc", "KHR": "Rial (Cambodia)", "CLP": "Chile Peso", "COP": "Colombia Peso", "XAF": "Central African CFA franc", "ZRN": "Congolese Francs", "CRC": "Colon (Costa Rica)", "HRK": "Kuna", "CUP": "Cuba Peso", "CZK": "Koruna", "DJF": "Djibouti Franc", "DOP": "Dominican Peso", "ECS": "Sucre", "SVC": "Colon (El Salvador)", "ETB": "Birr", "FKP": "Falkland Pound", "FJD": "Fiji Dollar" } ``` **For eBRC applications** * Use the appropriate currency code when filing eBRC (Electronic Bank Realisation Certificate) applications * Ensure the currency code matches the actual currency of the foreign exchange transaction * Refer to ISO 4217 standard for the most up-to-date currency codes **Code format** * Currency codes follow the ISO 4217 standard (3-letter codes) * First two letters typically represent the country * Third letter usually represents the currency name **Important notes** * Currency codes are mandatory for all foreign exchange transactions * Always refer to the latest RBI circulars for any updates to currency codes * Use current, active currency codes for new transactions ## Historical currencies The list above includes codes for currencies that have since been replaced, kept for historical remittances: `DEM` (Deutsch Mark), `ITL` (Italian Lira), `FRF` (French Franc), `BEF` (Belgian Franc), `FIM` (Finnish Markka), `ATS` (Austrian Schilling), and `NLG` (Dutch Guilder) were all replaced by `EUR`. Use current, active codes for new transactions. ## Used by * [`irmFCC` and `sbCumInvoiceFCC`](/annexure/push-irm) in the Push IRM request fields * [Submit IRMs for eBRC Generation](/api-reference/genebrc/push-irm) * The IRM FCC and SB Cum Invoice FCC columns in [Bulk Upload via Excel](/api-reference/genebrc/bulk-upload) Source: [ISO 4217 currency codes](https://www.iso.org/iso-4217-currency-codes.html) · Last reviewed: 22 July 2026 # Port Codes Source: https://docs.ebrc.in/annexure/port-codes Indian port codes for the portCode field: sea ports, airports, container depots, land customs stations, and SEZs, in UN/LOCODE format with facility suffixes. Complete list of Indian port codes used in import and export transactions. These are standardized identifiers for ports, airports, inland container depots (ICDs), land customs stations (LCS), and special economic zones (SEZ) across India, used in the `portCode` field. Codes follow the UN/LOCODE format: `IN` + 3-character location + facility type. Suffixes: 1 = Sea Port, 2 = Rail, 4 = Airport, 6 = ICD/CFS, B = Land Customs Station. Example: `INMAA1` is Chennai Sea Port. ```json Port Codes theme={"dark"} { "INADC6": "Dascroi AHMEDABAD", "INAGTB": "AGARTALA LCS", "INAIG6": "GE PVT. LTD", "INAIK6": "KHURJA ICD", "INAIP6": "ICBPPL EDAYANCHAVADI", "INAIR6": "SPPL PVT. LTD", "INAJJ6": "ARAKKANOM ICD", "INAKV6": "ANKALESHWAR ICD", "INALA1": "ALANG SEA", "INAMD4": "AHEMDABAD AIR ACC", "INAMG6": "AMINGAON ICD", "INAPL6": "ALBRATOS CFS PVT. LTD. ICD", "INASR2": "AMRITSAR RAIL CARGO", "INASR6": "CHEHERTA ICD", "INATQ4": "AMRITSAR ACC", "INATRB": "ATTARI ROAD", "INAWW6": "WIDL AEZ AURANGABAD", "INAZK1": "AZHIKKAL PORT", "INBAW6": "BAWAL ICD", "INBBI4": "BHUBANESWAR AIR CARGO", "INBDI6": "BADDI ICD", "INBDM6": "SONEPAT ICD", "INBED1": "BEDI PORT SEA", "INBEY1": "BEYPORE PORT", "INBFR6": "PIYALA ICD", "INBGK6": "CONCOR JODHPUR ICD", "INBGMB": "LCS Baghmara", "INBGUB": "BAIRGANIA", "INBHL6": "BHILWARA ICD", "INBHS6": "STERLING BHARUCH", "INBHU1": "BHAVNAGAR SEA", "INBKT1": "BANKOT PORT", "INBLE6": "BALASORE Concor ICD", "INBLJ6": "AGRA ICD", "INBLO6": "ICD BALLI", "INBLR4": "BANGALORE ACC", "INBMA6": "APIIC PRAKASHAM", "INBNG6": "TARAPUR ICD", "INBNK6": "KOLKATA IT PARK", "INBNRB": "BHIMNAGAR", "INBNT6": "TCS", "INBNYB": "BEHRNI LCS", "INBOA6": "ICD BORKHEDI", "INBOK6": "BORKHEDI ICD", "INBOLB": "LCS Bholaganj", "INBOM1": "MUMBAI CUSTOM HOUSE SEA", "INBOM4": "SAHAR AIR CARGO ACC", "INBRAB": "LCS Borsora", "INBRC6": "DASHRATH VADODRA ICD", "INBRL6": "Vadodaara", "INBSAB": "BANBASA LCS", "INBSL6": "BHUSAWAL ICD", "INBTMB": "BHITAMORE", "INBUL6": "AN FTWZ BULANDSHAHR", "INBVC6": "BALLABGARH CONCOR ICD", "INBWD6": "BHIWADI ICD", "INBWS6": "AFS Kapashera", "INCBDB": "CHANGRABANDHA", "INCBS6": "SE&C COIMBATORE", "INCCH6": "CHINCHWAD PUNE ICD", "INCCJ4": "CALICUT ACC", "INCCN6": "INFOSYS HINJAWADI", "INCCP6": "CHINCHWAD", "INCCQ6": "M/S QB PARK LTD", "INCCU1": "KOLKATA SEA", "INCCU4": "KOLKATA ACC", "INCCW6": "WIPRO LTD", "INCDC6": "RGT PARK PHASE-II", "INCDD6": "RGT PARK PHASE-I", "INCDL1": "CUDDALORE PORT", "INCDR6": "SUN PHARMACEUTICALS", "INCGA6": "MWCD APARELS CHENGPA", "INCGL6": "MWCD AUTO ANCILARIES", "INCHE6": "CHETTIPALAYM ICD", "INCHJ6": "WARDHA ICD", "INCHMB": "CHAMURCHI", "INCJB4": "COIMBATORE ACC", "INCJF6": "FTIL SRIPERUMBUDUR", "INCJO6": "SIPCOT ORAGADAM SRIP", "INCJS6": "SIPCOT SRIPERUMBUDUR", "INCML6": "KHATUWAS ICD", "INCNN4": "ACC KANNUR", "INCOK1": "COCHIN SEA", "INCOK4": "COCHIN AIR CARGO ACC", "INCPC6": "CHAKERI KANPUR ICD", "INCPL6": "CMA CGM LOGISTICS PARK ICD", "INCPR6": "CHAWAPAYAL ICD", "INCRXB": "LOKSAN LCS", "INCTY6": "LINGOJUGUDEM", "INDAH1": "DAHEJ PORT SEA", "INDDL6": "PSWC DHANDARI KALAN LUDHIANA", "INDEA6": "AS PVT. LTD.", "INDEH6": "HCL TECH. LTD. DEV.", "INDEL4": "DELHI AIR CARGO ACC", "INDEN6": "M/S NIIT TECH. LTD.", "INDER6": "DADRI ICD", "INDES6": "M/S SEAVIEW DEV. LTD", "INDEW6": "M/S WIPRO LTD.", "INDHA6": "DHANNAD ICD", "INDHP1": "DABHOL PORT", "INDHU1": "DHAHANU PORT", "INDIG1": "DIGHI PORT", "INDIG6": "DIGHI ICD", "INDLAB": "DHARCHULA LCS", "INDLOB": "BIRPARA", "INDLUB": "LCS Dalu", "INDMA1": "DHAMRA PORT SEA", "INDMT1": "DHARMATAR PORT MUMBAI", "INDPC4": "PCCCC BANDRA-KURLA COMPLEX", "INDPR6": "DAPPAR ICD", "INDRGB": "DARRANGA LCS", "INDRU6": "DESUR ICD", "INDUR6": "DURGAPUR ICD", "INDWKB": "LCS Dawki", "INDWN6": "JATTIPUR ICD", "INENR1": "KAMARAJAR PORT", "INFBD6": "BALLABGARH ICD", "INFBRB": "FULBARI", "INFMA6": "APIICL MEDAK", "INGAIB": "LCS GAURIPHANTA", "INGALB": "GALGALIA", "INGAU4": "GUWAHATI AIR CARGO", "INGDM6": "MF PARK PVT LTD", "INGED2": "LCS GEDE RAILWAY STATION", "INGGD6": "DLF LTD.", "INGGI6": "GURGAON", "INGGU6": "URP LTD.", "INGGV1": "GANGAVARAM PORT SEA", "INGHPB": "LCS Ghasuapara", "INGHR6": "GARI HARSARU ICD", "INGNI6": "MAHAPE", "INGNR6": "MARRIPALAM ICD", "INGOI4": "GOA ACC", "INGOX4": "ACC MOPA", "INGPL6": "ICDPLIL GHUNGRANA", "INGPR1": "GOPALPUR PORT", "INGRW6": "BHAMBOLI ICD", "INGTI6": "Medchal Malkagiri 500088", "INHAS6": "ICD HASSAN", "INHBL6": "EMBASSY PROPERTY DEV", "INHDD6": "PANTNAGAR ICD", "INHEL6": "L&T REALTY DEVELOPER", "INHIR6": "HIRA BORUSE SURAT ICD", "INHLD2": "HALDIBARI RAILWAY STATION", "INHLIB": "HILLI LCS", "INHND1": "HEMNAGAR LCS", "INHPI6": "KASHIPUR ICD", "INHSU6": "HOSUR ICD", "INHTSB": "LCS Hatisar", "INHYC6": "RAIDURG", "INHYD4": "HYDERABAD ACC", "INHZA1": "HAZIRA PORT SURAT", "INIDR4": "INDORE ACC", "INIDR6": "Indore", "INIGU6": "IRUGUR ICD", "INILP6": "IRUNGATTUKOTTAI ICD", "ININD6": "PITHAMPUR ICD", "INIXE1": "OLD MANGALORE PORT", "INIXE4": "MANGALORE AIR CARGO", "INIXM4": "MADURAI AIR CARGO", "INIXW6": "JAMSHEDPUR ICD", "INIXY1": "KANDLA SEA", "INIXZ1": "SEA PORT- PORT BLAIR", "INJAI4": "JAIPUR ACC", "INJAI6": "JAIPUR ICD", "INJAK1": "JAKHAU PORT", "INJAYB": "JAYANAGAR", "INJBNB": "JOGBANI", "INJGA4": "JAMNAGAR AIR CARGO", "INJGD1": "JAIGARH PORT MAHARASHTRA", "INJHOB": "JHULAGHAT LCS", "INJIGB": "LCS JAIGAON", "INJJK6": "JAJPUR ICD", "INJKA6": "SACHANA ICD", "INJNR4": "JANORI ACC", "INJNR6": "JANORI ICD", "INJSG6": "CONCOR ICD JHARSUGUDA", "INJUC6": "JALANDHAR ICD", "INJUX6": "RAJSICO BASNI JODNPUR ICD", "INKAK1": "KAKINADA SEA", "INKAR6": "KARUR ICD", "INKAT1": "KATTUPALLI PORT SEA", "INKBC6": "KRIBHCO SURAT ICD", "INKCG6": "Uppal Hyderabad 500039", "INKDN1": "KODINAR PORT", "INKGJ1": "KARIMGANJ LCS", "INKGJB": "LCS Karimganj Steamerghat", "INKHD6": "ICD KHEDA", "INKJIB": "PIPRAUN", "INKKU6": "KANAKPURA ICD", "INKLK6": "KINFRA KANAYANNOOR", "INKMAB": "LCS KULKULI", "INKML6": "DEIPL KURUBARAPALLI", "INKNLB": "KUNAULI", "INKNU6": "JRY KANPUR ICD", "INKPK6": "MIHAN ICD", "INKQZ6": "SATTVA BENGALURU ICD", "INKRI1": "KRISHNAPATNAM PORT SEA", "INKRK1": "KARAIKAL SEA PORT", "INKRM6": "MADC LTD", "INKRW1": "KARWAR PORT", "INKSH1": "KELSHI PORT", "INKTT6": "KOTA ICD", "INKTY6": "CHEYYAR POCHAMPALLI", "INKUK1": "KOLLAM PORT SEA", "INKWAB": "LCS KHUNWA", "INKWGB": "LCS Khowaighat", "INKYM6": "KOTTAYAM ICD", "INLDH6": "ICD CONCOR DHANDARI KALAN LUDHIANA", "INLGL1": "Maia Riverine Port", "INLKO4": "LUCKNOW AIR CARGO", "INLKQB": "LAUKAHA", "INLOK4": "LUCKNOW AIR CARGO", "INLON6": "LONI ICD", "INLPA6": "PHOENIX INFOCITY PVT", "INLPB6": "BBLLP NANAKRAMGUDA", "INLPF6": "PHOENIX VENTURES PL", "INLPM6": "MDL NANAKRAMGUDA", "INLPN6": "PHOENIX TECH ZONE115", "INLPP6": "PUPPALGUDA", "INLPS6": "D NSL IP LTD", "INMAA1": "CHENNAI SEA", "INMAA4": "CHENNAI AIR CARGO ACC", "INMAE6": "EC OF TAMIL NADU", "INMBD6": "PAKWARA MORADABAD ICD", "INMBS6": "MADHOSINGH ICD", "INMDA1": "MAGDALA PORT SEA", "INMDD6": "MANDIDEEP ICD", "INMDG6": "VERNA ICD", "INMDU6": "KERN ICD MADURAI", "INMEM6": "RCPL MUPPIREDDYPALLE", "INMGHB": "LCS Mehendraganj", "INMHDB": "MAHADIPUR LCS", "INMHGB": "MUHURIGHAT LCS", "INMKCB": "LCS Mankachar", "INMNUB": "LAND CUSTOMS STATION MANU", "INMPR6": "MALANPUR ICD", "INMREB": "MOREH LCS", "INMRM1": "GOA PORT SEA", "INMUN1": "MUNDRA SEA", "INMUZ6": "MODINAGAR ICD", "INMWA6": "MALIWADA ICD", "INNAG4": "NAGPUR AIR CARGO", "INNAV1": "NAVLAKHI PORT", "INNDB6": "YTPL INDORE", "INNGB6": "BUTIBORI ICD", "INNGKB": "LCS NAGARKATA", "INNGP6": "NAGPUR ICD", "INNGRB": "LCS Nepalgunj Road", "INNJP6": "DABGRAM ICD", "INNML1": "MANGALORE SEA", "INNPK6": "NANDIAMBAKKAM", "INNPT1": "NAGAPATTINAM CUSTOM HOUSE SEA", "INNRP6": "AA LTD", "INNSA1": "NHAVA SHEVA SEA", "INNSK6": "CFS NASIK ICD", "INNTVB": "LCS Thoothibari", "INNYP6": "APIIC LTD", "INNZM6": "TCS NOIDA", "INOKH1": "OKHA PORT", "INOMU1": "OLD MUNDRA PORT", "INPAN1": "PANAJI PORT", "INPAV1": "PIPAVAV - VICTOR PORT GUJARAT SEA", "INPBD1": "PORBANDAR PORT", "INPBLB": "KAMARDWISA LCS", "INPEK6": "Pune", "INPKR6": "PALI ICD REWARI", "INPMP6": "PIMPRI ICD", "INPNE6": "NT PVT. LTD", "INPNK6": "PANKI ICD", "INPNP6": "PANIPAT ICD", "INPNQ4": "PUNE AIR CARGO", "INPNTB": "PANITANKI-NAXALBARI", "INPNU6": "TMSF PVT. LTD", "INPNV6": "ICD Panvel", "INPNY1": "PONDICHERRY CUSTOM HOUSE SEA", "INPNY6": "GFPULICHAPALLAM ICD", "INPPG6": "PATPARGANJ ICD", "INPRK6": "ICD POWARKHEDA", "INPRT1": "PARADEEP PORT SEA", "INPTL6": "PATLI ICD", "INPTPB": "PETRAPOLE", "INPUM6": "MIDC PUNE", "INPWL6": "PALWAL ICD", "INQRH6": "HTPL ICD KILARAIPUR", "INQRP6": "KILARAIPUR ADANI ICD", "INRAI6": "RAIPUR ICD", "INRDP2": "RADHIKAPUR RAILWAY STATION", "INREA6": "REWARI ICD", "INRED1": "REDI PORT", "INRGJ2": "RAIGANJ LCS", "INRML6": "NAYA RAIPUR CONCOR ICD", "INRNG2": "RANAGHAT RAILWAY STATION NADIA", "INRNR1": "RANPAR PORT RATNAGIRI MAHARASHTRA", "INRTM6": "RATLAM ICD", "INRUG6": "BARHI ICD", "INRVD1": "REVDANDA PORT", "INRXLB": "RAXAUL", "INSAC6": "SACHIN ICD", "INSAJ6": "TUMB ICD", "INSAL1": "SALAYA PORT GUJRAT", "INSAU6": "THAR DRY PORT ICD/AHMEDABAD GUJARAT ICD", "INSBI6": "AHEMDABAD ICD", "INSBL6": "BENGALURU", "INSCA6": "SUSTAIN PROPERTIES P", "INSCB6": "TML BAHADURPALLY", "INSGF6": "GRFL SAHNEWAL LUDHIANA ICD", "INSIK1": "SIKKA PORT", "INSKD6": "KALINGANAGAR ICD", "INSMPB": "SRIMANTAPUR LCS", "INSNBB": "SONABARSA", "INSNF6": "HYDERABAD ICD", "INSNG2": "SINGHABAD RAILWAY STATION MALDA", "INSNI6": "KANECH SAHNEWAL ICD", "INSNLB": "SONAULI LCS", "INSNN6": "APIIC LTD.", "INSTT6": "STARTRACK TERMINAL ICD", "INSTV4": "SDB Diamond Bourse", "INSTV6": "Gujarat", "INSXR4": "SRINAGAR AIR CARGO", "INTCR6": "THRISSUR ICD", "INTDE6": "THUDIALUR ICD", "INTEN6": "SIPCOT GANGAKONDAN", "INTGN6": "KEIPL/ PUNE", "INTHA6": "THAR DRY PORT JODHPUR ICD", "INTHO6": "VEERAPANDI ICD", "INTKD6": "TUGLAKABAD ICD", "INTKNB": "TIKONIA LCS", "INTLG6": "TALEGAON PUNE ICD", "INTLT6": "L&T SBL L&T CHENNAI", "INTMX6": "THIMMAPUR ICD", "INTRV4": "TRIVANDRUM ACC", "INTRZ4": "TIRUCHIRAPALLI AIR CARGO", "INTTP6": "TRIDENT TERMINAL PVT. LTD. ICD", "INTTS1": "SHED KIDDERPORE TT", "INTUN1": "TUNA PORT", "INTUP6": "RAAKIYAPALAYAM ICD", "INTUT1": "TUTICORIN SEA", "INTUT6": "TUTICORIN ICD", "INTVT6": "TONDIAPET ICD", "INURG6": "GMR HYDTABAD AVIATIO", "INVAD1": "VADINAR PORT", "INVGR6": "VIRAMGAM ICD", "INVKH6": "HIRANANDANI BUIL", "INVKNB": "VALMIKINAGAR", "INVLR6": "SIPCOT LTD", "INVNS4": "VARANASI AIR CARGO", "INVPI6": "VAPI ICD", "INVRM6": "ICD VARNAMA", "INVTC6": "CHEYYAR VELLORE", "INVTZ1": "VIZAG SEA", "INVTZ4": "VISHAKHAPATNAM AIR CARGO", "INVYD1": "VIJAYDURG PORT", "INVZJ1": "VIZHINJAM PORT", "INWAL6": "WALUJ ICD", "INWDH6": "ICD MORBI", "INWFD6": "BANGALORE ICD", "INLNT6": "LARSEN & TOUBRO Ltd SEZ", "INEYE6": "3rd EYE VOICE SEZ", "INCND6": "CANDOR ONE HTSPL", "INNSL6": "NSL SEZ Pvt Ltd (HYD)", "INIFS6": "Infosys Ltd SEZ Pocharam" } ``` **For eBRC applications** * Use the appropriate port code when filing eBRC (Electronic Bank Realisation Certificate) applications * Ensure the port code matches the actual port of export/import mentioned in shipping documents * Port codes are mandatory fields in customs declarations and shipping bills **Code format** * Port codes follow the UN/LOCODE standard format * Format: 2-letter country code (IN for India) + 3-character location code + optional 1-digit facility type * Example: `INMAA1` - Chennai Sea Port (IN=India, MAA=Chennai, 1=Sea Port) * Facility type suffixes: 1=Sea Port, 2=Rail, 4=Airport, 6=ICD/CFS, B=Land Customs Station **Important notes** * Port codes are mandatory for all import/export transactions * Use the correct port code that matches your actual point of entry/exit * ICDs (Inland Container Depots) have different codes from sea ports * Always verify the port code with your customs broker or shipping agent * Incorrect port codes may lead to delays in customs clearance ## Used by * [`portCode`](/annexure/push-irm) in the Push IRM request fields * [Submit IRMs for eBRC Generation](/api-reference/genebrc/push-irm) * The Port Code column in [Bulk Upload via Excel](/api-reference/genebrc/bulk-upload) Source: [UN/LOCODE](https://unece.org/trade/uncefact/unlocode) via the Indian Customs EDI System and [DGFT](https://www.dgft.gov.in/) · Last reviewed: 22 July 2026 # Purpose Codes Source: https://docs.ebrc.in/annexure/purpose-codes RBI purpose codes for inward remittance used in the irmPurposeCode field, grouped by category, with the export codes most commonly used to file an eBRC. Complete list of purpose codes for inward remittance as per RBI guidelines. These codes categorize the nature of a foreign exchange transaction and are used in the `irmPurposeCode` field. Export transactions most commonly use category 01 codes, for example `P0101` for negotiated export bills and `P0103` for advance receipts. ## Purpose codes by category | Code | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **P0101** | Value of export bills negotiated / purchased / discounted (covered under GR/PP/SOFTEX/EC copy of shipping bills etc.) other than Nepal and Bhutan | | **P0102** | Realisation of export bills (goods) sent on collection, other than Nepal and Bhutan | | **P0103** | Advance receipts against export contracts, to be covered later by GR/PP/SOFTEX/SDF, other than Nepal and Bhutan | | **P0104** | Receipts against export of goods not covered by GR/PP/SOFTEX/EC copy (e.g., intermediary/transit trade) | | **P0108** | Goods sold under merchanting / receipts against export leg of merchanting trade | | **P0109** | Export realisation on account of exports to Nepal and Bhutan | | Code | Description | | --------------- | --------------------------------------------------------------------------------- | | **P0201** | Surplus freight/passenger fare by Indian shipping companies operating abroad | | **P0202** | Operating expenses of foreign shipping companies in India | | **P0205** | Operational leasing (with crew), Shipping companies | | **P0207** | Surplus freight/passenger fare by Indian Airlines operating abroad | | **P0208** | Operating expenses of foreign Airlines in India | | **P0214-P0226** | Receipts on account of transportation services, postal & courier (sea/air/others) | | Code | Description | | --------------- | --------------------------------------------------------------------------------------------------- | | **P0301** | Purchases towards travel (foreign TCs, currency notes, TT/SWIFT transfers, NR accounts, etc.) | | **P0302** | Business travel | | **P0304** | Medical travel receipts (including TCs purchased by hospitals) | | **P0305** | Travel for education (fees/receipts by educational institutions) | | **P0306-P0308** | Other travel-related receipts, including surrender of foreign currency by returning Indian tourists | | Code | Description | | --------- | -------------------------------------------------------------- | | **P0501** | Services relating to cost of construction of projects in India | | **P0502** | Construction works abroad by Indian companies | | Code | Description | | --------------- | --------------------------------------------------------------------------------------------------------------------- | | **P0601-P0612** | Life insurance premiums, freight insurance, reinsurance, auxiliary services, claims, pension entitlements, guarantees | | Code | Description | | --------------- | ------------------------------------------------------------------ | | **P0701-P0703** | Banking charges, investment banking, custodial/depository services | | Code | Description | | --------------- | ----------------------------------------------------------------------------------- | | **P0801-P0809** | IT consultancy, software exports (SOFTEX), telecom, satellite, news agency services | | Code | Description | | --------------- | ----------------------------------------------------------------------- | | **P0901-P0902** | Franchise services, receipts for use of patents, trademarks, copyrights | | Code | Description | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **P1002-P1099** | Trade-related commissions, leasing, legal, accounting, consultancy, advertising, R\&D, engineering, architecture, mining, technical, wholesale & retail trade, etc. | | Code | Description | | --------------- | ----------------------------------------------------------------------------- | | **P1101-P1109** | Audio-visual, broadcasting, entertainment, sports, education, health services | | Code | Description | | ---------------- | --------------------------------------------------------------------- | | **P1201, P1203** | Maintenance of foreign embassies, international institutions in India | | Code | Description | | --------- | --------------------------------- | | **P1505** | Deemed Exports (SEZ, EPZs & DTAs) | | Code | Description | | ---------------- | ------------------------------------------------------------- | | **P1601, P1602** | Maintenance/repair services for vessels, aircraft, spacecraft | | Code | Description | | --------- | ------------------- | | **P1701** | Processing of goods | ## Usage guidelines * Use the appropriate purpose code when filing eBRC (Electronic Bank Realisation Certificate) applications * Ensure the purpose code matches the actual nature of the foreign exchange transaction * Refer to RBI guidelines for detailed descriptions of each code * Main categories are numbered (01, 02, 03, etc.) * Specific purpose codes follow the format P0XXX * Some entries above summarize a range (e.g., P0214-P0226); refer to the linked RBI source for each individual code within a range * Purpose codes are mandatory for all foreign exchange transactions * Incorrect purpose code selection may lead to regulatory issues * Always refer to the latest RBI circulars for any updates to these codes ## Used by * [`irmPurposeCode`](/annexure/push-irm) in the Push IRM request fields * [Submit IRMs for eBRC Generation](/api-reference/genebrc/push-irm) * The IRM Purpose Code column in [Bulk Upload via Excel](/api-reference/genebrc/bulk-upload) Source: [RBI purpose codes for inward remittance](https://www.rbi.org.in/) · Last reviewed: 22 July 2026 # Push IRM Request Fields Source: https://docs.ebrc.in/annexure/push-irm Field-by-field reference for the Push IRM request payload: every JSON field, its format, whether it is required, and what it means. This annexure lists the complete field-level details for the Push IRM request payload. Legend: `Req` Y = Required, N = Not required, O = Optional, O(M) = Optional but conditionally Mandatory ### Message fields | JSON | Name | Req | Format | Description | | ------------------ | -------------------- | --- | ----------- | --------------------------------------------------------------------------------------------------------- | | `recordResCount` | Record request count | Y | `int(4)` | Total IRM invoice mappings in this message. At most **999** per message. | | `uploadType` | eBRC type | Y | `int(3)` | eBRC type: 101 Direct Export, 102 Softex, 103 Service Non IT, 104 Deemed. Sent as a string, e.g. `"101"`. | | `decalarationFlag` | Declaration Flag | Y | `string(1)` | Exporter declaration confirming correctness of data. Spelling preserved exactly for wire compatibility. | ### Item fields (`ebrcBulkGenDtos[]`) | JSON | Name | Req | Format | Description | | ---------------- | ------------------------- | --- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `serialNo` | Serial Number | Y | `number(3)` | Unique serial within the message; 1-999. | | `branchSlNo` | IEC branch Serial number | Y | `int(3)` | IEC branch where invoice is generated. Default 0. A whole number, 0-999. | | `irmNumber` | IRM Number | Y | `string(50)` | IRM number. | | `irmDt` | IRM date | Y | `date(ddMMyyyy)` | IRM date. | | `irmIfscCode` | IFSC Code | Y | `string(11)` | Bank IFSC for the IRM. | | `irmAdCode` | AD Code | Y | `string(7)` | AD code of Shipping bill/SOFTEX/Invoice. | | `irmFCC` | IRM foreign currency code | Y | `string(3)` | IRM FC code. See [Currency Codes](/annexure/currency-codes). | | `irmPurposeCode` | Purpose Code | Y | `string(5)` | Purpose code of IRM: `P` followed by four digits. Must match the purpose on the IRM itself, or the filing is warned and DGFT answers ERR22. See [Purpose Codes](/annexure/purpose-codes). | **These five fields are checked against the IRM we hold for the exporter**, and a disagreement is reported in the `warnings` array of an accepted filing rather than refused: `irmIfscCode`, `irmAdCode`, `irmDt`, `irmFCC` and `irmPurposeCode`. DGFT compares the same five and answers ERR15, ERR16, ERR19, ERR20 and ERR22 on the status poll hours later, so the warning is the same finding, earlier. See [Errors](/errors#warnings-on-an-accepted-filing). | JSON | Name | Req | Format | Description | | ------------------------ | ----------------------------------------------- | --- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `sbCumInvoiceNumber` | Shipping bill/SOFTEX/Invoice Number | Y | `string(20)` | **Which document this is depends on `uploadType`** — see below. Shipping bill for Direct Export, SOFTEX for software exports, invoice number for other service exports. | | `sbCumInvoiceDate` | Shipping Bill/SOFTEX/Invoice date | Y | `date(ddMMyyyy)` | Date of whichever document `sbCumInvoiceNumber` carries. | | `portCode` | Port Code | Y | `string(6)` | As per DGFT master data. See [Port Codes](/annexure/port-codes). | | `sbCumInvoiceFCC` | Shipping Bill/SOFTEX/Invoice FC Code | Y | `string(3)` | FC code for the invoice. See [Currency Codes](/annexure/currency-codes). | | `sbCumInvoiceValueinFCC` | Total Shipping Bill/SOFTEX/Invoice Value in FCC | Y | `number(16,2)` | Invoice value in FCC. | | `billNo` | Bill Number | Y | `string(20)` | The bill/invoice number the IRM is mapped against within the shipping bill or SOFTEX. This is **not** the same field as `sbCumInvoiceNumber`. For service exports other than software the invoice number and bill number may be identical. | **`sbCumInvoiceNumber` carries three different documents, and Direct Export has a stricter rule than the `string(20)` above.** | `uploadType` | What `sbCumInvoiceNumber` must contain | Constraint | | -------------------- | -------------------------------------- | -------------------------- | | `101` Direct Export | The **shipping bill number** | **Digits only, at most 7** | | `102` Softex | The SOFTEX number | Up to 20 characters | | `103` Service Non-IT | The invoice number | Up to 20 characters | | `104` Deemed | Not specified by DGFT | Up to 20 characters | For a Direct Export, an invoice-style reference such as `EX/25-26/028` or `SB7654321` is rejected with **400** before the filing is sent to DGFT. The invoice reference belongs in `billNo`. ```json Direct export (uploadType 101) theme={"dark"} { "uploadType": 101, "sbCumInvoiceNumber": "9489431", // shipping bill number - digits, max 7 "billNo": "EX/25-26/028" // your invoice reference } ``` Swapping these two is the most common cause of a rejected Direct Export filing. DGFT's own error for it is `ERR25` — *"Invalid shipping bill number. It cannot be greater than 7 digit"* — which would otherwise surface hours later on the status poll rather than at submission. | JSON | Name | Req | Format | Description | | -------------------- | ---------------------------------- | --- | -------------- | ---------------------------------- | | `irmRemitAmtFCC` | Remittance Amount Available in FCC | Y | `number(16,2)` | Total remittance available in FCC. | | `mappedIRMAmountFCC` | IRM FCC Amount mapped | Y | `number(16,2)` | IRM amount mapped against invoice. | | `mappedORMAmountFCC` | ORM Amount mapped | Y | `number(16,2)` | ORM amount mapped in invoice. | | JSON | Name | Req | Format | Description | | -------------------- | ------------------ | --- | ----------- | ------------------------------------------ | | `isVostro` | IsVostro Payment | Y | `string(1)` | Y if payment received in Vostro account. | | `vostroType` | Vostro Type | O | `string(4)` | SVRA or NVRA. | | `isThirdPartyExport` | Third Party Export | Y | `string(1)` | Y if remittance received by a third party. | | JSON | Name | Req | Format | Description | | ---------------------- | ------------------------------- | --- | -------------- | -------------------------------------------------------------------------------------------------- | | `commissionValDeduct` | Commission Value to be deducted | N | `number(16,2)` | Commission to deduct from IRM FCC. | | `commissionValInfo` | Commission Value Info | N | `number(16,2)` | Commission for information in invoice FCC. | | `discountValDeduct` | Discount value to be deducted | N | `number(16,2)` | Discount to deduct from IRM FCC. | | `discountValInfo` | Discount value Info | N | `number(16,2)` | Discount for information in invoice FCC. | | `insuranceValDeduct` | Insurance value to be deducted | N | `number(16,2)` | Insurance to deduct from IRM FCC. | | `insuranceValInfo` | Insurance value Info | N | `number(16,2)` | Insurance for information in invoice FCC. | | `otherDeductionDeduct` | Other deduction to be deducted | N | `number(16,2)` | Other deduction to deduct from IRM FCC. | | `otherdeductionsInfo` | Other deduction for info | N | `number(16,2)` | Other deduction for information in invoice FCC. Spelling preserved exactly for wire compatibility. | | `freightValDeduct` | Freight value to be deducted | N | `number(16,2)` | Freight to deduct from IRM FCC. | | `freightValInfo` | Freight value for info | N | `number(16,2)` | Freight for information in invoice FCC. | | JSON | Name | Req | Format | Description | | ----------------------- | -------------------------- | --- | ----------- | ----------------------------------------------------------------------------------- | | `sacCode1` | SAC Code | N | `string(8)` | SAC code for service export. | | `sacCode2` | SAC Code 2 | N | `string(8)` | Second SAC code, if applicable. | | `serviceTypeModesValue` | Mode of Export of Services | O | `string` | Cross-border, Consumption Abroad, Commercial Presence, Presence of Natural Persons. | | JSON | Name | Req | Format | Description | | -------------------- | ---------------- | ---- | ---------------- | ------------------------------------------------------------------------ | | `isGstAvail` | GSTIN Available | Y | `string(1)` | Whether to avail GSTIN benefit. `Y` or `N`. Cannot be null or empty. | | `gstinInvoiceNumber` | GST Invoice No | O(M) | `string(30)` | Mandatory if `isGstAvail` is `Y`; must be `null` if `isGstAvail` is `N`. | | `gstinInvoiceDate` | GST Invoice Date | O(M) | `date(ddMMyyyy)` | Mandatory if `isGstAvail` is `Y`; must be `null` if `isGstAvail` is `N`. | Only the request fields relevant to Push IRM are listed here. Response and status fields (e.g., `dgftAckId`, `ackStatus`) are documented on their respective pages. ## Used by * [Submit IRMs for eBRC Generation](/api-reference/genebrc/push-irm), which takes these fields as JSON * [Bulk Upload via Excel](/api-reference/genebrc/bulk-upload) and [its template](/api-reference/genebrc/bulk-upload-template), whose columns map to these fields by name * The [Quick Start](/quick-start) payload, a canonical example of this message # Create Customer Source: https://docs.ebrc.in/api-reference/customer/create POST /platform-customers Create a platform customer, the exporter entity you generate eBRCs for. Returns the platformCustomerId used in every later IRM and certificate generation call. Create a platform customer for each exporter you generate certificates for. This is the first call in the lifecycle: the returned `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 returns `isActive: 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](/api-reference/customer/validate). `POST /platform-customers` stores the exporter's profile and returns its `id`. The client is inactive and has no DGFT connection. `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`. Passing `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](/api-reference/customer/validate). The eBRC console behaves the same way: it collects the credentials on the onboarding form and verifies them in a second step. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/platform-customers' \ --header 'Content-Type: application/json' \ --header 'x-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. | Any other property is rejected with `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 accepts `iec` 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 Returns `201` with the client in the `data` field of the [standard envelope](/api-reference/introduction#response-envelope): ```json theme={"dark"} { "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" } ``` Optional fields you did not send are absent from the create response rather than `null`. Read them back with [Get Customer by Id](/api-reference/customer/getById), 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](/errors#the-24-hour-activation-and-retryafter). | | `createdAt`, `updatedAt` | ISO 8601 UTC. | The stored DGFT password is encrypted at rest and is never returned on any surface. Your API key prefix decides the mode: a `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](/environments). ### Errors * `400` `Validation failed` with `errors: ["email: email must be an email"]` when the email fails format validation. * `400` `Validation failed` with `errors: ["iec: iec must be exactly 10 alphanumeric characters (Importer Exporter Code)"]` when the IEC is not 10 letters and digits. * `400` `Validation failed` with `errors: [": property should not exist"]` for any property outside the table above. * `400` `User with email already exists` when 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. * `400` `DGFT username already in use` when the `dgftUsername` you sent is already linked to another of your clients in this mode. * `401` `No API key provided`, or `Invalid API key` when the key is unknown or revoked. See [authentication errors](/authentication#authentication-errors). * `403` `Only platform users can access this resource`, or `Master Platform Agreement not signed yet`. Both `dev_` and `prod_` keys require a signed agreement before issuance. See [common validation errors](/errors#common-validation-errors) for the full error body shape. ### Next steps * [Validate the customer's DGFT credentials](/api-reference/customer/validate). This step is required, not optional. * [Fetch their IRMs](/api-reference/irm/post) once the client is active. * Walk the whole flow in the [Quick Start](/quick-start). # Delete Customer Source: https://docs.ebrc.in/api-reference/customer/delete DELETE /platform-customers/{id} Delete a platform customer and all of its filing history from your account by id. This is permanent and cascades to the stored DGFT connection, remittances, generation requests and certificate details. Delete a platform customer. Use this when an exporter offboards from your platform. This is permanent and it cascades. Deleting a client also deletes, in a single transaction: * the stored DGFT connection for that client * every IRM record held for that client * every eBRC generation request submitted for that client * every certificate detail record enriched for that client There is no undo and no soft delete. Certificates already issued by DGFT are unaffected on the DGFT portal, but your record of them here is gone. Export anything you need to keep first. The operation returns `200` with a success flag, not `204`. ### Delete is not deactivate The API has no deactivate. If you want to stop filing for an exporter while keeping their history, do not call this endpoint. Stop sending IRMs for that client, or deactivate them from the eBRC console, which has a status toggle for exactly this case and does not offer delete at all. ### Request example ```bash theme={"dark"} curl --location --request DELETE 'https://api.ebrc.in/api/v1/platform-customers/ee849a90-7a28-49b4-8cb2-8e31041650a2' \ --header 'x-api-key: ' ``` ### Response example ```json theme={"dark"} { "success": true, "data": { "success": true }, "statusCode": 200, "timestamp": "2026-07-22T11:10:44.120Z" } ``` ### Errors * `401` `No API key provided` or `Invalid API key`. See [authentication errors](/authentication#authentication-errors). * `404` `Customer not found` when no client with that id belongs to your account **in the mode your key selects**. A `dev_` key cannot delete a live client, which is what stops a test integration from destroying live filing history. * `500` `Error removing platform customer` if the transaction fails. The whole cascade is one transaction, so a partial delete cannot happen. ### Next steps * [List remaining customers](/api-reference/customer/get). * [Create a new customer](/api-reference/customer/create). * Questions about data retention: [amin@eximfiles.io](mailto:amin@eximfiles.io). # Get Customers List Source: https://docs.ebrc.in/api-reference/customer/get GET /platform-customers List the platform customers under your account with pagination and search by partial name or email, so you can find the exporter entity you generate eBRCs for. List every exporter entity under your platform account. Use this to reconcile your records with the API, or to look up a `platformCustomerId` you did not store. The roster is scoped to the mode your key selects: a `dev_` key lists test clients only, a `prod_` key lists live clients only. Results are ordered newest first. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/platform-customers?page=1&limit=10&search=surya' \ --header 'x-api-key: ' ``` `page` starts at 1 and defaults to 1. `limit` defaults to 10 and caps at 100. `search` filters by partial name or email, case insensitive, and must be at least 1 character. ### Response example ```json theme={"dark"} { "success": true, "data": { "items": [ { "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", "isActive": true, "hasDgftCredentials": true, "createdAt": "2026-07-22T10:15:04.874Z" } ], "meta": { "totalItems": 1, "itemsPerPage": 10, "totalPages": 1, "currentPage": 1 } }, "statusCode": 200, "timestamp": "2026-07-22T10:25:00.000Z" } ``` See [the client object](/api-reference/customer/create#the-client-object) for what each field means. Two things differ on this endpoint: * `updatedAt` and `mode` are **not** returned in the list. Use [Get Customer by Id](/api-reference/customer/getById) for `updatedAt`. * Fields the client has no value for are `null` here, not absent. `isActive: false` with `hasDgftCredentials: false` means onboarding was never finished. That client cannot file until you [validate its DGFT credentials](/api-reference/customer/validate). ### Errors * `400` `Validation failed` for an out-of-range `limit`, a `page` below 1, or an empty `search`. * `401` `No API key provided` or `Invalid API key`. See [authentication errors](/authentication#authentication-errors). * `403` `Only platform users can access this resource`, or `Master Platform Agreement not signed yet`. ### Next steps * [Get a single customer](/api-reference/customer/getById) by id. * [Update a customer's details](/api-reference/customer/update). * [Fetch a customer's IRMs](/api-reference/irm/post). # Get Customer by Id Source: https://docs.ebrc.in/api-reference/customer/getById GET /platform-customers/{id} Fetch a single platform customer by its id to read the stored exporter entity details before you fetch IRMs or submit an eBRC generation request for them. Fetch one platform customer by its `id`. Use this to check a client's details, its IEC, or whether it is ready to file, before you push IRMs for it. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/platform-customers/ee849a90-7a28-49b4-8cb2-8e31041650a2' \ --header 'x-api-key: ' ``` ### Response example ```json theme={"dark"} { "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", "isActive": true, "hasDgftCredentials": true, "createdAt": "2026-07-22T10:15:04.874Z", "updatedAt": "2026-07-22T10:21:33.120Z" }, "statusCode": 200, "timestamp": "2026-07-22T10:25:00.000Z" } ``` See [the client object](/api-reference/customer/create#the-client-object) for what each field means. `mode` is not returned by this endpoint; a client is only reachable in the mode your key selects, so the mode is implied by the key you used. Fields the client has no value for are `null`. ### Is this client ready to file? | `isActive` | `hasDgftCredentials` | Meaning | | :--------: | :------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `false` | `false` | Created but never validated. [Validate its DGFT credentials](/api-reference/customer/validate). | | `false` | `true` | Credentials are on file but were never verified, or the client was deactivated. Re-run validation. | | `true` | `true` | Onboarding is complete. Check `dgftApiStatus.state`: `activation_pending` means DGFT opens API access at `activatesAt` (see [the 24-hour activation](/errors#the-24-hour-activation-and-retryafter)); `ready` means it can fetch and file now. | ### Errors * `400` `Invalid platform customer ID format: . Expected a UUID format...` when the id is not a UUID. Platform customer ids are UUIDs; a Clerk user id starting with `user_` is not one. * `401` `No API key provided` or `Invalid API key`. See [authentication errors](/authentication#authentication-errors). * `404` `Platform customer with id not found` when no client with that id belongs to your account **in the mode your key selects**. A `dev_` key cannot read a live client and gets this same `404`. ### Next steps * [Update this customer](/api-reference/customer/update). * [Validate their DGFT credentials](/api-reference/customer/validate). * [List all customers](/api-reference/customer/get). # Update Customer Source: https://docs.ebrc.in/api-reference/customer/update PATCH /platform-customers/{id} Partially update a platform customer's name, company name, or address. The IEC, email, type and mode are fixed after creation, and DGFT credentials are changed via the validate endpoint. Update a client's `name`, `companyName` or `address`. All three are optional; only the fields you send are changed. ### What can and cannot be changed | Field | Editable | Why | | ------------------------------ | :------: | -------------------------------------------------------------------------------------------------------------- | | `name` | Yes | | | `companyName` | Yes | The registered legal name. | | `address` | Yes | Not collected by the eBRC console, so console-onboarded clients start with no address. | | `iec` | No | Fixed after creation. To correct an IEC, contact support. | | `email` | No | Part of the client's identity within your account and mode. | | `type` | No | Always `customer`. | | `isActive` | No | Set by [DGFT credential validation](/api-reference/customer/validate), not by hand. | | `mode` | No | Fixed at creation. Moving a client between test and live would drag its filings across the isolation boundary. | | `dgftUsername`, `dgftPassword` | No | Use [Validate Customer](/api-reference/customer/validate) to rotate the password. | Anything other than `name`, `companyName` and `address` is rejected with a `400` before the update runs, including `iec`, `email`, `isActive` and `mode`. The eBRC console exposes only `name` and `companyName` on its client edit form. The API is the broader surface: it also accepts `address`. Everything the console can edit, the API can edit. ### Request example ```bash theme={"dark"} curl --location --request PATCH 'https://api.ebrc.in/api/v1/platform-customers/ee849a90-7a28-49b4-8cb2-8e31041650a2' \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "companyName": "Surya Textile Exports Private Limited", "address": "SIDCO Industrial Estate, Tiruppur, Tamil Nadu" }' ``` ### Response example ```json theme={"dark"} { "success": true, "data": { "id": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "name": "Rohan Mehta", "email": "finance@suryatextiles.example.com", "type": "customer", "companyName": "Surya Textile Exports Private Limited", "iec": "AAECS1234F", "address": "SIDCO Industrial Estate, Tiruppur, Tamil Nadu", "platformId": "1f0c9a52-3b41-4d78-9e26-7a8b5c4d3e2f", "mode": "live", "isActive": true, "hasDgftCredentials": true, "createdAt": "2026-07-22T10:15:04.874Z", "updatedAt": "2026-07-22T11:02:18.330Z" }, "statusCode": 200, "timestamp": "2026-07-22T11:02:18.352Z" } ``` See [the client object](/api-reference/customer/create#the-client-object) for every field. ### Errors * `400` `Validation failed` with one `errors` entry per rejected property, for example `["email: property email should not exist", "iec: property iec should not exist"]`. This covers every field outside `name`, `companyName` and `address`. See [common validation errors](/errors#common-validation-errors). * `401` `No API key provided` or `Invalid API key`. See [authentication errors](/authentication#authentication-errors). * `404` `Customer not found` when no client with that id belongs to your account in the mode your key selects. ### Next steps * [Get the customer](/api-reference/customer/getById) to confirm the change. * [Validate DGFT credentials](/api-reference/customer/validate) if the DGFT password changed. * [Delete the customer](/api-reference/customer/delete) if they are offboarding. # Validate Customer Source: https://docs.ebrc.in/api-reference/customer/validate POST /platform-customers/{id}/check-dgft-credentials Validate and securely store an exporter's DGFT portal credentials for a platform customer. Required before you fetch their IRMs or generate an eBRC for them. Validate the exporter's DGFT portal credentials and store the connection. This is the second and required half of onboarding: a client created by [Create Customer](/api-reference/customer/create) is inactive and cannot file until this call succeeds. Call it again whenever the exporter's DGFT password changes. Re-submitting the **same** username with a new password updates the stored password. Submitting a **different** username is rejected. This endpoint performs a real login against the DGFT portal, so it is synchronous and can take several seconds. It is limited to **4 calls per minute**. Five failed checks in fifteen minutes are refused for another fifteen minutes. Services are enabled after **24 hours** of successful validation. ### What success changes On a successful validation the client's `isActive` becomes `true` immediately, the DGFT connection is stored against the client, and `hasDgftCredentials` becomes `true`. Nothing else on the client is modified. This is the same operation the eBRC console runs when a platform user submits or rotates a client's DGFT credentials, so a client onboarded either way reaches the same state. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/platform-customers/ee849a90-7a28-49b4-8cb2-8e31041650a2/check-dgft-credentials' \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "dgftUsername": "", "dgftPassword": "" }' ``` Both fields are required. Credentials are encrypted at rest, redacted from logs, and never shown back by any endpoint. Submitting an exporter's DGFT credentials is what grants the mandate to act on their behalf, and the submission is recorded as consent evidence. Only submit credentials the exporter has authorised you to hold. See the [API Terms](/api-terms). ### Response example Returns `201` with the client in the `data` field. `isActive` and `hasDgftCredentials` are now both `true`. ```json theme={"dark"} { "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": true, "hasDgftCredentials": true, "dgftApiStatus": { "state": "ready", "activatesAt": null, "registration": "generated", "sharedCredentialsLikely": false }, "createdAt": "2026-07-22T10:15:04.874Z", "updatedAt": "2026-07-22T10:21:33.120Z" }, "statusCode": 201, "timestamp": "2026-07-22T10:21:33.145Z" } ``` The stored DGFT password is never present in any response. See [the client object](/api-reference/customer/create#the-client-object) for every field. **Read `dgftApiStatus` before the first refresh.** If the exporter already held DGFT API credentials, the response carries `"state": "activation_pending"` with an `activatesAt` timestamp: DGFT enables our IP on that account after 24 hours, and IRM refreshes until then answer `409 DGFT_IP_ACTIVATION_PENDING`. Nothing is wrong and nothing needs re-submitting. See [the 24-hour activation](/errors#the-24-hour-activation-and-retryafter). ### Errors * `400` `Invalid DGFT credentials` when the DGFT portal rejects the username and password. The client stays inactive. * `400` `DGFT credentials are already set for this customer` when you send a username different from the one already stored. Password rotation is supported, changing the username is not. * `400` `DGFT username already in use` when that username is already linked to another of your clients in this mode. * `400` `DGFT username already aligned with another platform customer` when the DGFT account is already connected to a different client of yours in this mode. * `400` `Validation failed` when `dgftUsername` or `dgftPassword` is missing or empty. * `401` `No API key provided` or `Invalid API key`. See [authentication errors](/authentication#authentication-errors). * `404` `Platform customer not found` when no client with that id exists under your account **in the mode your key selects**. A `dev_` key cannot reach a live client. * `429` when you exceed 4 calls per minute. See [rate limits](/authentication#rate-limits). * `500` `Error checking DGFT credentials` when the portal check could not be completed. Retry after a short delay. Filings and downloads made later with a stale password return `DGFT_CREDENTIALS_INVALID`. Recover by calling this endpoint again with the new password. See [DGFT credential error codes](/errors#dgft-credential-error-codes). ### Next steps * [Fetch the customer's IRMs](/api-reference/irm/post) once the client is active. * [Submit IRMs for generation](/api-reference/genebrc/push-irm). * [Download eBRC PDF](/api-reference/genebrc/download) shows credential recovery end to end. # Data Extraction Source: https://docs.ebrc.in/api-reference/extraction/introduction Turn shipping bill PDFs into the structured fields you need to map remittances and file eBRCs, with a report on whether each document agreed with its own arithmetic. ## Overview Shipping bill extraction turns an ICEGATE PDF into structured JSON: the summary fields you need to file, the full parsed document, and a verification report saying whether the bill's own totals reconcile. It is **deterministic**. The PDF's text layer is read and fields are located by their printed labels. There is no model, so the same document always returns the same answer. ## Base URL The same base URL as every other eBRC endpoint: ```bash theme={"dark"} https://api.ebrc.in/api/v1 ``` ## Authentication **Use your eBRC API key.** Extraction has no separate credential: the key you already send with filing requests authenticates it, and there is nothing to provision: ```bash theme={"dark"} x-api-key: prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` Create and manage keys in the console under **API keys → eBRC**. **Build against your `dev_` key.** The parse is identical either way (no DGFT sandbox is involved and nothing is filed), but the two keys draw on separate budgets, so anything you extract while integrating leaves your plan's volume untouched. Switch to `prod_` when you go to production. See [Allowances](#allowances). ## Endpoints | Endpoint | What it does | | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | [`POST /shipping-bills/platform/extract`](/api-reference/extraction/shipping-bills) | Extract a shipping bill | | `GET /shipping-bills/usage` | This month's volume and allowance. See [Allowances](#allowances) | [Verification](/api-reference/extraction/verification) documents the checks run on every extraction. ## Request format * `multipart/form-data`, one file per request, field name `file` * PDF only. The magic bytes are checked, not the filename or the declared type * Maximum **10 MB** ## Response format Responses use the standard eBRC envelope, with the extraction under `data`: ```json theme={"dark"} { "success": true, "data": { "fields": { }, "sections": { }, "verification": { }, "document": { } }, "statusCode": 200, "timestamp": "2026-08-07T10:04:11.512Z" } ``` ## Why scans are rejected Only the text layer is read; pages are never rasterised or OCR'd. That is a deliberate limit, not a gap. A shipping bill downloaded from ICEGATE always carries text. A file without one is a scan or a phone photo, both unreadable to us and the easiest kind of document to alter. Rejecting it with a clear instruction is better than reading a picture of unknown provenance and returning figures you would then file against. ## Allowances Extraction is free for general use, and the two key types draw on **separate** budgets, so integrating never spends volume you paid for. | Budget | Included free | Spent by | | ---------------- | -------------------------- | ---------------- | | Live extractions | **250** per calendar month | your `prod_` key | | Test extractions | **50** per calendar month | your `dev_` key | Both counters reset on the 1st, IST. Higher volume is available on a paid plan. Plans, what each one includes, and your usage for the month sit together in the console under **Billing**. A plan's extraction volume is a **total, not an increment**: it replaces the free 250 rather than stacking on it, and every rung's total sits well above it. Why test is capped at all, when test *filings* are unlimited: a sandbox filing produces no real certificate, so it is worthless and free. A sandbox extraction returns **byte-identical, production-usable JSON**. There is no degraded sandbox version of a parsed shipping bill. An uncapped test mode would simply be the product for free, so it is capped, just against its own budget. `GET /shipping-bills/usage` reports the current period. It authenticates with your **console session** rather than an API key, because it is an account-level billing figure rather than a per-key counter: ```json theme={"dark"} { "success": true, "data": { "period": "2026-08", "planSlug": "free", "enforced": true, "live": { "used": 118, "verified": 114, "cap": 250, "remaining": 132 }, "test": { "used": 30, "verified": 29, "cap": 50, "remaining": 20 }, "total": { "used": 148, "verified": 143 } } } ``` `planSlug` and the two `cap` figures are whatever your account is actually on, so read them rather than hard-coding the free numbers above. `live` and `test` are independent budgets. `total` is only there for "how many bills did we process this month". `cap: null` means unlimited. `verified` is how many of those passed every error-level [verification](/api-reference/extraction/verification) check. The gap is documents that extracted cleanly but did not agree with their own totals. `enforced` tells you whether the ceilings actually refuse work. It is **`true`** by default: an over-cap request is refused with `402` and the code below. Read the field rather than assuming, because an account can be set to record-only, in which case usage is counted and nothing is refused. ### When the allowance runs out ```json theme={"dark"} { "statusCode": 402, "errorCode": "monthly_extraction_limit_reached", "message": "Your plan includes 250 shipping bill extractions this month and they are used up.", "path": "/api/v1/shipping-bills/platform/extract", "timestamp": "2026-08-08T15:20:18.941Z" } ``` Branch on `errorCode`, never on the message. There are two, and which one you get tells you *which* budget is exhausted: | `errorCode` | Meaning | | ---------------------------------- | ----------------------------------------------------------------------------------------------- | | `monthly_extraction_limit_reached` | Your `prod_` key spent the live allowance. Plans and usage are in the console under **Billing** | | `sandbox_extraction_limit_reached` | Your `dev_` key hit the test ceiling. Your live allowance is **untouched**. Switch to `prod_` | A document that fails to parse does **not** consume the allowance: the unit is claimed before the parse so concurrent requests cannot both take the last one, and handed back if the PDF turns out to be unreadable. ## Getting started 1. Create a `dev_` key in the console under **API keys → eBRC**. 2. `POST` a shipping bill PDF to [`/shipping-bills/platform/extract`](/api-reference/extraction/shipping-bills). 3. Read `data.fields` for the summary, `data.sections` for the whole parsed document, and `data.verification` to see whether the bill reconciled with itself. 4. Switch the key to `prod_` when you go live. One call returns all three, so there is never a reason to send the same PDF twice. # Extract Shipping Bill Data Source: https://docs.ebrc.in/api-reference/extraction/shipping-bills Turn a shipping bill PDF into the summary fields needed to file an eBRC, the complete parsed document, and a report on whether the bill agreed with its own totals. Extract a shipping bill PDF. One call returns the summary fields, the full parsed document and a verification report. `POST /shipping-bills/platform/extract` ## Request The shipping bill PDF. Maximum 10 MB, one file per request. Must be the PDF downloaded from ICEGATE. A scan or photo has no text layer and is rejected. ### Headers Your eBRC API key (`dev_` or `prod_`). Extraction has no separate credential. See [Authentication](/api-reference/extraction/introduction#authentication). ## Example request ```bash cURL theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/shipping-bills/platform/extract' \ --header 'x-api-key: prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' \ --form 'file=@"/path/to/shipping-bill.pdf"' ``` ```javascript JavaScript theme={"dark"} const formData = new FormData(); formData.append('file', fileInput.files[0]); const res = await fetch('https://api.ebrc.in/api/v1/shipping-bills/platform/extract', { method: 'POST', headers: { 'x-api-key': 'prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' }, body: formData, }); const { data } = await res.json(); console.log(data.fields.shippingBillNumber, data.verification.passed); ``` ```python Python theme={"dark"} import requests res = requests.post( "https://api.ebrc.in/api/v1/shipping-bills/platform/extract", headers={"x-api-key": "prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}, files={"file": open("shipping-bill.pdf", "rb")}, ) data = res.json()["data"] print(data["fields"]["shippingBillNumber"], data["verification"]["passed"]) ``` ## Response ```json theme={"dark"} { "success": true, "data": { "fields": { "shippingBillNumber": "5554056", "shippingBillDate": "2020-09-30", "portCode": "INCCU1", "invoiceNumber": "10814885", "currency": "USD", "shippingBillValue": 3019368.56, "sacCode1": "", "sacCode2": "", "commission": 54687, "commissionInfo": 0, "discount": 0, "discountInfo": 0, "insurance": 1531, "insuranceInfo": 0, "otherDeductions": 0, "otherDeductionsInfo": 0, "freight": 41553, "freightInfo": 0 }, "sections": { "section_1": { }, "section_2": { }, "section_3": { }, "section_4": { } }, "verification": { "passed": true, "score": 1, "errors": 0, "warnings": 0, "failedChecks": [] }, "document": { "sha256": "d0aa4d7bab4219007a655328f5bec6284257648b8e6d8afcb6086b179f456e83", "pageCount": 10, "fileName": "shipping-bill.pdf" } }, "statusCode": 200, "timestamp": "2026-08-07T10:04:11.512Z" } ``` ### fields The summary most integrations want. Everything here comes from the bill's page header and PART I, which is why it resolves even when a bill's later parts are only partly understood. The SB number from the page header. ISO `YYYY-MM-DD`. A date that could not be parsed is `""`, never a guess. ICEGATE port code, e.g. `INCCU1`. The first invoice in the PART I summary. That invoice's currency. FOB value from the PART I value summary. Always `""`, not printed on the bill. Present so the key is never silently absent. As above. Commission deducted. The bill prints this column as `COM`. Discount deducted. Insurance deducted. Freight deducted. Other deductions. The "declared for information only" counterparts DGFT distinguishes from amounts actually deducted. PART I carries only the deducted figures, so these are always `0`, emitted rather than omitted so every key is present. Deductions are **top level** on `fields`, not nested under a `deductions` object. `fields.commission`, not `fields.deductions.commission`. ### sections The complete parsed document: PART I to PART IV in the shape ICEGATE prints them, with the original block and column names. Use it when you need more than the summary; ignore it otherwise. Keys appear only for parts actually found in the file. A standard bill yields `section_1` through `section_4`. ### document SHA-256 of the uploaded bytes, so a specific upload can be identified later. Pages in the PDF. The filename you sent. ### verification Whether the bill agreed with its own arithmetic. See [Verification](/api-reference/extraction/verification) for every check and what a failure means. ## Errors Every rejection names the fix rather than failing generically. | Status | Message | What to do | | ------ | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 400 | Upload the shipping bill as a PDF. | Not a PDF. The magic bytes are checked, not the filename | | 400 | This PDF has no text layer, so it is a scan or a photo… | Download the bill again from ICEGATE and upload that file | | 400 | This PDF could not be opened… | Damaged or password protected | | 400 | No shipping bill could be found in this PDF. | It parsed, but carries no recognisable PART banner | | 401 | | Missing, revoked or unrecognised API key | | 402 | Your plan includes N shipping bill extractions… | Month's allowance spent. `errorCode` is `monthly_extraction_limit_reached` (prod) or `sandbox_extraction_limit_reached` (dev). See [Allowances](/api-reference/extraction/introduction#allowances) | | 413 | | Over 10 MB | ```json theme={"dark"} { "statusCode": 400, "message": "This PDF has no text layer, so it is a scan or a photo. Download the shipping bill again from ICEGATE and upload that file.", "path": "/api/v1/shipping-bills/platform/extract", "timestamp": "2026-08-07T10:04:11.512Z" } ``` # Verification Source: https://docs.ebrc.in/api-reference/extraction/verification Every extraction is checked against the arithmetic the shipping bill performs on itself, so you can tell which of your documents are internally inconsistent before you file against them. A shipping bill states its own totals twice. Every extraction checks them against each other and returns the result on `data.verification`. This is the part a document-reading model cannot offer. It does not tell you whether *we* read the bill correctly. It tells you whether **the bill agrees with itself**, which is a fact about your document and worth knowing before you file against it. ## The response ```json theme={"dark"} { "verification": { "passed": true, "score": 1, "errors": 0, "warnings": 0, "failedChecks": [] } } ``` True when no **error**-level check failed. Warnings do not affect it. Share of applicable checks that passed, 0 to 1. Checks that do not apply to a document are not counted, so a bill with no container table is not penalised for it. Error-level failures. Warning-level failures. One entry per failure, with `id`, `severity` and a `detail` naming the figures that disagreed. A failure looks like this: ```json theme={"dark"} { "verification": { "passed": false, "errors": 1, "warnings": 0, "failedChecks": [ { "id": "value.fob-equals-item-sum", "severity": "error", "detail": "PART I 104381.85 vs items 1043881.85 (delta -939500.00)" } ] } } ``` ## The checks | id | Severity | What it asserts | | ------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | | `header.invoice-count` | error | Header `INV Nos` matches the number of PART II invoice records | | `header.item-count` | error | Header `ITEM Nos` matches the PART III item rows | | `header.container-count` | warning | Header `CONT Nos` matches the equipment table. A warning because air consignments legitimately omit it | | `value.fob-equals-item-sum` | error | PART I FOB equals the sum of PART III `FOB (INR)` | | `invoice.*.item.*.qty-rate` | warning | Quantity × rate equals the line value, per PART II line | | `summary.invoice-table-within-header` | warning | The PART I summary lists no more invoices than the header declares. The form truncates this table, so fewer is normal | | `document.single-bill` | error | The file contains exactly one shipping bill | | `format.iec` | warning | IEC is a 10-character code | | `format.gstin` | warning | GSTIN is 15 characters | | `format.sb-date` | error | The SB date parsed to ISO `YYYY-MM-DD` | | `presence.sb-no` | error | An SB number was found | ## What a failure usually means **`document.single-bill`**: several bills concatenated into one PDF. Their sections have been merged into a single incoherent document: the header is the first bill's, the item rows are all of them. Split the file and extract each bill separately. **`value.fob-equals-item-sum`**: the summary FOB and the item lines disagree. A delta that is an exact factor of ten is a decimal-place error somewhere in the document. **`header.item-count` or `header.invoice-count`**: the file is truncated, or a part is missing. A bill whose header declares four items but carries three rows is missing a row, not mis-read. ## Extraction still succeeds A document that fails verification is still returned with a `200` and full `fields`. The checks describe the document; they do not gate the response. What you do with that is yours to decide. Routing failures to human review before filing is the obvious use. A bill that does not reconcile with itself will not reconcile with DGFT either. # Bulk Upload via Excel Source: https://docs.ebrc.in/api-reference/genebrc/bulk-upload POST /genebrc/bulk-upload Upload a filled Excel file to generate eBRCs in bulk. Each row is validated before anything is filed, and errors come back per row with field and message. Upload an Excel file (`.xlsx` or `.xls`, max **5 MB** and **999 data rows**) to generate eBRCs in bulk. Column headers are matched to the required fields by name and the rows are submitted to DGFT in a single request. Validation errors come back per row, so you know exactly which line to fix. Limited to **5 calls per minute**. Download the starting file from [Download Bulk Upload Template](/api-reference/genebrc/bulk-upload-template), or [pre-filled with real IRM data](/api-reference/irm/bulk-template). Extracting rows from shipping bill PDFs first? See [Shipping Bill extraction](/api-reference/extraction/shipping-bills). A row is one IRM mapped to one document, and the same IRM may appear on as many rows as it has invoices: the mapped amounts per IRM are summed across the file and checked against the remittance and against the amount still available on it. Several IRMs may likewise share one invoice, one row each; DGFT issues one eBRC per row. See [the template page](/api-reference/genebrc/bulk-upload-template#one-row-per-irm-to-invoice-mapping) for the worked example. ### Request example ```bash theme={"dark"} curl -X POST "https://api.ebrc.in/api/v1/genebrc/bulk-upload?uploadType=101&decalarationFlag=Y&platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2" \ -H "x-api-key: " \ -F "file=@/path/to/ebrc-data.xlsx" ``` Query parameters: | Parameter | Required | Values | | -------------------- | -------- | --------------------------------------------------------------------- | | `platformCustomerId` | Yes | Platform customer UUID | | `uploadType` | Yes | `101` Direct Export, `102` Softex, `103` Service Non IT, `104` Deemed | | `decalarationFlag` | Yes | `Y` or `N` (spelling as per DGFT specification) | ### Response Alongside the DGFT acknowledgement, the response echoes back every IRM that was parsed and submitted: * `parsedRowCount`: how many rows were read from the file * `irmNumbers`: flat list of the submitted IRM numbers, in file order * `irms`: the same rows with `serialNo`, `irmDt`, `irmAdCode`, `irmIfscCode`, and `sbCumInvoiceNumber` Use `irms` rather than `irmNumbers` when reconciling, since an IRM number is not unique on its own: the same number can recur under a different AD code or date. ```json theme={"dark"} { "success": true, "data": { "dgftAckId": "ACK202404010001", "requestId": "IEC1234560120240001ABCDE12345", "ackStatus": "Validated", "recordResCount": 2, "errorDetails": [], "parsedRowCount": 2, "irmNumbers": ["IRM0000012345", "IRM0000012346"], "irms": [ { "serialNo": 1, "irmNumber": "IRM0000012345", "irmDt": "2024-01-10", "irmAdCode": "6390005", "irmIfscCode": "HDFC0000123", "sbCumInvoiceNumber": "INV-2024-001" }, { "serialNo": 2, "irmNumber": "IRM0000012346", "irmDt": "2024-01-11", "irmAdCode": "6390005", "irmIfscCode": "HDFC0000123", "sbCumInvoiceNumber": "INV-2024-002" } ] }, "statusCode": 200, "timestamp": "2026-07-22T13:00:00.000Z" } ``` ### Validation rules Validation runs entirely before anything is filed, so a file either passes in full or is rejected in full — a partially-filed batch is not possible. **Mandatory columns.** 19 of the 37 columns must have a value in every non-blank row: `Serial No`, `Upload Type`, `Branch Sl No`, `IRM IFSC Code`, `IRM AD Code`, `IRM Number`, `IRM Date`, `IRM FCC`, `IRM Purpose Code`, `IRM Remit Amt FCC`, `SB Cum Invoice Number`, `SB Cum Invoice Date`, `Port Code`, `Bill No`, `SB Cum Invoice FCC`, `SB Cum Invoice Value In FCC`, `Mapped IRM Amount FCC`, `Is Vostro`, `Is GST Avail`. Everything else is optional, except the two conditional GST columns below. The full column-by-column table is on the [template page](/api-reference/genebrc/bulk-upload-template). **Value rules.** | Rule | Detail | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Headers | Matched by name, case- and punctuation-insensitive. Order does not matter; unknown columns are ignored. | | Dates | `DD/MM/YYYY`, `DD-MM-YYYY`, `DDMMYYYY`, `YYYY-MM-DD`, or a real Excel date cell. Read **day-first**, normalised to `DDMMYYYY`. Impossible dates (`31/02/2024`) are rejected. | | Y/N columns | `Y` or `N`, either case. `Yes`, `True`, `1` are rejected. | | Numbers | Digits, as a number or as text. | | GST | If `Is GST Avail` = `Y`, both `GSTIN Invoice Number` and `GSTIN Invoice Date` are required. If `N`, both must be **empty** — a populated GSTIN column with `N` is an error. | | Blank rows | A row with no values in any column is skipped, not reported. | | File | `.xlsx` or `.xls`, max 5 MB, first worksheet only. | | Rows | At most **999** data rows (excluding the header). DGFT types `recordResCount` as `int(4)` and refuses a larger message, so a file over the cap is rejected with `400` before any row is validated. Split a bigger sheet into batches and upload them one at a time. | Codes are not validated against the DGFT masters at upload time, so a syntactically valid but wrong `IRM Purpose Code`, `Port Code` or currency code passes here and fails at DGFT. Check them against the annexures linked below. ### Row-level validation errors If the file fails validation, the API returns `400` with one entry per failing cell. `row` is the **Excel row number** (row 1 is the header, so data starts at row 2) and `field` is the JSON field name from the [annexure](/annexure/push-irm), not the column header: ```json theme={"dark"} { "statusCode": 400, "message": "Excel validation failed", "errors": [ { "row": 2, "field": "irmNumber", "message": "Required field \"irmNumber\" is missing" }, { "row": 4, "field": "isGstAvail", "message": "Invalid yesno value \"Yes\" in column \"Is GST Avail\". Expected Y or N." }, { "row": 7, "field": "irmDt", "message": "Invalid date value \"31/02/2024\" in column \"IRM Date\". Expected a date as DD/MM/YYYY, DD-MM-YYYY, DDMMYYYY, YYYY-MM-DD, or a real Excel date cell." } ] } ``` Each failing cell is reported exactly once: a cell whose value cannot be read is reported as invalid, never additionally as missing. ### Valid codes * [Purpose Codes](/annexure/purpose-codes), [Currency Codes](/annexure/currency-codes), and [Port Codes](/annexure/port-codes) for the code columns. * Field formats: [Push IRM Request Fields annexure](/annexure/push-irm). ### Next steps * [Get Request Status](/api-reference/genebrc/status) with the returned `requestId`. * [List generation requests](/api-reference/genebrc/list) across your history. * [Download certificates](/api-reference/genebrc/download) once processed. # Download Bulk Upload Template Source: https://docs.ebrc.in/api-reference/genebrc/bulk-upload-template GET /genebrc/bulk-upload/template Download the Excel bulk upload template for eBRC generation, with all 37 column headers and two example rows, then fill one row per IRM-to-invoice mapping. Download a pre-filled Excel (`.xlsx`) template with all required and optional column headers and two example rows. Use it as the starting point for a [bulk upload](/api-reference/genebrc/bulk-upload). Column headers are matched to fields by name, so keep the header text unchanged. ### One row per IRM-to-invoice mapping A row is one IRM against one shipping bill, Softex or invoice. Either side may repeat: * **One remittance settling several invoices.** Repeat the IRM columns on one row per invoice, with a different `SB Cum Invoice Number`, `Bill No` and `Mapped IRM Amount FCC` on each. The mapped amounts for one IRM must add up to no more than the amount still available on it; the whole file is refused if they do not. The two example rows show this: `IRMNUMBER123` maps 6,000 to shipping bill `1234567` and 4,000 to shipping bill `1234568`, out of a 10,000 remittance. * **Several remittances settling one invoice.** One row per remittance, each carrying the same `SB Cum Invoice Number`. DGFT issues one eBRC per row, so the invoice ends up with one certificate per remittance. Every row needs its own `Serial No`, from 1 upwards. The file is named `ebrc-bulk-upload-template.xlsx` and the sheet is named `EBRC Bulk Upload`. ### Request example ```bash theme={"dark"} curl --request GET \ --url 'https://api.ebrc.in/api/v1/genebrc/bulk-upload/template' \ --header 'x-api-key: ' \ --output ebrc-bulk-upload-template.xlsx ``` ### Template columns The template contains these 37 columns, in order. **19 are mandatory** — a row missing any of them is rejected with a per-row error and nothing in the file is filed. | # | Column header | Required | Example row value | | -- | --------------------------- | ----------- | ----------------- | | 1 | Serial No | **Yes** | `1` | | 2 | Upload Type | **Yes** | `101` | | 3 | Branch Sl No | **Yes** | `1` | | 4 | IRM IFSC Code | **Yes** | `HDFC0001234` | | 5 | IRM AD Code | **Yes** | `0510215` | | 6 | IRM Number | **Yes** | `IRMNUMBER123` | | 7 | IRM Date | **Yes** | `01/01/2024` | | 8 | IRM FCC | **Yes** | `USD` | | 9 | IRM Purpose Code | **Yes** | `P0102` | | 10 | IRM Remit Amt FCC | **Yes** | `10000` | | 11 | SB Cum Invoice Number | **Yes** | `1234567` | | 12 | SB Cum Invoice Date | **Yes** | `01/01/2024` | | 13 | Port Code | **Yes** | `INMAA1` | | 14 | Bill No | **Yes** | `SB123456` | | 15 | SB Cum Invoice FCC | **Yes** | `USD` | | 16 | SB Cum Invoice Value In FCC | **Yes** | `6000` | | 17 | Mapped IRM Amount FCC | **Yes** | `6000` | | 18 | Is Vostro | **Yes** | `N` | | 19 | Vostro Type | No | | | 20 | Mapped ORM Amount FCC | No | | | 21 | Is Third Party Export | No | `N` | | 22 | Commission Val Deduct | No | | | 23 | Commission Val Info | No | | | 24 | Discount Val Deduct | No | | | 25 | Discount Val Info | No | | | 26 | Insurance Val Deduct | No | | | 27 | Insurance Val Info | No | | | 28 | Other Deduction Deduct | No | | | 29 | Other Deductions Info | No | | | 30 | Freight Val Deduct | No | | | 31 | Freight Val Info | No | | | 32 | SAC Code 1 | No | | | 33 | SAC Code 2 | No | | | 34 | Service Type Modes Value | No | | | 35 | Is GST Avail | **Yes** | `N` | | 36 | GSTIN Invoice Number | Conditional | | | 37 | GSTIN Invoice Date | Conditional | | `Conditional` means required when `Is GST Avail` is `Y`, and it must be left **empty** when it is `N`. Full formats and constraints for each field are in the [Push IRM Request Fields annexure](/annexure/push-irm) under the field of the same name. The annexure documents the DGFT specification, which marks `mappedORMAmountFCC` and `isThirdPartyExport` as required. Our Excel validation treats both as optional and will accept a file without them. DGFT may still reject such a filing downstream, so populate them when they apply to your consignment. ### Column and value formats * **Header text is matched by name**, case-insensitively and ignoring spaces and punctuation. `SB Cum Invoice Number`, `sbcuminvoicenumber` and `Invoice Number` all resolve to the same field, so a header your ERP exports in a different case still works. Column *order* does not matter; only the header text does. Unrecognised columns are ignored. * **Dates** are accepted as `DD/MM/YYYY`, `DD-MM-YYYY`, `DDMMYYYY`, `YYYY-MM-DD`, or a real Excel date cell, and are normalised to DGFT's `DDMMYYYY` before filing. Ambiguous values are always read **day-first**: `01/02/2024` is 1 February, never 2 January. A well-formed but impossible date such as `31/02/2024` is rejected rather than filed. * **Y/N columns** (`Is Vostro`, `Is Third Party Export`, `Is GST Avail`) accept either case — `y` and `Y` both work. Anything else, including `Yes` and `True`, is rejected. * **Numeric columns** may arrive as numbers or as text; `"10000"` and `10000` are equivalent. * **Fully blank rows are skipped**, so trailing empty rows in the sheet are harmless. ### Valid codes * [Purpose Codes](/annexure/purpose-codes) for IRM Purpose Code * [Currency Codes](/annexure/currency-codes) for IRM FCC and SB Cum Invoice FCC * [Port Codes](/annexure/port-codes) for Port Code ### Next steps * [Upload the filled file](/api-reference/genebrc/bulk-upload). * Want the template pre-filled with real IRM data? Use [Load IRMs in Excel](/api-reference/irm/bulk-template). # Download eBRC PDF Source: https://docs.ebrc.in/api-reference/genebrc/download Download a generated eBRC certificate as a PDF by certificate number, returning the raw file with a Content-Disposition attachment header for saving locally. Download a generated eBRC certificate as a PDF. The certificate is fetched from the DGFT portal using the customer's stored DGFT credentials and cached, so the first call for a certificate may take longer than subsequent (cached) calls. Rate limited to **5 downloads per minute**. Cached results return quickly and still count toward the limit. ### Request ```bash theme={"dark"} curl -X GET \ "https://api.ebrc.in/api/v1/genebrc/download-pdf/{eBRCNumber}?platformCustomerId={id}" \ -H "x-api-key: " \ --output ebrc.pdf ``` A successful response is the raw `application/pdf` body with `Content-Disposition: attachment`. ### Handling credential failures Downloads use the customer's DGFT connection. If the customer **changed or reset their DGFT password**, that connection fails and the download returns a **structured error** you can act on programmatically. Branch on `errorCode`, never on the human-readable `message`. ```json theme={"dark"} { "statusCode": 409, "errorCode": "DGFT_CREDENTIALS_INVALID", "requiresPasswordUpdate": true, "message": "We could not sign in to the DGFT portal with your saved password. Please update it to download this certificate.", "causes": [ "Your DGFT portal password was recently changed", "The password on file has expired", "The account was locked after multiple failed attempts" ], "path": "/api/v1/genebrc/download-pdf/...", "timestamp": "2026-07-19T06:31:04.874Z" } ``` | `errorCode` | HTTP | `requiresPasswordUpdate` | What it means | What to do | | -------------------------- | ---- | ------------------------ | --------------------------------------- | ----------------------------------------------------------------- | | `DGFT_CREDENTIALS_INVALID` | 409 | `true` | Stored DGFT password was rejected | Update the customer's DGFT password (below), then retry | | `DGFT_ACCOUNT_LOCKED` | 409 | `true` | DGFT locked the portal account | Reset the password on the DGFT portal, update it here, then retry | | `DGFT_CREDENTIALS_MISSING` | 422 | `true` | No DGFT credentials on file | Link the customer's DGFT account first | | `EBRC_NOT_FOUND` | 404 | `false` | Certificate not on the portal yet | Retry later | | `DGFT_PORTAL_UNAVAILABLE` | 502 | `false` | DGFT portal was unreachable/misbehaving | Retry after a short delay | ### Recovering from `requiresPasswordUpdate` When `requiresPasswordUpdate` is `true`, submit the customer's **current** DGFT credentials (same username, new password) to update the stored password, then retry the download: ```bash theme={"dark"} curl -X POST \ "https://api.ebrc.in/api/v1/platform-customers/{id}/check-dgft-credentials" \ -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "dgftUsername": "", "dgftPassword": "" }' ``` On success (`201`) the stored credentials are replaced in place. Retry the download and it will use the updated password. Re-submitting the **same** DGFT username with a new password is an update. Submitting a **different** username is rejected, since that would be switching to a different DGFT account, not a password update. ### Next steps * [Fetch eBRC details](/api-reference/genebrc/fetch-details) to find `eBRCNumber` values. * [Validate Customer](/api-reference/customer/validate) to update stored DGFT credentials. * [Errors](/errors) for the full error body and status code reference. # Fetch eBRC Details Source: https://docs.ebrc.in/api-reference/genebrc/fetch-details POST /genebrc/fetch-details Fetch generated eBRC details for a platform customer over an issue-date range, including certificate numbers, dates, realised values, and status. Fetch eBRC details for a platform customer over an issue-date range. Results are fetched live and saved to your account. Use this after a request reaches `Processed` to pull the certificate metadata into your system. Limited to **10 calls per minute**. ### Request body example ```json theme={"dark"} { "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "iecCode": "0123456789", "eBRCIssueFromDt": "01012026", "eBRCIssueToDt": "31032026", "sbCumInvoiceNumber": null, "sbCumInvoiceDate": null } ``` ### Field notes | Field | Required | Description | | -------------------- | -------- | --------------------------------------------------------------------------------------- | | `platformCustomerId` | Yes | Platform customer UUID | | `iecCode` | Yes | IEC code linked to the customer's DGFT credentials | | `eBRCIssueFromDt` | Yes | Start of eBRC issue date range (`DDMMYYYY`) | | `eBRCIssueToDt` | Yes | End of eBRC issue date range (`DDMMYYYY`). **At most 3 months after `eBRCIssueFromDt`** | | `sbCumInvoiceNumber` | No | Filter by shipping bill cum invoice number (max 25 characters) | | `sbCumInvoiceDate` | No | Filter by shipping bill cum invoice date (`DDMMYYYY`) | DGFT accepts at most a **3-month** window per call, so a wider range is refused with a **400** before the request is forwarded. To cover a longer period, request consecutive windows of three months or less. ### Response example An array of certificates in the `data` field. An invoice settled by several remittances returns several entries, one certificate per IRM record DGFT processed, each with its own `eBRCNumber` and `realisedValueFCC`: ```json theme={"dark"} { "success": true, "data": [ { "iec": "0123456789", "eBRCNumber": "EBRC0000012345", "eBRCDate": "01042026", "eBRCStatus": "Issued", "billNo": "EXP-2024-0042", "sbCumInvoiceNumber": "7654321", "sbCumInvoiceDate": "15032026", "realisedValueFCC": 25000, "currencyCode": "USD", "realizationDt": "01042026" } ], "statusCode": 200, "timestamp": "2026-07-22T12:50:00.000Z" } ``` ### Errors * `422` / `409` for DGFT credential problems. See [DGFT credential error codes](/errors#dgft-credential-error-codes). * `429` beyond 10 calls per minute. See [rate limits](/authentication#rate-limits). ### Next steps * [Download the certificate PDF](/api-reference/genebrc/download) with the `eBRCNumber`. * [Get Request Status](/api-reference/genebrc/status) if a request is still processing. * [Currency Codes](/annexure/currency-codes) for `currencyCode` values. # List Generation Requests Source: https://docs.ebrc.in/api-reference/genebrc/list GET /genebrc List eBRC generation requests for a platform customer with filters and pagination, so you can track each submission and its processing status over time. List a platform customer's eBRC generation requests. Use this to find older request IDs, audit past submissions, or drive a status dashboard on your side. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/genebrc?platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2&status=Processed&page=1&limit=10' \ --header 'x-api-key: ' ``` Filters: `requestId`, `status`, `fromDate` / `toDate` (ISO dates), plus `page` / `limit` for pagination. `status` matches case-insensitively as a substring and accepts a comma-separated list, so `status=Failed,Error,Rejected` returns every refused filing in one call. ### Response A generation-request array in `data.data` plus a `meta` block with `total`, `page`, `limit` and `totalPages`, wrapped in the [standard envelope](/api-reference/introduction#response-envelope). Each row carries the request's identifiers and lifecycle fields — `requestId`, `iecNumber`, `recordResCount`, `uploadType`, `dgftAckId`, `status`, `processedAt`, `createdAt`, `updatedAt`. The submitted records and the certificate numbers are **not** included by default, because one request can cover thousands of invoices and every row on the page would carry them. Both are available on request through the two flags below. ### Getting your submitted records back Add `includeRecords=true` and each row gains `ebrcBulkGenDtos`: the records you sent in [Submit new IRMs](/api-reference/genebrc/push-irm), echoed back in the order you submitted them. ```json theme={"dark"} "ebrcBulkGenDtos": [ { "serialNo": 1, "irmNumber": "IRM-A", "sbCumInvoiceNumber": "INV-001", "irmRemitAmtFCC": 100.5 } ], "recordsTruncated": false ``` Use it to reconcile your side against what we hold, without spending a live DGFT call on [Fetch eBRC details](/api-reference/genebrc/fetch-details) just to read data back. It is opt-in for the same reason as `includeCertificates`, only more so: a record is a full \~20-field object rather than a two-string pair. When the flag is set, page size is capped at 5 and each request returns at most 2000 records, oldest-first by submission order. Past that, `recordsTruncated` is `true` for that row and the remainder is only retrievable through [Fetch eBRC details](/api-reference/genebrc/fetch-details). Before August 2026 the documented response listed `ebrcBulkGenDtos` unconditionally, but the API stopped returning it on 25 July 2026 when the list projection was slimmed to keep large batches from exhausting memory. `includeRecords=true` is the supported way to get it back. ### Getting eBRC numbers in this response Add `includeCertificates=true` and each request row gains a compact `certificates` array: the invoice number and eBRC number of every certificate issued for that request: ```json theme={"dark"} "certificates": [ { "sbCumInvoiceNumber": "INV-001", "ebrcNumber": "BRC0001" } ], "certificatesTruncated": false ``` Pass `ebrcNumber` straight to [Download eBRC PDF](/api-reference/genebrc/download). No DGFT call is made (these are read from data already stored), so you do not need [Fetch eBRC details](/api-reference/genebrc/fetch-details) just to obtain the number. It is opt-in because a generation request is a batch: one request can cover thousands of invoices. When the flag is set, page size is capped at 10 and each request returns at most 2000 certificates. If a request somehow exceeds that, `certificatesTruncated` is `true` for that row. The remaining certificates are only retrievable through [Fetch eBRC details](/api-reference/genebrc/fetch-details), which queries DGFT directly. ### `status` values | Value | Meaning | | ----------- | ------------------------------------------------------------- | | `Pending` | Request saved; submission in progress or not yet acknowledged | | `Validated` | Push accepted successfully | | `Failed` | Push acknowledgement failed | | `Processed` | Processing completed successfully | | `Errored` | Processing failed | | `Error` | Local/system failure | ### Next steps * [Get Request Status](/api-reference/genebrc/status) for a live DGFT status check. * [Fetch eBRC details](/api-reference/genebrc/fetch-details) for processed requests. * [Submit new IRMs](/api-reference/genebrc/push-irm). # Submit IRMs for eBRC Generation Source: https://docs.ebrc.in/api-reference/genebrc/push-irm POST /genebrc/push-irm Submit one or many IRM-to-invoice mappings to DGFT for eBRC generation as JSON, then poll the returned requestId for status while DGFT processes the request. Submit one or more IRM-to-invoice mappings for eBRC generation. You get back a DGFT acknowledgement with a `requestId`; keep it and [poll status](/api-reference/genebrc/status). Limited to **10 calls per minute**. Available in both test and live mode. In live mode, acknowledgement typically arrives within about **2 hours**. See the full field list and constraints in the [Push IRM Request Fields annexure](/annexure/push-irm). Dates are `DDMMYYYY` strings. The message-level `uploadType` is a string code and the item-level one is a number: 101 Direct Export, 102 Softex, 103 Service Non IT, 104 Deemed. ### Request body example ```json theme={"dark"} { "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "recordResCount": 1, "uploadType": "101", "decalarationFlag": "Y", "ebrcBulkGenDtos": [ { "serialNo": 1, "uploadType": 101, "branchSlNo": 0, "irmIfscCode": "HDFC0000123", "irmAdCode": "6390005", "irmNumber": "IRM0000012345", "irmDt": "01042024", "irmFCC": "USD", "irmPurposeCode": "P0101", "irmRemitAmtFCC": 25000, "sbCumInvoiceNumber": "7654321", "sbCumInvoiceDate": "15032024", "portCode": "INMAA1", "billNo": "EXP-2024-0042", "sbCumInvoiceFCC": "USD", "sbCumInvoiceValueinFCC": 25000, "mappedIRMAmountFCC": 25000, "isVostro": "N", "isGstAvail": "N", "gstinInvoiceNumber": null, "gstinInvoiceDate": null } ] } ``` `recordResCount` must equal the number of entries in `ebrcBulkGenDtos`. `decalarationFlag` keeps its wire spelling (as per DGFT specification). When `isGstAvail` is `"Y"`, `gstinInvoiceNumber` and `gstinInvoiceDate` become mandatory; when `"N"`, they must be `null`. **For a Direct Export (`uploadType` 101), `sbCumInvoiceNumber` is the shipping bill number — digits only, at most 7.** The field carries a different document per `uploadType` (shipping bill for 101, SOFTEX for 102, invoice number for 103), and only the Direct Export case has the tighter rule. Your own invoice reference goes in `billNo`: ```json theme={"dark"} "sbCumInvoiceNumber": "7654321", // shipping bill number "billNo": "EX/25-26/028" // your invoice reference ``` Sending an invoice-style value such as `EX/25-26/028` in `sbCumInvoiceNumber` returns **400** with `sbCumInvoiceNumber ... is not a shipping bill number`. Swapping these two fields is the most common cause of a rejected Direct Export. See the [field reference](/annexure/push-irm) for all four upload types. ### Response example ```json theme={"dark"} { "success": true, "data": { "dgftAckId": "ACK202404010001", "requestId": "IEC1234560120240001ABCDE12345", "ackStatus": "Validated", "recordResCount": 1, "errorDetails": [] }, "statusCode": 200, "timestamp": "2026-07-22T10:35:00.000Z" } ``` ### `ackStatus` values | Value | Meaning | | ----------- | ------------------------------------------ | | `Validated` | Request accepted for processing | | `Failed` | Acknowledgement failed, see `errorDetails` | ### Errors * `400` with `message: "Validation failed"` and per-field `errors`. The exact messages are listed under [common validation errors](/errors#common-validation-errors). * `422` / `409` for DGFT credential problems. See [DGFT credential error codes](/errors#dgft-credential-error-codes). ### Valid codes * [Purpose Codes](/annexure/purpose-codes) for `irmPurposeCode` * [Currency Codes](/annexure/currency-codes) for `irmFCC` and `sbCumInvoiceFCC` * [Port Codes](/annexure/port-codes) for `portCode` ### Next steps * [Get Request Status](/api-reference/genebrc/status) with the returned `requestId`. * [List generation requests](/api-reference/genebrc/list) across your history. * Prefer Excel? [Bulk upload](/api-reference/genebrc/bulk-upload) instead. # Get Request Status Source: https://docs.ebrc.in/api-reference/genebrc/status POST /genebrc/status Poll the processing status of a submitted eBRC generation request by requestId. In live mode, acknowledgement typically arrives within about 2 hours of submission. Check processing status for a previously submitted generation request, using the `requestId` returned by [Submit IRMs](/api-reference/genebrc/push-irm) or [Bulk Upload](/api-reference/genebrc/bulk-upload). Available in both test and live mode. In live mode, acknowledgement typically arrives within about **2 hours**; polling earlier may return an incomplete or unchanged status. ### Request body example ```json theme={"dark"} { "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "requestId": "IEC1234560120240001ABCDE12345" } ``` ### Response example The per-record results come back in `ebrcBulkGenStatusLst` (field name as returned on the wire): ```json theme={"dark"} { "success": true, "data": { "dgftAckId": "ACK202404010001", "requestId": "IEC1234560120240001ABCDE12345", "recordResCount": 1, "recordProCount": 1, "recordFailCount": 0, "processingStatus": "Processed", "ebrcBulkGenStatusLst": [ { "serialNo": "1", "irmNumber": "IRM0000012345", "irmDt": "01042024", "iecNumber": "0123456789", "sbCumInvoiceNumber": "7654321", "sbCumInvoiceDate": "15032024", "portCode": "INMAA1", "eBRCNumber": "EBRC0000012345", "billNo": "EXP-2024-0042", "eBRCDt": "01042024", "fobFCC": 25000, "fcc": "USD", "processingStatus": "Processed", "errorDetails": [] } ] }, "statusCode": 200, "timestamp": "2026-07-22T12:40:00.000Z" } ``` ### `processingStatus` values | Value | Meaning | | ----------- | ------------------------------------- | | `Processed` | All records processed successfully | | `Errored` | Processing failed, see `errorDetails` | Per-record status in `ebrcBulkGenStatusLst[].processingStatus` uses the same values. ### Next steps * [Fetch eBRC details](/api-reference/genebrc/fetch-details) once processed. * [Download the certificate PDF](/api-reference/genebrc/download) with the `eBRCNumber`. * [List generation requests](/api-reference/genebrc/list) to find older request IDs. # Introduction Source: https://docs.ebrc.in/api-reference/introduction Conventions shared by every eBRC API endpoint: base URLs, x-api-key authentication, the JSON response envelope, pagination, date formats, and error handling. The eBRC API is a REST API. Requests and responses are JSON over HTTPS, authenticated with an API key. ## Base URL Every endpoint lives under one base URL: ```bash theme={"dark"} https://api.ebrc.in/api/v1 ``` There is no separate sandbox host. A `dev_` key runs the request in test mode and a `prod_` key files for real, so going live means swapping the key and nothing else. See [Base URL and Modes](/environments). ## Authentication Every endpoint requires an API key in the request headers, alongside a JSON content type: ```bash theme={"dark"} x-api-key: Content-Type: application/json ``` Rate limits are published per endpoint. See [Authentication](/authentication) for limits, key handling, and the exact auth error responses. ## Processing timelines | Event | When services / status are ready | | ----------------------------------- | ------------------------------------------------------------------------ | | Customer validation | Services enabled after **24 hours** | | Push IRM (`POST /genebrc/push-irm`) | In live mode, acknowledgement typically arrives within about **2 hours** | ## Response envelope Every successful JSON response is wrapped in the same envelope. The schemas documented on each endpoint describe the `data` field: ```json theme={"dark"} { "success": true, "data": { }, "statusCode": 200, "timestamp": "2026-07-22T10:15:04.874Z" } ``` File downloads (Excel templates, certificate PDFs) return the raw file body instead, with a `Content-Disposition: attachment` header. Error responses are not wrapped; they use a flat shape with `statusCode`, `message`, and often a machine-readable `errorCode` and a `requestId`. The full shape, every status code, and the exact validation messages are documented on the [Errors](/errors) page. ## Pagination List endpoints accept `page` (starts at 1) and `limit` (default 10, maximum 100) query parameters. Customer lists also accept `search` to filter by partial name or email. ## Date formats Filing date fields (`irmDt`, `sbCumInvoiceDate`, `eBRCIssueFromDt`, and friends) are `DDMMYYYY` strings, for example `01042024`. Timestamps generated by the API (`createdAt`, `timestamp`) are ISO 8601. ## Need help? Email [amin@eximfiles.io](mailto:amin@eximfiles.io) and quote the requestId from your API response. # Load IRMs in Excel Source: https://docs.ebrc.in/api-reference/irm/bulk-template GET /irm/bulk-template Download an Excel bulk template pre-filled with a platform customer's IRM data, so you only add the invoice columns before uploading it back to generate eBRCs. Download an Excel (`.xlsx`) bulk-upload template pre-filled with the platform customer's IRM remittance data. Each saved IRM becomes one row with its serial number, IRM columns, and safe defaults (`Is Vostro`, `Is Third Party Export`, and `Is GST Avail` set to `N`); the invoice columns are left blank for you to fill. Limited to **10 calls per minute**. The columns are identical to the [bulk upload template](/api-reference/genebrc/bulk-upload-template), so a filled file can be [uploaded straight back](/api-reference/genebrc/bulk-upload). ### Request example ```bash theme={"dark"} curl --request GET \ --url 'https://api.ebrc.in/api/v1/irm/bulk-template?platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2' \ --header 'x-api-key: ' \ --output ebrc-bulk-base.xlsx ``` ### Response The raw `.xlsx` file with `Content-Disposition: attachment`. The file is named `ebrc-bulk-base-.xlsx` and the sheet is named `EBRC Bulk Upload`. ### Next steps * Fill the invoice columns using the [field reference](/annexure/push-irm). * [Upload the filled file](/api-reference/genebrc/bulk-upload) to generate in bulk. * Prefer JSON? [Submit IRMs directly](/api-reference/genebrc/push-irm). # List Saved IRMs Source: https://docs.ebrc.in/api-reference/irm/list GET /irm Read a platform customer's already-fetched inward remittances (IRMs) from your account without a live refresh, with pagination for reviewing saved records. Return the customer's IRMs from your account's saved data, without a live refresh. Use this for everyday reads and pagination; run [Fetch IRM List](/api-reference/irm/post) first, and again whenever you want fresh data. ### Request example ```bash theme={"dark"} curl --location 'https://api.ebrc.in/api/v1/irm?platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2&page=1&limit=10' \ --header 'x-api-key: ' ``` Optional filters: `irmNumber`, `fromDate`, `toDate` (ISO dates), and `page` / `limit` for pagination. ### Response Same paginated shape as [Fetch IRM List](/api-reference/irm/post): an IRM array in `data.data` plus a `meta` block with `total`, `page`, `limit`, and `totalPages`, wrapped in the [standard envelope](/api-reference/introduction#response-envelope). ### Next steps * [Fetch IRM List](/api-reference/irm/post) to refresh the live data first. * [Submit IRMs for generation](/api-reference/genebrc/push-irm). * [Download IRMs as Excel](/api-reference/irm/bulk-template). # Fetch IRM List Source: https://docs.ebrc.in/api-reference/irm/post POST /irm/refresh Refresh inward remittances (IRMs) for a platform customer and return the latest records, the first step before mapping them and generating an eBRC. Pull the customer's latest inward remittances (IRMs) and return them paginated. This performs a live refresh on every call and is limited to **6 calls per minute**; for everyday reads of already-fetched data, use [List saved IRMs](/api-reference/irm/list) instead. ### Request example ```bash theme={"dark"} curl --location --request POST 'https://api.ebrc.in/api/v1/irm/refresh?platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2&page=1&limit=10' \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data '' ``` Optional filters: `irmNumber`, `fromDate`, `toDate` (ISO dates), and `page` / `limit` for pagination. ### Response example `remitterCountry` is an ISO 3166-1 alpha-3 code — see [Country Codes](/annexure/country-codes). ```json theme={"dark"} { "success": true, "data": { "data": [ { "id": "3d1f7a2b-8c4e-4f5a-9b6d-2e1c0f9a8b7c", "irmNumber": "IRM0000012345", "irmIssueDate": "2024-04-01", "irmStatus": "fresh", "ifscCode": "HDFC0000123", "remittanceAdCode": "6390005", "remittanceDate": "2024-04-01", "remittanceFCC": "USD", "remittanceFCCAmount": 25000, "irmAvailableAmt": 25000, "irmUtilizedAmt": 0, "iecCode": "0123456789", "remitterName": "Acme Trading LLC", "remitterCountry": "USA", "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "createdAt": "2026-07-22T10:30:00.000Z", "updatedAt": "2026-07-22T10:30:00.000Z" } ], "meta": { "total": 1, "page": 1, "limit": 10, "totalPages": 1 } }, "statusCode": 200, "timestamp": "2026-07-22T10:30:01.000Z" } ``` ### Errors * `422` / `409` when the customer's DGFT credentials are missing or stale. See [DGFT credential error codes](/errors#dgft-credential-error-codes). * `409` `DGFT_IP_ACTIVATION_PENDING` with a `retryAfter` timestamp during the 24 hours after linking an exporter who already held DGFT API credentials. The refresh is remembered and runs automatically once DGFT opens access. See [the 24-hour activation](/errors#the-24-hour-activation-and-retryafter). * `429` beyond 6 calls per minute. See [rate limits](/authentication#rate-limits). ### Next steps * [List saved IRMs](/api-reference/irm/list) for reads without a live refresh. * [Submit IRMs for generation](/api-reference/genebrc/push-irm). * [Download IRMs as Excel](/api-reference/irm/bulk-template) to work in a spreadsheet. # API Terms Source: https://docs.ebrc.in/api-terms What the eBRC API Terms mean for your integration: keys and attribution, fair use, environments, end-customer mandates, and prohibited integrations, in plain language. The short version of the rules your integration runs under. This page is an informational summary. The canonical API Terms live at [ebrc.in/api-terms](https://ebrc.in/api-terms) and govern if anything here reads differently. Holding or using an API key is acceptance of them. ## The rules, in plain language * **Keys and attribution.** Every call made with your account's key is your instruction, whoever in fact made it. Keys are shown once, non-transferable, and yours to safeguard; replacements are issued on request through support. * **Fair use.** The published [rate limits](/authentication#rate-limits) and the [free general-use allowance](/pricing) form part of the terms. Circumventing limits, including by key rotation or distributed calling, is a material breach. * **Test and live modes.** Your key's prefix decides the mode: `dev_` is test, `prod_` is live. Nothing filed in test mode is legally binding, and test artefacts must not be presented as real certificates. Live access follows the Master Platform Agreement, e-signed in the console, and every certificate records the mode that produced it. * **End-customer mandates.** Filing for an exporter entity requires that entity's own recorded authorisation, granted at its connection step. A platform must be able to evidence the mandate for every entity it files for. * **Data.** What you submit or retrieve is your (or your customer's) content; personal data within it is handled under the [Privacy Policy](https://ebrc.in/privacy-policy). You warrant the DPDP notices and consents behind any end-customer data you transmit. * **Prohibited.** Misrepresenting identity or authority, filing without a mandate, reselling raw API access without a written agreement, publishing benchmarks without consent, and security testing outside coordinated disclosure to [amin@eximfiles.io](mailto:amin@eximfiles.io). * **Change and precedence.** The API evolves with reasonable notice of breaking changes and carries no SLA unless a signed agreement says otherwise. If documents conflict: signed agreement, then API Terms, then Terms of Service, then this documentation. ## Read the full text * [API Terms](https://ebrc.in/api-terms), the canonical document * [Terms of Service](https://ebrc.in/terms-of-service) * [Privacy Policy](https://ebrc.in/privacy-policy) # Authentication Source: https://docs.ebrc.in/authentication Authenticate the eBRC API with a single x-api-key header over HTTPS. Covers key issuance, contract-gated live access, and per-endpoint rate limits. Every request to the eBRC API authenticates with a single header over HTTPS: ```bash theme={"dark"} x-api-key: ``` The key also selects the mode. Every request goes to the same [base URL](/environments); a `dev_…` key runs it in test mode and a `prod_…` key files for real. | Key prefix | Mode | | ---------- | ---------------------------------------------------- | | `dev_…` | Test: nothing is legally binding, nothing is metered | | `prod_…` | Live: real, legally binding certificates | Because the prefix is what the API reads, a mode header sent alongside a key is ignored: a test key cannot be talked into acting live. ## Getting a key * Test and live keys are issued as a pair, shown once at issue, and never stored in a readable form: keep yours somewhere safe. * [Create your account in the eBRC API console](https://console.ebrc.in/sign-up) and request access there; issued keys appear in the console, where you can view and copy them. * Live (`prod_`) keys work after the Master Platform Agreement — covering production access and mutual confidentiality — is e-signed in the console. * You can hold several active keys of each type, so a key can be rotated without downtime. Revoke the old one when the new one is live. * Help, or a key reissue: [amin@eximfiles.io](mailto:amin@eximfiles.io). Keep API keys server side. Never embed them in client-side code or commit them to version control. ## Authentication errors These are the exact responses the API returns: | HTTP | `message` | Why | | ---- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | 401 | `No API key provided` | The `x-api-key` header is missing | | 401 | `Invalid API key` | The key does not match any active key | | 403 | `Only platform users can access this resource` | The key is valid but not a platform key | | 403 | `Master Platform Agreement not signed yet` | Contract signing is not complete for this account | | 403 | `Platform customer not accessible` | The exporter belongs to another platform, or to the other mode: a `dev_` key cannot reach a customer created with a `prod_` key | The error body follows the standard [error shape](/errors). ## Rate limits Limits are applied per API key (per client IP when unauthenticated) over a 60 second window: | Endpoint | Limit per minute | | ------------------------------------------------------ | ---------------- | | `POST /platform-customers/{id}/check-dgft-credentials` | 4 | | `POST /genebrc/bulk-upload` | 5 | | `GET /genebrc/download-pdf/{eBRCNumber}` | 5 | | `POST /irm/refresh` | 6 | | `POST /genebrc/push-irm` | 10 | | `POST /genebrc/fetch-details` | 10 | | `GET /irm/bulk-template` | 10 | | All other endpoints | 100 | When a limit is exceeded the API returns **429** with the message `Too many requests. Please try again later.` The API does not currently send rate limit headers, so back off and retry after a short delay rather than reading headers. ## Free general use The API is free for general use: the rate limits above, plus a published allowance of 250 live certificates a month and 10 exporter entities in either mode, with test filing not metered. The full definition and the quote path for volume live on the [Pricing](/pricing) page. ## Related * [Base URL and Modes](/environments) explains the one base URL and how a key's prefix selects test or live. * [Errors](/errors) documents the error body and common failures. * [Quick Start](/quick-start) makes your first authenticated calls. # Base URL and Modes Source: https://docs.ebrc.in/environments The eBRC API has one base URL for everything. Your API key decides the mode: dev_ keys run in test, prod_ keys file for real. Build with the test key, then swap the key to go live. The eBRC API has a **single base URL**. There is no separate sandbox host: ```bash theme={"dark"} https://api.ebrc.in/api/v1 ``` Which mode a request runs in is decided by **the key you send**, not by the host you call. | Key prefix | Mode | What it is for | | ---------- | -------- | ------------------------------------------------------------------------------------ | | `dev_…` | **Test** | Building and testing. Nothing filed here is legally binding, and nothing is metered. | | `prod_…` | **Live** | Real filings. Certificates generated here are real and legally binding. | Going live is a credential change, not a URL change: swap the key, leave the base URL and every request untouched. Generation endpoints work in both modes. In live mode, a generation request is typically acknowledged within about 2 hours. ## How the mode is decided * **The key prefix is authoritative.** `dev_` → test, `prod_` → live. This is read from the `x-api-key` header on every request. * **A request header can never change it.** If a key is present, mode headers are ignored entirely, so nothing you send alongside a test key can make it act live. * **Test and live data are isolated.** Every exporter, remittance and generation request belongs to one mode. A test key presented against a live exporter is rejected with the same `403` as a key from another platform. * **Every generation request records the mode it was filed in**, so a test run is never mistaken for a live filing. ## Working across both modes Test and live keys are issued as a pair, so you can hold both at once (one in staging, one in production) and point them at the same base URL. Because the two modes are isolated, records do not carry over: exporters you created with a test key have to be created again with the live key before you can file for them. ## Data extraction [Shipping bill extraction](/api-reference/extraction/introduction) runs on the eBRC API, at the same base URL as everything else. It authenticates with your ordinary `dev_`/`prod_` eBRC key. There is no separate extraction credential. The parse itself carries **no mode**: a shipping bill parses identically in test and live, no DGFT sandbox is involved and nothing is filed. The allowance, however, is split by key: a `prod_` key spends the live budget and a `dev_` key spends the test budget, and the two do not draw on each other. The figures are on the [pricing page](/pricing). | Environment | Base URL | | ----------- | ---------------------------- | | **Both** | `https://api.ebrc.in/api/v1` | ## Related * [Quick Start](/quick-start) walks the full flow end to end. * [Authentication](/authentication) covers API keys and rate limits. * [API Reference](/api-reference/introduction) documents the response envelope and conventions. # Errors Source: https://docs.ebrc.in/errors Error handling for the eBRC API: the error body shape, every HTTP status code, common validation messages with exact text, and DGFT credential error codes. Successful responses are wrapped in the standard envelope documented in the [API Reference introduction](/api-reference/introduction#response-envelope). Errors are not wrapped; they use the shape below. ## Error body ```json theme={"dark"} { "statusCode": 400, "timestamp": "2026-07-22T10:15:04.874Z", "path": "/api/v1/genebrc/push-irm", "method": "POST", "message": "Validation failed", "errors": [ "uploadType: uploadType must be a string", "ebrcBulkGenDtos.0.serialNo: serialNo must be a number conforming to the specified constraints" ], "error": "Bad Request", "requestId": "b3f1c2d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d" } ``` | Field | Always present | Meaning | | ------------------------ | -------------- | ----------------------------------------------------------- | | `statusCode` | Yes | HTTP status code | | `timestamp` | Yes | When the error occurred (ISO 8601) | | `path` | Yes | The request path | | `method` | Yes | The HTTP method | | `message` | Yes | Human-readable summary. Do not branch on it | | `errors` | No | Per-field validation messages | | `error` | No | Error type, e.g. `Bad Request` | | `errorCode` | No | Stable machine-readable code. Branch on this | | `requiresPasswordUpdate` | No | Whether re-submitting DGFT credentials would resolve it | | `causes` | No | Human-readable probable causes, safe to display | | `requestId` | No | Quote this to [amin@eximfiles.io](mailto:amin@eximfiles.io) | ## HTTP status codes | Code | Meaning | | :--: | ------------------------------------------------------------------------ | | 200 | Request successful | | 201 | Resource created (customer create, credential validation) | | 400 | Invalid request parameters or failed validation | | 401 | Missing or invalid API key | | 403 | Key valid but not permitted, or contract signing incomplete | | 404 | Resource not found | | 409 | DGFT credential conflict, see the credential error codes below | | 422 | DGFT configuration issue, for example no credentials on file | | 429 | Rate limit exceeded, see [rate limits](/authentication#rate-limits) | | 500 | Internal server error | | 502 | The government system was unreachable, retry after a short delay | | 503 | Service temporarily unavailable, retry after a short delay | | 504 | The government system did not respond in time, retry after a short delay | ## Common validation errors Validation failures return **400** with `message: "Validation failed"` and an `errors` array. Each entry is `field: constraint`. The exact messages you will see most often: | `errors` entry | What it means | | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `uploadType: uploadType must be a string` | The message-level `uploadType` is a string code, e.g. `"101"` | | `ebrcBulkGenDtos.0.uploadType: uploadType must be a number conforming to the specified constraints` | The item-level `uploadType` is a number, e.g. `101` | | `sbCumInvoiceNumber: ... these two fields look swapped` | `sbCumInvoiceNumber` holds an invoice reference while `billNo` holds a valid shipping bill number. On `uploadType` `101`, `sbCumInvoiceNumber` takes the **shipping bill** and `billNo` takes the **invoice** — the opposite of what the two names suggest. Exchange the values | | `sbCumInvoiceNumber: ... is not a shipping bill number: a direct export carries the shipping bill number, which is digits only` | `uploadType` is `101` (Direct Export), so `sbCumInvoiceNumber` must be the shipping bill number — digits only, at most 7. An invoice reference belongs in `billNo`. See the [field reference](/annexure/push-irm) | | `sbCumInvoiceNumber: sbCumInvoiceNumber is N digits; a shipping bill number cannot be more than 7` | Send the shipping bill number on its own, not a longer combined reference | | `isGstAvail: isGstAvail must be one of the following values: Y, N` | Only `Y` or `N` is accepted | | `gstinInvoiceNumber: gstinInvoiceNumber should not be empty` | Mandatory because `isGstAvail` is `Y` | | `gstinInvoiceNumber: gstinInvoiceNumber must be empty` | Must be `null` because `isGstAvail` is `N` | | `email: email must be an email` | Customer email failed format validation | | `property x should not exist` | Unknown fields are rejected, check spelling against the [field reference](/annexure/push-irm) | Bulk Excel uploads return row-level errors instead, each with `row`, `field` and `message`. See [Bulk Upload via Excel](/api-reference/genebrc/bulk-upload). ## Warnings on an accepted filing A successful `push-irm` response may carry a `warnings` array. These are **not** failures — the filing was accepted and forwarded to DGFT — but each one is something DGFT is likely to reject later, surfaced now so you can act before the status poll rather than after it. They come from comparing your filing against the IRM records we hold for that exporter: | Warning | What it means | | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `no IRM with this number is on record for this exporter` | We hold no IRM row for that number, so the available-amount check could not run. Usually the remittance predates the last IRM refresh — refresh IRMs for that period. Otherwise check the number (DGFT answers **ERR18**) | | `irmIfscCode stated as "X" but the IRM on record says "Y"` | **ERR15** — the IFSC does not match the IRM | | `irmAdCode stated as ...` | **ERR16** — invalid AD code | | `irmDt stated as ...` | **ERR19** — IRM number and date do not combine | | `irmFCC stated as ...` | **ERR20** — currency does not match the IRM shared by the bank | | `irmPurposeCode stated as ...` | **ERR22** — purpose code does not match the bank's record | | `irmPurposeCode P0301 is a "Travel" code, and 101 (Direct Export) is an export of goods` | **ERR39** — the purpose code's category does not suit the export type. See below | These are warnings rather than errors because our IRM records are a snapshot of what DGFT last shared, and DGFT's copy is authoritative. Refusing a filing on a disagreement would let a stale or incomplete local copy block a correct submission. A clean filing carries no `warnings` key at all. ### Purpose code and export type DGFT maps purpose codes to export types by [its own published rules](https://www.dgft.gov.in/CP/?opt=eBRCRules), and answers **ERR39** when a filing does not follow them. Those rules are not reproduced in the technical specification, so this check is inferred from the categories in [Purpose Codes](/annexure/purpose-codes) rather than read from the rulebook — which is why it warns and never refuses. Two cases are flagged, both drawn from category `01` being titled "Exports (of Goods)": | You sent | Warned because | | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | A non-goods code on `uploadType` `101` or `104` | A direct or deemed export moves goods, which normally carries a category `01` code such as `P0101` or `P0102` | | A category `01` code on `uploadType` `103` | A Service (Non-IT) export is not a movement of goods | Three cases are deliberately **never** warned about, because the annexure does not support the inference: * **Any category on `uploadType` `102` (Softex).** The category `01` descriptions name SOFTEX themselves — `P0101` is "covered under GR/PP/SOFTEX/EC copy of shipping bills" and `P0103` is "to be covered later by GR/PP/SOFTEX/SDF". * **Category `15` (Others)** — ambiguous by name. * **Category `17` (Manufacturing)** — manufacturing services on physical inputs owned by someone else, where which export type applies is exactly what DGFT's rules page decides. A warning here does not mean the filing was rejected. It was accepted and forwarded; check the purpose code against the IRM your bank shared before DGFT's status poll answers. ## DGFT error codes DGFT validates every record on its own side, hours after the filing is accepted. Its codes arrive in `errorDetails` on the [status response](/api-reference/genebrc/status), per record. The codes we can prevent at submission are listed under [common validation errors](#common-validation-errors) above; the rest are DGFT's own. | Code | Meaning | | ------- | ----------------------------------------------------------------- | | `ERR01` | Invalid client id and client secret | | `ERR02` | Invalid header parameters, a mandatory parameter is missing | | `ERR03` | Invalid JSON | | `ERR04` | Invalid secret value | | `ERR05` | Invalid encryption key, could not decrypt | | `ERR06` | Digital signature mismatch in record verification | | `ERR07` | Invalid message id, length cannot exceed 50 | | `ERR08` | Count mismatch between header and data | | `ERR09` | Duplicate message id | | `ERR10` | Invalid serial number | | `ERR11` | Duplicate serial number in the same message | | `ERR12` | Invalid club id | | `ERR13` | Duplicate club id in the same message | | `ERR14` | Invalid IFSC code, length must be 11 | | `ERR15` | IFSC code does not match the IFSC on the IRM | | `ERR16` | Invalid AD code | | `ERR17` | Invalid IRM date, must be `DDMMYYYY` | | `ERR18` | Invalid IRM number | | `ERR19` | Invalid IRM number and date combination | | `ERR20` | Invalid IRM FCC, must match the FCC on the IRM shared by the bank | | `ERR21` | Invalid purpose code | | `ERR22` | Purpose code does not match the bank's record | | `ERR23` | IRM available amount does not match DGFT's | | `ERR24` | Invalid `paymentDate`, null or wrong format | | `ERR25` | Invalid shipping bill number, cannot exceed 7 digits | | `ERR26` | Invalid SOFTEX number | | `ERR27` | Invalid invoice number | | `ERR28` | Invalid shipping bill / SOFTEX / invoice date | | `ERR29` | Invalid port code, cannot exceed 6 characters | | `ERR30` | Port code does not exist in DGFT's master data | | `ERR31` | Invalid `billNo`, cannot exceed 20 characters | | `ERR32` | Invalid `isVostro`, allowed values are `Y` / `N` | | `ERR33` | Invalid vostro type, allowed values are `SVRA` / `NVRA` | | `ERR34` | Invalid third-party export flag, allowed values are `Y` / `N` | | `ERR35` | Invalid ORM amount | | `ERR36` | Declaration flag is missing | | `ERR37` | Invalid value for the declaration flag | | `ERR38` | Total IRM mapped exceeds the available amount | | `ERR39` | Invoice and purpose code mapping is not correct | Two of these describe things this API does not send. `ERR24` refers to a `paymentDate` field that appears in no request we make, and `ERR12` / `ERR13` refer to a `clubID` that DGFT's own field tables do not document. They are listed for completeness. ## DGFT upstream error codes `fetchIRMDetails`, `fetchEBRCDetails` and `getRequestStatus` all reach DGFT's GenEBRC API. DGFT does not use HTTP status the way you would expect: an empty result set, a malformed request and a genuine outage all arrive from them as `HTTP 500`, distinguished only by a message in the body. We classify them so you can branch on `errorCode` instead: | `errorCode` | HTTP | Retry? | What it means | | ---------------------- | :--: | :----: | ---------------------------------------------------------------------------------- | | `DGFT_NO_DATA` | 404 | No | DGFT matched no records. Usually the date range does not cover the IRM — see below | | `DGFT_INVALID_REQUEST` | 422 | No | DGFT rejected a field's format or width. The message carries their exact wording | | `DGFT_API_TIMEOUT` | 504 | Yes | DGFT did not respond in time. Retry in a few minutes | | `DGFT_API_UNAVAILABLE` | 503 | Yes | Repeated upstream failures; requests are being held back briefly. Retry shortly | | `DGFT_API_ERROR` | 502 | Maybe | Anything else DGFT returned. Their text is preserved in `message` | **`DGFT_NO_DATA` is not an error in your integration.** It is DGFT's way of saying "nothing matched". The most common cause is a date range that does not cover the IRM you asked for. ## Fetching IRMs by number and date `POST /irm/refresh` accepts an `irmNumber`, a `fromDate`/`toDate` range, or both. DGFT applies **both filters together** — it does not look an IRM up by number alone — so an IRM issued outside the requested period comes back as `DGFT_NO_DATA` even though the number is perfectly valid. | You send | What happens | | ------------------------------------ | -------------------------------------------------------- | | `fromDate` + `toDate` | Used exactly as given. Maximum span **36 months** | | `irmNumber` only, IRM already synced | The window is derived from the IRM we hold. Fastest path | | `irmNumber` only, IRM not yet synced | A three-year window is searched automatically | | Neither | A three-year window is searched | A range wider than 36 months is refused locally with **400** before any DGFT call: ```json theme={"dark"} { "statusCode": 400, "message": "The IRM date range 01012021 to 31122026 is longer than the 36 months this API fetches in one call. Request a narrower window.", "error": "Bad Request" } ``` If a `DGFT_NO_DATA` surprises you for an IRM you know exists, widen `fromDate`/`toDate` around the period the remittance was actually received, or drop them entirely to search three years. ## DGFT credential error codes Endpoints that operate on a customer's DGFT connection return a structured error when that connection fails. Branch on `errorCode`, never on `message`: | `errorCode` | HTTP | `requiresPasswordUpdate` | What to do | | ---------------------------- | :--: | :----------------------: | ---------------------------------------------------------------------------------------------------------------------------------------- | | `DGFT_CREDENTIALS_INVALID` | 409 | `true` | [Update the stored DGFT password](/api-reference/customer/validate), then retry | | `DGFT_ACCOUNT_LOCKED` | 409 | `true` | Reset the password on the DGFT portal, update it here, then retry | | `DGFT_CREDENTIALS_MISSING` | 422 | `true` | [Link the customer's DGFT account](/api-reference/customer/validate) first | | `DGFT_IP_ACTIVATION_PENDING` | 409 | `false` | Nothing. DGFT activates our IP on this account after 24 hours; retry at `retryAfter`. See below | | `DGFT_ACCESS_FORBIDDEN` | 409 | `false` | DGFT refused the access token and no activation window explains it. Check the account's API whitelist and credentials on the DGFT portal | | `EBRC_NOT_FOUND` | 404 | `false` | Certificate not on the portal yet, retry later | | `DGFT_PORTAL_UNAVAILABLE` | 502 | `false` | Retry after a short delay | ### The 24-hour activation, and `retryAfter` Most exporters have never generated DGFT API credentials. Validation creates a fresh registration with our IP on it, DGFT enables it immediately, and the first IRM refresh seconds later works. An exporter who **already held DGFT API credentials** takes a different path. We reuse those credentials rather than rotate them, and add our IP to the existing registration. DGFT enables an IP added to an already-enabled account after 24 hours, and until then every call that needs an access token answers: ```json theme={"dark"} { "statusCode": 409, "message": "This account is still being activated. Activation takes up to 24 hours from the time the credentials were linked; access is expected from 2026-09-09T05:56:19.000Z. Retry after that time — nothing needs to be re-submitted.", "errorCode": "DGFT_IP_ACTIVATION_PENDING", "retryAfter": "2026-09-09T05:56:19.000Z", "requiresPasswordUpdate": false } ``` `retryAfter` is an ISO 8601 UTC timestamp. Schedule the retry for then instead of polling. You do not have to: an IRM refresh refused this way is remembered and runs automatically once DGFT opens access, and the client's [`dgftApiStatus`](/api-reference/customer/create#the-client-object) tells you in advance whether a client is in this window. ## Related * [Authentication](/authentication) for auth failures and rate limits. * [Download eBRC PDF](/api-reference/genebrc/download) shows credential error recovery end to end. * [Push IRM Request Fields](/annexure/push-irm) for every field's format and constraints. # FAQ Source: https://docs.ebrc.in/faq Answers to common eBRC questions: eBRC full form, how to generate and check an eBRC via API, authentication, bulk submission, timing, FIRC vs eBRC, purpose codes, AD code, and GST refunds. ## What is an eBRC? An eBRC (electronic Bank Realization Certificate) is the certificate that confirms an exporter's foreign payment was actually received against an export. It is issued through DGFT, the Directorate General of Foreign Trade, and exporters need it for compliance and for claiming export incentives. See [What is an eBRC?](/what-is-an-ebrc) for the full explanation. ## What is the eBRC API? The eBRC API is a REST API for generating and managing eBRCs for Indian exporters. It covers the whole lifecycle: onboard an exporter, connect their DGFT account, pull their inward remittances, generate certificates, and download the PDF. It is built for platforms, aggregators, and CHAs that file on behalf of many exporters, with one account managing many exporter entities. ## How do I generate an eBRC via API? Create a platform customer for the exporter, validate their DGFT credentials, pull their inward remittances, and submit them with [`POST /genebrc/push-irm`](/api-reference/genebrc/push-irm). You get a request ID back and [poll status](/api-reference/genebrc/status); in live mode, requests are typically acknowledged within about 2 hours. The [Quick Start](/quick-start) walks the whole flow. ## How do I authenticate? Send your API key in a single `x-api-key` header over HTTPS on every request. Test and live keys are issued as a pair, shown once, and never stored in a readable form; the prefix (`dev_` or `prod_`) also selects the mode. Live access is contract gated. See [Authentication](/authentication) for the header, rate limits, and the exact auth error responses. ## Can I submit eBRCs in bulk? Yes, two ways. Post an array of IRM records in one [`push-irm`](/api-reference/genebrc/push-irm) call, or [download a pre-filled Excel template](/api-reference/genebrc/bulk-upload-template), fill it, and [upload it back](/api-reference/genebrc/bulk-upload). Excel validation errors come back per row, so you know exactly which line to fix before anything is filed. ## How long does eBRC generation take? Submitting takes minutes. In live mode, a generation request is typically acknowledged within about 2 hours, after which you can [fetch the certificate details](/api-reference/genebrc/fetch-details) and [download the PDF](/api-reference/genebrc/download). You track progress by polling the request status with your request ID. ## What is GenEBRC? GenEBRC is the name of the official eBRC generation module. With this API you send IRM data as JSON or Excel, and submission, status tracking, and certificate PDF download are handled for you end to end. ## Do you support a test or sandbox environment? Yes, and there is no separate sandbox host to point at. Every request goes to the same base URL, and your API key decides the mode: a `dev_` key runs in test mode, where nothing filed is legally binding and nothing is metered, and a `prod_` key files for real. Going live means swapping the key. Every generation request records the mode it was filed in, so a test run is never mistaken for a live filing. See [Base URL and Modes](/environments). ## Is there an eBRC API for India? Yes. This is a REST API for generating and managing eBRCs for Indian exporters, built for platforms, aggregators, and CHAs that file on behalf of many exporters. One account manages many exporter entities, each with their own DGFT connection. [Create your account in the eBRC API console](https://console.ebrc.in/sign-up) to get started, or email [amin@eximfiles.io](mailto:amin@eximfiles.io) with any query. ## Is the eBRC API free? Yes. The eBRC API is free for general use: 250 live certificates a month and 10 exporter entities per account in either mode, test filing not metered, within the published [rate limits](/authentication#rate-limits). The full definition and the quote path for committed volume live on the [Pricing](/pricing) page. The eBRC exporter app at [ebrc.in](https://ebrc.in) is a separate product, for exporters filing against their own IEC, and is free at any volume with no certificate limit and no card at sign-up. ## What is the full form of eBRC? eBRC stands for Electronic Bank Realisation Certificate. It is the electronic successor to the paper Bank Realisation Certificate (BRC), issued through DGFT. See [What is an eBRC?](/what-is-an-ebrc). ## How do I check an eBRC status on the DGFT portal? Manually, an exporter logs in to the DGFT portal and opens My Dashboard, then Repositories, then Bills Repositories, selects Bank Realisations, sets a date range, and searches to view or print the certificate. Via this API, you poll a generation request with its request ID using [Get Request Status](/api-reference/genebrc/status), then [fetch details](/api-reference/genebrc/fetch-details) and [download the PDF](/api-reference/genebrc/download). ## What is the difference between an eBRC and a FIRC? An eBRC ties a realised payment to a specific export and is issued through DGFT, which is what export incentive schemes require. A FIRC (Foreign Inward Remittance Certificate) is broader proof that foreign money arrived, and is not by itself tied to a particular export. ## Is an eBRC needed for a GST refund? For the export of services, realisation of payment in convertible foreign exchange is a condition for the supply to count as an export, so an eBRC or FIRC is commonly part of the refund claim. The GST rules are with the [CBIC](https://www.cbic.gov.in/). ## What is a purpose code, and which one is used for exports? A purpose code is an RBI code on an inward remittance that describes what the money is for. Export of goods most commonly uses category 01, for example `P0101` for negotiated export bills and `P0103` for advance receipts. See [Purpose Codes](/annexure/purpose-codes). ## What is an AD code? An AD code is the Authorised Dealer code of the bank branch that handles export proceeds, issued by a bank the RBI authorises to deal in foreign exchange. It is registered at each port of shipment on [ICEGATE](https://www.icegate.gov.in/), and a shipping bill cannot be filed at a port without it. ## How long do exporters have to realise export proceeds? FEMA requires export proceeds to be realised within the period the RBI prescribes in its [Master Direction on Export of Goods and Services](https://www.rbi.org.in/Scripts/BS_ViewMasDirections.aspx?id=10395). That period has been revised in recent years, so check the current Master Direction rather than an older figure. ## Related * [What is an eBRC?](/what-is-an-ebrc) for the concept and why it matters. * [Introduction](/introduction) for what the API covers. * [Base URL and Modes](/environments) before you make your first call. * [Errors](/errors) when something does not validate. # Introduction Source: https://docs.ebrc.in/introduction One REST API for the full eBRC lifecycle. Onboard an exporter, connect their DGFT account, pull inward remittances, generate certificates, and download the PDF. The eBRC API lets you generate electronic Bank Realization Certificates for every exporter on your platform. Onboard an exporter, connect their DGFT account, pull inward remittances, generate certificates, and download the PDF. All REST, all JSON, one API key. The API is [free for general use](/pricing) (250 live certificates a month included), with contract-gated live access. [Create your account in the eBRC API console](https://console.ebrc.in/sign-up) to get started; a [test and a live key](/environments) are issued as a pair and appear in the console. Questions: [amin@eximfiles.io](mailto:amin@eximfiles.io). New to eBRCs? Read [What is an eBRC?](/what-is-an-ebrc) for the concept, the DGFT and FEMA context, and why exporters need one. ## Start here Create a platform customer, validate DGFT credentials, fetch IRMs, and submit your first generation request. One API key header over HTTPS, with published per-endpoint rate limits. Submit IRM records for generation, then poll status with your request ID. Download the pre-filled template, fill it, upload it back. Errors come back per row. The error body, exact validation messages, and DGFT credential error codes. DGFT reference data: field specs, purpose codes, currency codes, and port codes. ## The lifecycle at a glance [Create a platform customer](/api-reference/customer/create) and [validate their DGFT credentials](/api-reference/customer/validate). [Pull the exporter's inward remittances](/api-reference/irm/post) into your system. [Push IRM records](/api-reference/genebrc/push-irm) for eBRC generation, one at a time or [in bulk via Excel](/api-reference/genebrc/bulk-upload). [Poll status](/api-reference/genebrc/status) with your request ID, then [fetch details](/api-reference/genebrc/fetch-details) and [download the certificate PDF](/api-reference/genebrc/download). ## Base URL One base URL, `https://api.ebrc.in/api/v1`, for both test and live: your API key's prefix decides which. See [Base URL and Modes](/environments) for how that works, and the [API Reference](/api-reference/introduction) for conventions and the response envelope. ## Need help? Email [amin@eximfiles.io](mailto:amin@eximfiles.io) and quote the requestId from your API response. # Pricing Source: https://docs.ebrc.in/pricing The eBRC API is free for general use: 250 live certificates a month, 250 shipping bill extractions plus 50 in test, 10 exporter entities in either mode, test filing not metered. Beyond that, plans and your usage sit together in the console under Billing. The API is free for general use. This page is the exact definition, so nobody has to guess. ## Free general use | Allowance | Included | | ----------------------------------- | ------------------------------------- | | Live certificates generated | **250** per calendar month | | Shipping bill extractions, live | **250** per calendar month | | Shipping bill extractions, test | **50** per calendar month, separately | | Exporter entities per account, live | **10** | | Exporter entities per account, test | **10** | | Test mode filing | Not metered | Only certificates generated in live mode (that is, with a `prod_` [API key](/environments)) count: reads, status polls, downloads, and everything in test mode are free. The figure is the same one your console shows each cycle. [Shipping bill extraction](/api-reference/extraction/introduction) is metered separately, and unlike filing it **is** split by mode: into two budgets that do not draw on each other. A `prod_` key spends the 250; a `dev_` key spends its own 50. So integrating never costs you live volume. Test extraction is capped where test filing is not, and the reason is worth stating: a sandbox filing produces no real certificate, so it is worthless and free. A sandbox extraction returns byte-identical, production-usable JSON (there is no degraded sandbox version of a parsed bill), so an uncapped test mode would simply be the product for free. Exporter entities are capped in **both** modes, and the test ceiling is a flat 10 on every plan. It is not a paywall, since test exporters are never billed, but an abuse guard: an integration needing more than ten test exporters has stopped testing shape and started running a roster. Live is where the roster grows: paid plans raise the live ceiling well past ten. Per-endpoint [rate limits](/authentication#rate-limits) apply to every account, free or contracted. They protect the service and are not a pricing lever. Crossing an allowance **does** stop the work that draws on it. A live filing past the monthly certificate cap returns `402` with `monthly_certificate_limit_reached`, an extraction past its ceiling returns `402`, and onboarding past the exporter ceiling returns `402` `exporter_limit_reached` (or `sandbox_extraction_limit_reached` on a `dev_` key). The certificate and exporter refusals carry the figure you hit and what you have used; the extraction refusal names the figure it hit. In every case the fix is a plan change rather than a support ticket. Test filing is the exception and is never refused. ## Beyond the free allowance Plans, what each one includes, and your usage for the month sit together in one place: the console, under **Billing**. A plan's volumes are **totals, not increments**: the figure a plan includes is the monthly cap, full stop, and it replaces the free allowance rather than stacking on it. Every rung's totals sit well above the free tier, so subscribing is never a step down. Prices are not published here on purpose. They belong next to your actual usage, where the figure that matters is what *your* volume costs rather than what a table says. You will have seen them before you are ever asked to choose. ## Committed volume and customisation For a committed annual arrangement, or anything the plans do not cover, email [amin@eximfiles.io](mailto:amin@eximfiles.io) with: 1. Expected certificates per month 2. Number of exporter entities 3. Anything custom you need You get a quote back, and production continues uninterrupted while you talk. ## The eBRC exporter app The eBRC exporter app at [ebrc.in](https://ebrc.in) is a separate product, for an exporter filing certificates against their own IEC. It is free at any volume, with no certificate limit, no paid tier for exporters and no card at sign-up. Nothing on this page applies to it: the allowances above are the eBRC API's, and the two products have separate accounts. ## The fine print Allowances are published limits under the [API Terms](https://ebrc.in/api-terms) and may evolve prospectively with notice. # Quick Start Source: https://docs.ebrc.in/quick-start Generate your first eBRC via the API: create an exporter, connect DGFT, fetch inward remittances, submit them for generation, and track by request ID. This guide walks the full lifecycle once: create an exporter, connect their DGFT account, pull their remittances, submit them for generation, and track the request. ## Before you begin 1. An API key. [Create your account in the eBRC API console](https://console.ebrc.in/sign-up) to request one; for help, email [amin@eximfiles.io](mailto:amin@eximfiles.io). Use your `dev_` key to walk this guide. The calls are identical in live mode. 2. The exporter's DGFT portal credentials. The API is free for general use, so you can complete this whole guide without any billing setup. See [Pricing](/pricing). Set `BASE_URL` to `https://api.ebrc.in/api/v1`. It is the same for test and live: your key's prefix decides which mode you are in. See [Base URL and Modes](/environments). Services are enabled after **24 hours** of customer validation. ## Steps to generate an eBRC Create the exporter entity you will generate for. See [Create Customer](/api-reference/customer/create). ```bash theme={"dark"} curl --location "$BASE_URL/platform-customers" \ --header 'Content-Type: application/json' \ --header 'x-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" }' ``` The response's `data.id` is the `platformCustomerId` used in every later call. The client is created with `isActive: false` and cannot file until the next step succeeds. Connect the exporter's DGFT account. See [Validate Customer](/api-reference/customer/validate). This endpoint is limited to 4 calls per minute. ```bash theme={"dark"} curl --location "$BASE_URL/platform-customers/ee849a90-7a28-49b4-8cb2-8e31041650a2/check-dgft-credentials" \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "dgftUsername": "", "dgftPassword": "" }' ``` Pull the exporter's inward remittances. See [Fetch IRM List](/api-reference/irm/post). ```bash theme={"dark"} curl --location --request POST "$BASE_URL/irm/refresh?platformCustomerId=ee849a90-7a28-49b4-8cb2-8e31041650a2" \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data '' ``` Map each IRM to its invoice and submit. See [Submit IRMs for eBRC Generation](/api-reference/genebrc/push-irm) and the [field reference](/annexure/push-irm). Dates are `DDMMYYYY` strings; the message-level `uploadType` is a string code and the item-level one is a number: 101 Direct Export, 102 Softex, 103 Service Non IT, 104 Deemed. ```bash theme={"dark"} curl --location "$BASE_URL/genebrc/push-irm" \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "recordResCount": 1, "uploadType": "101", "decalarationFlag": "Y", "ebrcBulkGenDtos": [ { "serialNo": 1, "uploadType": 101, "branchSlNo": 0, "irmIfscCode": "HDFC0000123", "irmAdCode": "6390005", "irmNumber": "IRM0000012345", "irmDt": "01042024", "irmFCC": "USD", "irmPurposeCode": "P0101", "irmRemitAmtFCC": 25000, "sbCumInvoiceNumber": "7654321", "sbCumInvoiceDate": "15032024", "portCode": "INMAA1", "billNo": "EXP-2024-0042", "sbCumInvoiceFCC": "USD", "sbCumInvoiceValueinFCC": 25000, "mappedIRMAmountFCC": 25000, "isVostro": "N", "isGstAvail": "N", "gstinInvoiceNumber": null, "gstinInvoiceDate": null } ] }' ``` Keep the returned `requestId`. If validation fails, the exact messages are listed under [common validation errors](/errors#common-validation-errors). Poll with your request ID. See [Get Request Status](/api-reference/genebrc/status). Available in both modes. In live mode, a generation request is typically acknowledged within about 2 hours. ```bash theme={"dark"} curl --location --request POST "$BASE_URL/genebrc/status" \ --header 'x-api-key: ' \ --header 'Content-Type: application/json' \ --data-raw '{ "platformCustomerId": "ee849a90-7a28-49b4-8cb2-8e31041650a2", "requestId": "IEC1234560120240001ABCDE12345" }' ``` Once processed, [fetch details](/api-reference/genebrc/fetch-details) or [download the certificate PDF](/api-reference/genebrc/download). ## Going live Nothing in the flow above changes. Replace your `dev_` key with your `prod_` key and the same calls, against the same base URL, file for real. Test and live data are isolated, so create your exporters again with the live key before filing for them. See [Base URL and Modes](/environments). ## Prefer Excel? Skip the JSON payload: [download the pre-filled template](/api-reference/genebrc/bulk-upload-template), fill it, and [upload it back](/api-reference/genebrc/bulk-upload). Validation errors come back per row. ## Need help? Email [amin@eximfiles.io](mailto:amin@eximfiles.io) and quote the requestId from your API response. # Use with AI (MCP) Source: https://docs.ebrc.in/use-with-ai Connect the eBRC API docs to Claude, Cursor, or ChatGPT over MCP, call the API from your AI assistant with your own key, or feed any page to an LLM as clean Markdown. These docs are built to be driven by AI. Add one MCP server and your assistant can search and answer from the whole knowledge base; open the API Reference and it can help you call the API with your own key; or hand any page to an LLM as clean Markdown. ## Connect over MCP The docs are served as an MCP (Model Context Protocol) server. Point any MCP-capable tool at one URL and it can search and read this documentation from inside the tool. ```text theme={"dark"} https://docs.ebrc.in/mcp ``` ```bash theme={"dark"} claude mcp add --transport http ebrc-docs https://docs.ebrc.in/mcp ``` Then ask questions like "how do I submit IRMs for eBRC generation" and it answers from these docs, with citations. Add this to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally): ```json theme={"dark"} { "mcpServers": { "ebrc-docs": { "url": "https://docs.ebrc.in/mcp" } } } ``` In ChatGPT, open **Settings**, then **Connectors**, and add a custom connector with the URL `https://docs.ebrc.in/mcp`. The docs MCP is **read-only**: it searches and returns documentation. It never sees, asks for, or transmits your API key. Calling the API is a separate step, below, and always uses your own key. ## Ask AI on any page Every page has a contextual menu next to its title. Use it to **copy the page as Markdown**, **view it as plain text**, or **open it in ChatGPT or Claude** with the page content already attached, so you can ask questions without leaving your assistant. ## Plain text for LLMs For tools that consume documentation as a single file: * [`/llms.txt`](https://docs.ebrc.in/llms.txt) is a compact index of every page. * [`/llms-full.txt`](https://docs.ebrc.in/llms-full.txt) is the entire documentation as one plain-text file, ready to paste into a model's context. ## Call the API with AI Reading the docs is one half; the other is making requests. 1. Open the [API Reference](/api-reference/introduction). Every endpoint has a live playground and copy-paste cURL, generated from the OpenAPI spec. 2. Add your `x-api-key` (see [Authentication](/authentication)) and the base URL, which is the same for test and live (see [Base URL and Modes](/environments)). 3. An MCP-connected assistant can read an endpoint page and generate correct request code for your language, because the request and response shapes come straight from the spec. Your API key is yours: it goes in the `x-api-key` header over HTTPS on requests **you** make. It is never part of the docs, the MCP server, or any example on this site. ## When the base URLs change The system is built so a future move is a swap, not a rebuild: * The **API base URL** always comes from [Base URL and Modes](/environments); it is driven by the single `servers` entry in the OpenAPI spec, so a change updates the reference, the playground, and every cURL example at once. Take the current base URL from that page rather than hardcoding it, and remember the mode comes from the key, not the URL. * The **docs MCP URL** follows this documentation site; if the docs move to a new domain, use the MCP URL shown on this page at that time. ## Related * [Quick Start](/quick-start) if you are integrating by hand. * [Authentication](/authentication) for the API key header and rate limits. * [API Reference](/api-reference/introduction) for conventions and the response envelope. # What is an eBRC? Source: https://docs.ebrc.in/what-is-an-ebrc eBRC full form is Electronic Bank Realisation Certificate. What it is, why DGFT, FEMA, and export incentives depend on it, and how self-certification works, with primary sources. An eBRC (electronic Bank Realisation Certificate) is the official record that an exporter's foreign payment was realised against an export. It is issued through DGFT, the Directorate General of Foreign Trade, and is a core compliance document for Indian exporters. **In one line:** a shipping bill proves the goods left India. An eBRC proves the money came back and was realised. The full form of eBRC is Electronic Bank Realisation Certificate. The "e" is for electronic; the rest describes what the certificate does, which is to record the realisation, by a bank, of the proceeds of an export. ## Why an eBRC matters * **Proof of realisation.** An eBRC confirms that the export proceeds, the foreign payment for a shipment or invoice, were actually received. It ties an inward remittance to the export it settles. * **FEMA compliance.** Inward remittances against exports are tracked under the Foreign Exchange Management Act (FEMA). Export proceeds must be realised within the period the RBI prescribes in its [Master Direction on Export of Goods and Services](https://www.rbi.org.in/Scripts/BS_ViewMasDirections.aspx?id=10395), and the eBRC is the record that links a remittance to a specific export and closes it out. * **Export incentives.** Exporters need eBRCs to claim benefits and remissions such as RoDTEP (Remission of Duties and Taxes on Exported Products) and Duty Drawback, and to support DGFT and export promotion schemes. * **GST refunds.** For the export of services, realisation of payment in convertible foreign exchange is a condition for the supply to count as an export, so an eBRC or FIRC is often part of a GST refund claim. See the [CBIC](https://www.cbic.gov.in/) for the GST rules. ## Self-certification: how an eBRC is created today DGFT revamped the eBRC system in November 2023 so that exporters self-certify. The flow is: When a foreign payment arrives, the exporter's bank transmits the Inward Remittance Message (IRM) to DGFT electronically. The IEC holder matches each IRM to the shipping bill, SOFTEX, or invoice it pays for. DGFT issues the eBRC, which is then available as a certificate PDF and can be used to claim incentives and evidence realisation. The bank no longer issues the certificate by hand at a branch. This is the process the [eBRC API](/introduction) carries end to end for platforms filing for many exporters. ## Key terms | Term | Meaning | | ---------------- | ------------------------------------------------------------------------------------------------- | | **DGFT** | Directorate General of Foreign Trade, the authority that issues eBRCs | | **IRM** | Inward Remittance Message, a foreign payment received against an export | | **Realisation** | The export proceeds being received, the payment landing in the exporter's account | | **IEC** | Importer Exporter Code, the exporter's registration number | | **AD code** | Authorised Dealer code, the bank's code registered at each port on ICEGATE | | **Purpose code** | The RBI code on a remittance that describes what the money is for | | **BRC** | The older paper Bank Realisation Certificate the eBRC replaced | | **FIRC** | Foreign Inward Remittance Certificate, broad proof of a remittance, not tied to a specific export | | **EDPMS** | Export Data Processing and Monitoring System, the RBI system that tracks exports to realisation | | **GenEBRC** | DGFT's module for generating eBRCs from remittance and invoice data | ## eBRC, BRC, and FIRC An eBRC is the electronic form of the older paper BRC, so those two are the same certificate in different eras. A FIRC is broader: it proves that foreign money arrived, for any reason, and it does not by itself tie the payment to a specific export. That is why DGFT incentive schemes are claimed against the eBRC, not a FIRC. ## Primary sources * [DGFT eBRC](https://www.dgft.gov.in/CP/?opt=eBRC), the authority that issues the certificate. * [RBI Master Direction on Export of Goods and Services](https://www.rbi.org.in/Scripts/BS_ViewMasDirections.aspx?id=10395), for realisation and FEMA rules. * [ICEGATE](https://www.icegate.gov.in/), the customs gateway for shipping bills and AD codes. * [CBIC](https://www.cbic.gov.in/), for GST and customs. This documentation is for the eBRC API, which generates and manages eBRCs programmatically for platforms that file on behalf of many exporters. ## Related * [Introduction](/introduction) for what the eBRC API covers. * [FAQ](/faq) for short answers to common eBRC questions. * [Quick Start](/quick-start) to generate your first eBRC via the API. * [Purpose Codes](/annexure/purpose-codes) and [Currency Codes](/annexure/currency-codes) for the DGFT reference data.