The files your customers actually send
An implementation team onboarding a distributor gets an item master with 180,000 rows exported from a system that predates the web. SKUs are ABC-1001, abc1001, and ABC 1001 (with a trailing space) for the same part, because three warehouses each keyed them in differently. Unit of measure is EA, Each, ea., CS, Case of 12, and in one column a number that is actually the case pack quantity. Descriptions are truncated at 30 characters in half the file and full-length in the other half, depending on which screen the data was originally typed into.
Vendor IDs reference suppliers who were merged or deactivated years ago. GL codes are missing their segment separators, or carry an extra segment from an old chart of accounts. Cost has currency symbols in some cells, negative values where a credit was recorded, and #REF! where a formula broke. Quantity on hand is a decimal for items sold by the each. The subsidiary column says "US", "USA", "United States", and "Acme US Inc" interchangeably, and currency is blank for the entire domestic range because everyone assumed dollars. This file has to load into the general ledger correctly, and it has to load again next month when the vendor sends an update.
Fields and rules that matter in ERP
| Field | What goes wrong in real files | How Dromo catches it |
|---|---|---|
| SKU | Case, spacing, and separator inconsistencies create duplicates | Column hook normalizes case and strips whitespace; unique validator flags collisions after normalization |
| Item description | Truncation, embedded newlines, leading part numbers | Required field; column hook trims and collapses whitespace |
| Unit of measure | Abbreviations, plurals, pack sizes in the same cell | Select field with allowed values; bulk transform maps the variants in one operation |
| Vendor ID | Deactivated or merged suppliers | Custom validator calls your vendor API and rejects IDs that no longer exist |
| GL code | Missing or extra segments, old chart of accounts | Regex validator enforces the segment structure with a message that shows the expected shape |
| Cost | Currency symbols, negatives, broken formulas | Number type with a non-negative range; column hook strips symbols before parsing |
| Quantity | Decimals for discrete items, blanks treated as zero | Number type with integer and non-negative constraints; required when the line is stocked |
| Entity or subsidiary | Aliases for the same legal entity | Allowed values, remembered per customer for the next upload |
| Currency | Blank, symbols instead of codes, lowercase | Select field restricted to ISO 4217 codes; default value fills the blanks |
A working ERP schema
{
"fields": [
{
"label": "SKU",
"key": "sku",
"type": "string",
"validators": [
{ "validate": "required" },
{ "validate": "unique" },
{ "validate": "regex_match", "regex": "^[A-Z0-9]{3,20}$", "errorMessage": "SKU must be 3 to 20 uppercase letters or digits" }
]
},
{
"label": "Unit of measure",
"key": "uom",
"type": "select",
"selectOptions": [
{ "label": "Each", "value": "EA" },
{ "label": "Case", "value": "CS" },
{ "label": "Pallet", "value": "PL" },
{ "label": "Kilogram", "value": "KG" }
],
"validators": [{ "validate": "required" }]
},
{
"label": "GL code",
"key": "gl_code",
"type": "string",
"validators": [
{ "validate": "regex_match", "regex": "^\\d{4}-\\d{3}-\\d{2}$", "errorMessage": "GL code format is 0000-000-00" }
]
},
{
"label": "Unit cost",
"key": "unit_cost",
"type": "number",
"validators": [{ "validate": "required" }, { "validate": "greater_than_or_equal_to", "value": 0 }]
},
{
"label": "Quantity on hand",
"key": "qty_on_hand",
"type": "number",
"validators": [{ "validate": "greater_than_or_equal_to", "value": 0 }]
},
{
"label": "Currency",
"key": "currency",
"type": "select",
"selectOptions": [
{ "label": "USD", "value": "USD" },
{ "label": "EUR", "value": "EUR" },
{ "label": "GBP", "value": "GBP" },
{ "label": "CAD", "value": "CAD" }
]
}
]
}
The vendor lookup runs as a custom validator against your API during the import, and the integer constraint on quantity is a field hook, so neither is part of the static definition above. An implementation lead can build the same schema in Schema Studio, paste the allowed UOM and currency lists from a spreadsheet, and set a default currency without writing anything.
Security and deployment for ERP
ERP customers ask two questions before anything else: where does the data live, and can this run without a person clicking buttons every month. For the first, Dromo can be deployed as a complete stack inside your own cloud via Kubernetes, which keeps item masters, cost data, and vendor records within whatever region or network boundary your customers require. SOC 2 Type II certification, GDPR compliance, and a security report under MNDA through the Trust Center cover the standard review.
For the second, the Headless API takes the schema you built for the widget and runs it with no user in the loop. Files can arrive over SFTP, which is how most vendors still deliver price lists and inventory updates. There is no row limit, so the 180,000-line item master and the monthly delta both go through the same pipeline. When a file validates cleanly, you get results and nothing else; when a row needs judgment, Dromo generates a fix-it URL that a buyer or an implementation consultant can open to resolve the specific problem in the review grid.
Connect it to NetSuite, SAP, and Oracle
For interactive imports run by a customer's operations staff, the onResults callback delivers JSON with normalized SKUs, canonical UOM codes, validated GL segments, and non-negative numbers, ready for your NetSuite SuiteTalk, SAP OData, or Oracle REST integration. Because the item master is validated before it reaches your service, the integration layer can concentrate on mapping and upsert logic rather than data cleaning.
Recurring vendor feeds through the Headless API report back with a webhook POST when processing finishes, and the REST API exposes the import metadata, the full result set, and presigned downloads for your job runner to fetch. CSV output is available alongside JSON for downstream systems that expect a flat file, so a legacy loader can consume the cleaned data without changes.

