---
title: File Uploads
description: Bringing transactions into Essential Budget from a CSV, TSV, or TXT
  file exported from your bank. Where to upload, what the parser tolerates, how
  candidate transactions become real ones, and why re-uploading the same file is
  safe.
subtitle: Uploading transactions from a CSV, TSV, or TXT file.
sidebar:
  order: 70
  section: Bringing in transactions
canonical_html_url: https://eb.app/learn/file-uploads/
---

# File Uploads

Essential Budget can pull transactions in two ways: by linking your bank through Plaid, or by uploading a file you exported from your bank. This page covers the file path. For the linked-bank path, see [Bank linking](https://eb.app/learn/bank-linking.md).

File upload is available on every plan. Bank linking through Plaid is part of Premium ([Subscription](https://eb.app/learn/subscription.md)). The matching and resolving that happens after either path is the same; only the source of the candidate transactions differs.

## Where to upload

There are two places a file upload appears.

### When creating a new budget

Open the **Budgets** page, tap **Create Budget**, and pick **AI Generated** in the mode segment at the top of the dialog. The dialog walks you through naming the budget and choosing a theme. Below those, you'll see a drop-target labeled **Drop bank transaction files here**. Drag a file onto it, or tap to open your file picker. Each file you add gets an account-name input next to it; the name you type becomes a new account in the budget being created. Continue through the dialog and the new budget is built around the transactions you uploaded.

<!-- SCREENSHOT: Create Budget dialog with the AI Generated mode segment selected. The dashed-border drop target is centered with the prompt "Drop bank transaction files here" in bold and the lines "Accepts: Up to 3 CSV, TSV, or TXT files" plus "Max 200KB per file" beneath. Two example files have been added below the drop area, each shown alongside an "Account name (required)" input. -->

If you're a Premium user with at least one bank already linked through Plaid, a smaller segment with **Connect Bank** and **Upload File** options appears above the drop area, and the dialog defaults to **Connect Bank**. Switching to **Upload File** brings you back to the same drop target.

### Inside an existing budget

Open the **Planner** tab and tap **Match** in the toolbar. The **Match Transactions** dialog opens. If your budget isn't linked to a bank (or you're not on Premium), the dialog shows the same drop-target. Drag a file in, pick which existing account each file belongs to from the dropdown next to the filename, then tap the button at the bottom: **Analyze** if you're on Premium with Integrated AI on, or **Next** otherwise. The app parses the file, suggests matches against your open events, and opens the **Review Transaction Matches** screen for you to confirm.

<!-- SCREENSHOT: Match Transactions dialog with the file-upload area showing one uploaded file alongside a "Select Account" dropdown set to "Chase Checking". The Analyze button is highlighted at the bottom. -->

When the budget *is* linked to Plaid and you're a Premium user with AI on, the dialog shows your linked bank accounts instead of the drop area, and the file-upload path isn't offered there. (You can still upload a file by creating a new, unlinked budget for it, or by unlinking the bank first. See [Bank linking](https://eb.app/learn/bank-linking.md) for unlink mechanics.)

The matching and resolving that follows is described on [Matching and Resolving](https://eb.app/learn/matching-and-resolving.md). The mechanics are the same whether the candidates came from a file or from a Plaid pull.

## Supported file formats

Three plain-text formats are accepted:

- **`.csv`**, comma-separated values.
- **`.tsv`**, tab-separated values.
- **`.txt`**, plain text using comma, tab, semicolon, or pipe as the separator.

The parser tries each separator in turn and picks the one that produces the most-consistent column count across the first few rows. Most bank exports work without any preparation, including ones that include several lines of metadata (account number, statement date, branch info) before the actual header row.

> **Why no Excel (`.xlsx`)?** The parser is text-based; Excel files are binaries. If your bank only offers Excel, open the file in Excel or Numbers, choose **Save As** (or **Export**), pick CSV, and upload that instead. The conversion is lossless for transaction data.

## Size and count limits

The drop area enforces three limits:

- **3 files at most** in a single upload.
- **200 KB per file**.
- **600 KB across all files**, when you're on Premium with Integrated AI on.

For most users, the per-file 200 KB limit is the only one that matters: 200 KB times 3 files is 600 KB, which is the same as the AI-augmented total. A typical month of transactions for one account is well under 100 KB, so the cap mostly bites when someone tries to upload a multi-year history at once. If a file is too big, you'll see a clear error naming the file and the limit. The fix is to export a shorter date range from your bank.

> **Why these caps?** Integrated AI sends the file content to a large language model, and language models charge by tokens (rough proxy for characters). 600 KB across all files is the budget that keeps a single match round affordable on the included Premium Subscriber Credits. The 200 KB per-file cap is the same on the free path because it keeps the parser fast on phones and prevents one over-stuffed file from blocking the other two.

## Each file is one account

Every uploaded file is tied to one account.

- **In a new budget:** type a name for each file's account. The name you type becomes a new account in the budget being created. If you upload three files, you get three new accounts. The input is required; if it's blank, the underline turns red and **Analyze** / **Next** stays disabled until you fill it in.
- **In an existing budget:** pick an existing account from the dropdown next to each file (the dropdown is labeled **Select Account**). The transactions parsed from that file land in that account.

If your bank exports every account into a single CSV with one column saying which account each row belongs to, you'll need to split it before uploading. Most banks let you export per-account; if yours doesn't, opening the file in a spreadsheet, filtering, and saving each account as its own file is the standard workaround.

## What the parser figures out for you

The parser handles the parts of bank-export variability that would otherwise force you to clean up the file by hand:

- **Headers in the first few rows.** If your bank includes 3 or 4 metadata lines before the column headers, the parser scans the first 10 rows for the header line and skips everything before it.
- **Common header names** for the date, description, amount, debit, credit, balance, and reference columns. The parser recognizes the everyday English variants (Date, Posted, Transaction Date; Description, Memo, Payee, Merchant; Amount, Debit, Credit, Withdrawal, Deposit, Charge, Income, Balance, Running Balance, Reference, Check, Number) and the equivalent Spanish ones.
- **Day-first dates.** If your file uses `21/09/2025` style, the parser figures out it's day-first by scanning the file for any first-segment value greater than 12. ISO `YYYY-MM-DD`, US `MM/DD/YYYY`, European `DD.MM.YYYY`, and written-month forms like `21 Sep 2025` are all recognized.
- **Amounts written in any common style.** Dollar signs are stripped, thousands commas are stripped, and parenthetical negatives like `(123.45)` or `$(123.45)` are read as negatives.
- **Two-column debits and credits.** When your file has a debit column and a credit column instead of a single signed amount, the parser uses both: debits become negative, credits become positive.
- **Running-balance columns.** The parser checks whether one numeric column equals the previous row's value plus the amount column. If it does, that column is treated as the balance and the other as the amount.
- **Quoted descriptions.** A description like `"Acme Co., Inc."` is read as a single field, even though it contains a comma.

When you load a file, a small section labeled **Bank Account Transactions** appears above the drop area showing the files you've added. In the Create Budget dialog the helper text reads "Include 3 or more months of transactions so that AI can identify recurring income and expenses." In the Match Transactions dialog it reads "Include the last 30 days of transactions or more if you haven't synced recently."

## Re-uploading the same file is safe

Each row the parser produces carries a fingerprint (a short hash) computed from the row's date, description, and signed amount, plus the running balance when the file has one. If your bank's export already includes a hash column, the parser uses that value verbatim instead of computing one.

The fingerprint is the basis for duplicate detection. If you upload the same file twice (you weren't sure if the first one went through, or your bank handed back the same export), rows you already kept are filtered out of later matching prompts and the final save avoids adding the same line to the same item again. The check is per item: see [Transactions](https://eb.app/learn/transactions.md#why-the-same-imported-line-cannot-be-recorded-twice-on-one-item) for the full hash-and-item story.

> **Why not warn me?** Because re-running an upload to make sure it worked shouldn't punish you. The Review screen shows you how many transactions were actually inserted after Resolve, so a redundant upload is visible without being a hazard.

A few practical consequences:

- The hash is frozen when the row is parsed. Editing the description, amount, or date on a bank-imported transaction inside the **Edit Item Event** dialog later does not change the row's hash, so the next file re-upload still skips it. The detail is on [Transactions](https://eb.app/learn/transactions.md).
- If you delete a bank-imported transaction from an event, the hash is released. Re-uploading the same file (or re-running Match) will offer the row again so you can route it to a different event.
- Banks that change description text between a "pending" and a "posted" version of the same charge can produce two different fingerprints. The app would rather show you both copies than silently drop one that genuinely differs; you can deselect or delete the wrong one in the Review screen.

## When a file can't be read

The parser rejects files for three reasons:

- **The file is empty**, or contains no transaction rows. Sometimes a bank export comes back as a blank report. Re-export and try again.
- **No columns can be detected.** The file isn't using one of the recognized separators (comma, tab, semicolon, or pipe), or the column shape is too irregular. Open the file in a text editor and re-export, or trim the file to just the data rows before uploading.
- **No date or amount column can be identified.** The file looks structured but the parser can't find a column that consistently holds dates, or one that holds numbers. Check that you exported transaction history (not, say, an account summary).

The error message names the file and what went wrong. Individual rows with a missing date, missing description, or unreadable amount are dropped quietly while the rest of the file imports normally; the count on the **Review Transaction Matches** screen is the source of truth, not the row count in the file. If you can't get the parser to read a file from your bank, the manual fallback is to type the transactions in by hand on the events you care about. See [Transactions](https://eb.app/learn/transactions.md).

## After Resolve

Confirming matches in the **Review Transaction Matches** screen and tapping **Resolve N Selected Matches** does the same thing as resolving from a Plaid pull:

- Each kept match becomes a transaction in your account.
- Your account balance updates by the net of the inserted transactions. Income rows add; expense rows subtract; transfer rows move money between two accounts.
- For items where you record each purchase, an event closes once its running total reaches the planned amount and moves to History. If the total stays below the planned amount, the event stays open with the partial total attached.
- For items you tap once when paid, a confirmed match resolves the event immediately and moves it to History.

The Review screen tells you how many of each happened. The full mechanics are described on [Matching and Resolving](https://eb.app/learn/matching-and-resolving.md).

Anything that didn't match (a row the engine couldn't connect to any open event, often because there's no item set up for it) is left on the screen for you to skip or ignore. You can create the missing item later and re-upload the file; the duplicate check will skip the rows you already kept.

## Quick reference

| If you want to... | Do this |
|-------------------|---------|
| Upload while creating a new budget | **Budgets**, **Create Budget**, **AI Generated**, drop file, name each account |
| Upload to an existing budget | **Planner** toolbar **Match** button, drop file, pick each account from the dropdown |
| Upload more than one file at once | Same flow, up to 3 files |
| Avoid uploading duplicates | Re-upload is safe; the fingerprint check skips rows already on file |
| Convert an Excel export | Open in Excel or Numbers, save as CSV, upload that |
| Split one big CSV into per-account files | Open in a spreadsheet, filter by account, save each subset separately |
| Stay under the size limit | 200 KB per file, 3 files at most. Export a shorter date range if a file is too big |

## Behind the scenes

The parser is intentionally tolerant of how different banks lay out their exports. Some details that aren't visible in the UI:

- **Separator detection.** The parser scores comma, tab, semicolon, and pipe across the first 5 lines and picks whichever produces the most consistent column count.
- **Header recognition.** A row qualifies as a header when at least half of its fields contain a known column keyword. Spanish equivalents are recognized alongside English (so a file with `Fecha`, `Descripción`, `Monto`, `Saldo` headers parses correctly).
- **Date format scan.** When the date column uses an ambiguous slash format like `01/02/2025`, the parser scans up to 50 rows looking for any value with a first segment greater than 12 (which forces the format to day-first) or a second segment greater than 12 (which forces month-first). If neither appears, it defaults to month-first.
- **Debit/credit detection.** When two numeric columns are present, the parser checks whether they're mutually exclusive (each row has a value in one or the other but not both). If so, the column with more empty rows becomes the debit column and the other becomes credit.
- **Balance detection.** When two numeric columns are present and one looks like a running total (each row's value equals the previous row's value plus the amount column, within a one-cent tolerance, on at least 60% of the rows), that column becomes the balance and the other becomes the amount.
- **Line endings.** Windows-style `\r\n` and old Mac-style `\r` line endings are normalized to `\n` before parsing, so files saved on any platform work.
- **Quoted values with embedded commas.** Standard CSV quoting is honored, including the `""` escape for a literal quote inside a quoted field.

The fingerprint hash is a 16-character truncation of a SHA-256 over the canonical, normalized data (date in ISO form, description trimmed, amount and balance to two decimal places). At that length, the chance of two genuinely different transactions producing the same fingerprint is roughly 3 in 100 million across 10,000 transactions, which is small enough that the per-item dedup is the binding rule and not the hash collision rate.

## Related pages

- [Bank linking](https://eb.app/learn/bank-linking.md): the Premium alternative to file upload.
- [Matching and Resolving](https://eb.app/learn/matching-and-resolving.md): what happens after candidates are parsed.
- [Transactions](https://eb.app/learn/transactions.md): the canonical home for the per-item dedup story, plus how to type transactions by hand when you can't get a file to upload.
- [Subscription](https://eb.app/learn/subscription.md): file upload is on every plan; Plaid is Premium-only.

---

## About this document

This is a markdown mirror of [https://eb.app/learn/file-uploads/](https://eb.app/learn/file-uploads/).
The HTML version is the canonical form. This file exists so AI/LLM
tools can ingest the content without HTML parsing.
