> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nyumbazetu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Bulk upload

> Import units, leases, residents, invoices, payments and more from spreadsheets — with validation, history and per-row outcomes.

**Admin → Bulk Upload → `/file-upload`**

Bulk upload imports data from a spreadsheet into the platform. It is how a portfolio gets
onboarded, how a month of vendor invoices gets recorded, and how historical payments get migrated.

## What you can import

| Type                    | Notes                                                            |
| ----------------------- | ---------------------------------------------------------------- |
| **Utility Readings**    | Water, electricity, gas and other meter readings.                |
| **Payments**            | Received payments, typically from a bank or mobile-money export. |
| **Residents**           | Tenant and contact records.                                      |
| **Invoices**            | Bills, including historical ones.                                |
| **Units**               | The physical estate.                                             |
| **Leases**              | Tenancies, with grouping and validation across related rows.     |
| **Recurring Invoices**  | Standing charges on leases.                                      |
| **Credit Notes**        | Adjustments, for example reversing a mis-billed run.             |
| **Expenses**            | Vendor bills.                                                    |
| **Sales Opportunities** | Pipeline records.                                                |

## The wizard

<Steps>
  <Step title="File information">
    Choose what you are importing and download the **sample template** for that type. The sample
    matches the real column schema, so starting from it avoids most mapping problems.
  </Step>

  <Step title="File upload">
    Upload the spreadsheet. The file itself is retained, so what you actually submitted can be
    reviewed later.
  </Step>

  <Step title="Data mapping">
    Map your columns to the platform's fields. Mapping is remembered per type, so a recurring
    import gets faster.
  </Step>

  <Step title="Review & submit">
    Validation runs before anything is written — on the server as well as in the browser, so a
    malformed file cannot slip past.
  </Step>

  <Step title="Confirmation">
    The result: how many rows were created, skipped and failed.
  </Step>
</Steps>

## History

**History** lists every upload run — who ran it, when, which type, and the outcome (succeeded,
failed, or partial). Open a run to see:

* **per-row outcomes** — created, skipped or failed, each with a reason;
* the **original file**, downloadable;
* the option to **re-run**.

<Note>
  History is scoped to operators and administrators. Imported files are not exposed to residents.
</Note>

This is the difference between an import you can trust and one you cannot: after the fact, you can
answer exactly what a run did to every row.

## Importing from inside a module

The upload wizard is embeddable, so several modules launch their own import without sending you to
`/file-upload` — for example importing expenses from the expenses list, or leases from the leases
list. It is the same engine, the same validation and the same run history.

## Getting an import right

<Steps>
  <Step title="Start from the sample template">
    Not from last year's spreadsheet.
  </Step>

  <Step title="Import in dependency order">
    Units before leases; residents before leases; leases before invoices; invoices before payments.
    Importing out of order is the main cause of mass row failures.
  </Step>

  <Step title="Test with a small file first">
    Ten rows. Check the outcomes, then run the rest.
  </Step>

  <Step title="Check the branch">
    Imports land in your active branch.
  </Step>

  <Step title="Read the skipped rows, not just the failed ones">
    Skipped rows are silent. A run reporting "500 created, 200 skipped" imported 500 records and
    quietly ignored 200.
  </Step>

  <Step title="Reconcile after the run">
    Count records in the app against rows in the file, and check a sample end to end.
  </Step>
</Steps>

<Warning>
  Importing money — payments, invoices, credit notes — writes real financial records. There is no
  one-click undo for an import that has already been allocated or posted. Test small, and check the
  branch and period before running the full file.
</Warning>

## Common problems

| Symptom                            | Cause                                                                                                           |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Most rows failed with "not found"  | A dependency does not exist yet — usually the unit or lease. Import in order.                                   |
| Rows silently skipped              | Duplicates against existing records, or rows failing a rule that skips rather than errors. Read the run detail. |
| Amounts imported wrong by a factor | Formatting — thousands separators or currency symbols in a numeric column.                                      |
| Dates shifted                      | Spreadsheet date format. Use the sample template's format.                                                      |
| Import created duplicates          | The file was run twice. Check history before re-running.                                                        |

## Next steps

<Columns cols={2}>
  <Card title="Units" icon="door-closed" href="/guides/units">
    The first thing to import when onboarding.
  </Card>

  <Card title="Managing leases" icon="file-signature" href="/guides/managing-leases">
    Leases depend on units and residents existing first.
  </Card>
</Columns>
