The files your customers actually send
An HR admin at a 400-person company is switching to your platform. What they have is a payroll export where the header row starts on line four, beneath the company name and a date range; a benefits spreadsheet with merged cells spanning each department; and a "master roster" that an office manager built in 2020 and has maintained since, with color-coded rows that mean something only to her. Employee IDs in one file are E0042, in another 42, and in the third 0042 because Excel stripped the letter and kept the zeros.
Hire dates are the worst column. Some are ISO, some are 1/7/23, several are five-digit Excel serial numbers, and at least one is in the future because a start date was entered for a candidate who never showed. Department is free text with "Eng", "Engineering", and "Engineerng". Manager is a full name rather than an ID, and two managers share the name. Pay frequency reads "biweekly", "bi-weekly", "every 2 weeks", and "26". The admin needs to load all of it herself, on a Friday, before payroll runs on Monday.
Fields and rules that matter in HRIS
| Field | What goes wrong in real files | How Dromo catches it |
|---|---|---|
| Employee ID | Duplicates across merged files, leading zeros lost by Excel | unique validator plus a column hook that restores a consistent format |
| Legal name | Preferred names, nicknames, and trailing spaces | Required field; column hook trims whitespace before validation |
| Work email | Personal addresses, duplicates, domain typos | Email type with unique; regex can restrict to your customer's domain |
| Hire date | Serial numbers, mixed formats, dates in the future | Date parsing handles the formats; a row hook rejects any date after today |
| Department | Free text with abbreviations and misspellings | Select field with allowed values; bulk transform maps variants in one step |
| Job title | Inconsistent capitalization, slashes, and codes | Column hook applies title case and strips internal codes |
| Manager ID | References an employee who is not in the file or the system | Custom validator checks the ID against your API or the rows already imported |
| Pay frequency | Synonyms and numbers standing in for labels | Allowed values with the mapping remembered for the next upload |
| Location | Office nicknames instead of official site names | Select field or a hook that resolves aliases to canonical locations |
| Employment type | "FT", "Full time", "Contractor (1099)" | Allowed values, with clear inline errors for anything unmapped |
A working HRIS schema
{
"fields": [
{
"label": "Employee ID",
"key": "employee_id",
"type": "string",
"validators": [{ "validate": "required" }, { "validate": "unique" }]
},
{
"label": "Work email",
"key": "work_email",
"type": "email",
"validators": [{ "validate": "required" }, { "validate": "unique" }]
},
{
"label": "Hire date",
"key": "hire_date",
"type": ["date", { "outputFormat": "YYYY-MM-DD" }],
"validators": [{ "validate": "required" }]
},
{
"label": "Department",
"key": "department",
"type": "select",
"selectOptions": [
{ "label": "Engineering", "value": "engineering" },
{ "label": "Sales", "value": "sales" },
{ "label": "People", "value": "people" },
{ "label": "Finance", "value": "finance" }
],
"validators": [{ "validate": "required" }]
},
{
"label": "Manager ID",
"key": "manager_id",
"type": "string"
},
{
"label": "Pay frequency",
"key": "pay_frequency",
"type": "select",
"selectOptions": [
{ "label": "Weekly", "value": "weekly" },
{ "label": "Biweekly", "value": "biweekly" },
{ "label": "Semimonthly", "value": "semimonthly" },
{ "label": "Monthly", "value": "monthly" }
]
}
]
}
The future-date check and the manager existence check are row and field-level hooks rather than static validators, because they depend on today's date and on your database. Schema Studio lets a product manager build the field list above, choose the validators, and enter the department and pay frequency options from a form, so the schema can change when a customer's org chart does without waiting on an engineer.
Security and deployment for HRIS
Employee records contain home addresses, compensation, and identifiers that are personal data in every jurisdiction your customers operate in. Dromo is SOC 2 Type II certified and GDPR compliant, and the security report is available under MNDA through the Trust Center for the procurement reviews that HR software buyers run.
For customers who want stronger guarantees than a certificate, Bring Your Own Storage writes the validated results from the admin's browser directly into your S3, GCS, Azure Blob, or Dropbox storage, so employee data never sits in Dromo's infrastructure. Private Mode goes further and runs the complete import locally with zero retention. Both are configuration changes, and both work with the same schema and the same results handling.
Connect it to payroll and your ATS
The clean rows arrive through the onResults callback in the browser, which is the natural fit when an admin is running the import herself and wants to see the roster update on screen. Your backend receives JSON where every hire date is ISO, every department is a known value, and every manager ID resolves, so it can write to the employee table and push to your payroll provider in one pass.
For imports that should be recorded server-side regardless of what happens in the browser tab, register a webhook and Dromo will POST the completed import with its metadata; the full result set is then available from the REST API or as a presigned download. Recurring feeds from an applicant tracking system, where new hires land in a file every week with no human involved, fit the Headless API: it processes the file against the same schema and only produces a fix-it URL when something needs a person's attention.

