# POST /api/v1/transactions/bulk-upload

> Bulk upload transactions to new source account

- **Tag:** transactions
- **Operation ID:** `bulk_upload_transactions_api_v1_transactions_bulk_upload_post`

## Description

Upload historical transactions from a CSV/Excel file to a new source account.

**Workflow (via Temporal for durability):**

*Local engine:*
1. Gets/creates ledger
2. Reads transactions from the CSV/Excel file in S3
3. Creates Transaction + Journal Entry rows with categorization
4. Runs AI categorization pass for uncategorized transactions

*Teal engine:*
1. Gets/creates ledger and personal source account in Teal
2. Reads transactions from the CSV/Excel file in S3
3. Posts transactions to Teal source account
4. Imports journal entries created by Teal

**Supported File Formats:** .csv, .xlsx, .xls

**CSV/Excel Columns (flexible naming):**
- date/datetime/transaction_date: Transaction date (YYYY-MM-DD or ISO format)
- amount/transaction_amount/value: Amount in dollars (positive or negative)
- description/memo/name: Transaction description

## Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

## Request body

Schema: `BulkTransactionUploadRequest`

- `ledger_id` (string) — Optional: UUID of existing ledger to use. If provided, ledger creation is skipped and ledger_name/ledger fields are ignored.
- `ledger_name` (string) — Display name for the new ledger (required if ledger_id not provided, e.g., 'My Old Credit Card XXXX')
- `source_account_name` (string) — Optional: Display name for the source account. Defaults to ledger name if not provided.
- `business_personal` (string) — Whether the source account is a business or personal account. 'business' (default) for company transactions, 'personal' for owner draws/contributions.
- `invert_transaction_amounts` (boolean) — If true, transaction amounts are inverted during import. Useful when CSV has opposite sign convention.
- `s3_key` (string · required) — S3 key of the CSV file containing transactions
- `start_date` (string · date) — Optional: Only upload transactions on or after this date (YYYY-MM-DD). Filters transactions before upload.
- `end_date` (string · date) — Optional: Only upload transactions on or before this date (YYYY-MM-DD). Filters transactions before upload.
- `check_duplicates` (boolean) — If true, checks for duplicate transactions before uploading. Duplicates are skipped.
- `duplicate_match_fields` (array · string) — Fields to use for duplicate detection: 'amount', 'date', 'description'. Defaults to all three.
- `currency` (string) — Currency for this account (USD, CAD, AUD, EUR, or GBP). Defaults to business default.
- `editable` (boolean) — If true, journal entries can be manually posted to this account.
- `type` (string) — Account type: asset, liability, equity, revenue, expense. Required in Custom Mode.
- `description` (string) — Optional description of the account's purpose.
- `status` (string) — Account status: 'active' or 'inactive'. Inactive accounts hidden from dropdowns.
- `debit_credit` (string) — Normal balance: 'debit' (assets/expenses) or 'credit' (liabilities/equity/revenue). Required in Custom Mode.
- `sort_code` (string) — Sort code for chart ordering (e.g., '1000' for assets, '4000' for revenue). Required in Custom Mode.
- `sub_type` (string) — Sub-classification (current_assets, operating_expenses, etc.). Required in Custom Mode.
- `report_cash_flow` (boolean) — Include in cash flow statement. Required in Custom Mode.
- `financial_account_type` (string) — Templated Mode: bank_account, credit_card, payments, payroll, loan, prepaid_card, accounts_receivable, accounts_payable.
- `parent_id` (string) — UUID of parent ledger for sub-accounts (e.g., 'Operating Expenses' → 'Office Supplies').
- `column_mapping` (object) — User-supplied mapping from DayZero field names to CSV column names. Keys: 'date', 'amount', 'description'. Values: the CSV header to use. When provided, auto-detection is skipped.

## Responses

### 201 — Successful Response

Schema: `BulkTransactionUploadResponse`

- `workflow_id` (string · required) — Temporal workflow ID for tracking progress
- `business_id` (string · required) — Business ID the upload is for
- `ledger_name` (string · required) — Name of the ledger being created
- `status` (string · required) — Workflow status (typically 'started' initially)
- `executor` (string · required) — Execution backend (typically 'temporal')

### 400 — Bad Request - Invalid input

### 401 — Unauthorized - Authentication required

### 403 — Forbidden - Insufficient permissions

### 422 — Validation Error

Schema: `HTTPValidationError`

- `detail` (array · ValidationError) → `ValidationError`
  - `loc` (array · string | integer · required)
  - `msg` (string · required)
  - `type` (string · required)
  - `input` (object)
  - `ctx` (object)

## Code samples

### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/transactions/bulk-upload' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "s3_key": "string"
}'
```

### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/transactions/bulk-upload', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "s3_key": "string"
}),
});
const data = await response.json();
```

### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {
  "s3_key": "string"
}

response = httpx.post("https://api.ondayzero.com/api/v1/transactions/bulk-upload", headers=headers, json=payload)
data = response.json()
```

## See also

- HTML version: https://www.ondayzero.com/docs/reference/transactions/bulk-upload-transactions
- OpenAPI slice: https://www.ondayzero.com/docs/reference/transactions/bulk-upload-transactions/openapi.json
- Other endpoints in **transactions**: https://www.ondayzero.com/docs/reference/transactions
