Batch Patient Import
Create or update as many as 500 patients from one CSV file on the import page. Each data row is processed independently, so one failed row does not undo successful rows.Quick start
- Download the current CSV template from the import page.
- Add one patient per row. Keep the camelCase column names exactly as shown.
- Upload the file and correct any client-side validation errors.
- Submit the import.
- Review the separate patient and insurance totals. Every CSV row remains available in the result table, including rows with no insurance information.
- Download the insurance-results CSV if you need to reconcile unresolved, incomplete, or failed coverages outside Solum.
Identifying a patient
Each row must contain either:phoneNumber; or- all three of
firstName,lastName, anddateOfBirth.
externalIdType and externalId.
externalIdTypeaccepts the UUID or case-insensitive name of an external-ID type configured for your company.externalIdis trimmed and must contain 1–500 characters.- A row supports one typed external ID.
- If the same resolved type and value appears more than once in the file, every duplicate row fails. Other rows continue.
How existing patients are matched
Batch import uses the same matching rules as the patient upsert API, in this order:- Exact typed external ID
- Exact first name, last name, and date of birth
- Normalized phone number plus fuzzy name
- Normalized email plus fuzzy name
POST /v1/patients/upsert. If no patient matches, a new patient is created.
CSV columns
Column order does not matter. Unknown columns are ignored.Patient fields
Workflow and tags
Values that cannot be resolved are reported in
dropped_fields for that row.
Insurance
Insurance names are lookup-only and flow through the same resolver used by
POST /v1/patients/upsert. Solum can select only an active insurance belonging
to your company with a nonblank trading-partner service ID. It tries canonical
names, configured aliases, state-aware variants, and then a bounded
AI-assisted match.
An unresolved insurance does not fail the patient row. The patient and any
other valid coverage can still succeed, and the unresolved coverage is
reported with a stable reason. A member ID with a blank insurance-name cell is
reported as incomplete; a row where all four insurance cells are blank is
not_provided.
Referral
Partial-success results
A valid top-level request returns HTTP200 even if individual rows fail. Authentication errors, malformed JSON, an empty item list, and more than 500 items remain request-level errors.
The response keeps the original patient aggregates and adds separate insurance
aggregates plus one ordered result for every patient row. Each row contains one
ordered payor_results item per supplied primary or secondary coverage.
row is the one-based data-row number and does not count the header. Patient
outcomes are represented by error, created, and matched; insurance
outcomes come from insurance_status and payor_results.
Insurance statuses and outcomes
Row-levelinsurance_status values are:
Each
payor_results[].outcome is one of created, updated, unchanged,
unresolved, incomplete, failed, or not_processed. Expected resolution
abstentions use these stable reason_code values:
insurance_name_missingno_configured_matchconfigured_insurance_inactiveinsurance_not_vob_readyambiguous_matchmatch_confidence_too_lowresolution_unavailablepersistence_failedpatient_row_failed
not_provided rows. The downloadable
insurance report contains patient and configured-coverage identifiers and safe
outcome details, but never patient names or insurance member IDs.

