Transaction Imports & Matching
Zenvilope supports importing transactions from your bank via OFX/QFX files. This guide explains how the import, matching, approval, and rejection workflows operate.
Import Overview
When you import transactions from your bank:
- Parse - The OFX file is parsed to extract transaction data
- Match - Each transaction is checked for duplicates and potential matches
- Preview - You see what will be imported before confirming
- Import - Transactions are created or linked to existing entries
- Approve - You review and approve imported transactions
Transaction States
After import, transactions can be in several states:
| State | isApproved | isMatched | Description |
|---|---|---|---|
| Pending Import | false | false | New import, needs review |
| Pending Match | false | true | Linked to manual entry, needs review |
| Approved Import | true | false | Reviewed and accepted |
| Approved Match | true | true | Linked transaction, reviewed |
| Manual Entry | true | false | User-created, no import data |
Matching Behaviour
Duplicate Detection
During import preview, transactions are checked against existing imports:
- Duplicates: Same
imported_idalready exists in the account → Skipped - Rejected: Previously rejected import with same
imported_id→ Skipped
Payee Fuzzy Matching
Import files contain raw payee strings (e.g., "AMAZON.COM*1A2B3C SEATTLE"). Zenvilope fuzzy-matches these against your existing payees:
- Normalize the imported payee string (lowercase, strip punctuation)
- Compare against existing payee names
- If match found → Link to existing payee
- If no match → Create new payee from import string
Manual Transaction Matching
When importing, the system looks for existing manual entries that might match:
Match criteria:
- Same account
- Exact same amount
- Date within ±3 days of import date
- Not already matched or reconciled
When matched:
- Import metadata is "dumped" onto the manual transaction
- Manual transaction's date is preserved (user's date takes priority)
- OFX date stored in
importedDatefor reference - Transaction marked as
isMatched=true,isApproved=false
Approval Workflow
All imported transactions require approval. This ensures you review bank data before it affects your budget.
Approving a Transaction
- Find transactions with the warning indicator (needs attention)
- Open the transaction for editing
- Review/adjust: payee, category, date, amount
- Click "Approve" (replaces "Save" button for unapproved transactions)
TIP
Unapproved transactions still affect your budget calculations - approval is about verification, not activation.
Bulk Approval
Select multiple transactions and use bulk actions to approve them all at once.
Rejection Workflow
Reject an import when the bank data shouldn't create a transaction.
What Rejection Does
For pure imports (not matched):
- Deletes the imported transaction
- Creates a "tombstone" record to prevent re-import
For matched transactions:
- Removes import metadata from the manual transaction
- Reverts the manual entry to approved status
- Creates a tombstone to prevent re-import
When to Reject
- Duplicate charge that will be refunded
- Bank error that will be corrected
- Transaction you don't want to track
- Incorrect match to manual entry
Tombstones
When you reject an import, a RejectedImport record is created. This prevents the same imported_id from being re-imported in future imports.
Unmatch Workflow
Use unmatch when an import was incorrectly linked to the wrong manual transaction.
What Unmatch Does
Reverts the manual transaction:
- Clears all import metadata (
importedId,importedPayee, etc.) - Sets
isMatched=false,isApproved=true - Manual entry returns to its original state
- Clears all import metadata (
Creates a new import transaction:
- New transaction from the original import data
- Fuzzy-matches payee (creates new if needed)
- Uses payee's default category if available
- Sets
isMatched=false,isApproved=false - Marked as cleared (bank exports only cleared transactions)
When to Unmatch
- Import was matched to wrong manual transaction
- You want to keep both entries separate
- Manual entry was for something different
INFO
After unmatching, you'll have:
- Your original manual entry (restored, approved)
- A new pending import transaction (needs approval)
Visual Indicators
The transaction list shows status with icons:
| Icon | Meaning |
|---|---|
| ⚠️ Yellow triangle | Needs attention (unapproved) |
| 🔗 Blue link | Matched with bank import (approved) |
| ⬇️ Grey download | Imported transaction (approved, not matched) |
Import Data Fields
When a transaction has import data, these fields are populated:
| Field | Description |
|---|---|
importedId | Bank's unique transaction ID (prevents duplicates) |
importedPayee | Raw payee string from bank |
importedTransactionType | OFX transaction type (DEBIT, CREDIT, etc.) |
importedDate | Date from bank (may differ from transaction date) |
Best Practices
Import Regularly
Import weekly or after each bank statement to catch transactions early.
Review Matches Carefully
When a match is found, verify it's correct:
- Check the amounts match exactly
- Verify the dates are reasonable
- Confirm payees align
Categorize During Approval
Use the approval step to assign categories to imported transactions.
Don't Fear Rejection
If an import is wrong, reject it. The tombstone prevents re-import headaches.
Unmatch When Needed
If you matched to the wrong transaction, unmatch rather than trying to fix it manually.
API Endpoints
For developers, the key endpoints are:
POST /api/budgets/{id}/accounts/{id}/import-ofx-preview # Preview import
POST /api/budgets/{id}/accounts/{id}/import-ofx-confirm # Confirm import
POST /api/budgets/{id}/transactions/{id}/approve # Approve transaction
POST /api/budgets/{id}/transactions/{id}/reject # Reject import
POST /api/budgets/{id}/transactions/{id}/unmatch # Unmatch transaction
POST /api/budgets/{id}/transactions/bulk-approve # Bulk approveNext Steps
- Learn about recording transactions manually
- Understand account reconciliation
- Set up categories for better organization