# Bank Statement CSV → NetSuite Import Normalizer (`omararida/bank-statement-to-netsuite`) Actor

Turn any bank's CSV export into a clean NetSuite-ready import file: auto-detects columns, dates, debit/credit, flags duplicates, and outputs bank-statement or journal-entry layouts with totals.

- **URL**: https://apify.com/omararida/bank-statement-to-netsuite.md
- **Developed by:** [Omar Arida](https://apify.com/omararida) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 transaction row normalizeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Bank Statement CSV → NetSuite Import Normalizer

Every bank exports a different CSV: different column names, semicolons instead of commas, `1.234,56` instead of `1,234.56`, debit/credit in two columns or one signed column, dates in three orders. This Actor takes **any bank statement CSV** and returns a **clean, consistent file ready for NetSuite import** – plus totals and data-quality flags so month-end reconciliation starts from trustworthy numbers.

Built by a NetSuite-certified consultant who has reconciled too many statements by hand.

### What it does

1. **Detects the structure** – delimiter, header row (skips bank metadata lines), and which columns hold date, description, payee, reference, debit, credit, amount, balance. Works with English, German, Spanish, French and Arabic headers.
2. **Normalizes values** – parses `(1,234.56)`, `1.234,56`, `1 234,56 DR`, currency symbols; converts dates from any common order to the format your NetSuite user expects.
3. **Flags issues** – unparseable dates, missing amounts, empty descriptions, possible duplicate rows.
4. **Outputs NetSuite layouts**:
   - **Bank statement import** – `Date, Amount, Transaction Type, Transaction ID, Payee, Memo, Account Number, Currency`
   - **Journal entry import** – balanced two-line journals (bank account vs. suspense/offset account) with an External ID per transaction for easy reversal
   - **Generic cleaned CSV** – all columns plus an *Issues* column
5. **Summarizes** – money in, money out, net, date range, rows with issues.

### Who uses it

- NetSuite admins and accountants doing bank reconciliation or importing historical statements
- Implementation consultants migrating opening transactions
- Bookkeepers serving multiple clients with different banks
- AI agents (via Apify MCP) that need structured bank data from a CSV

### Input

```json
{
    "csvText": "Date;Description;Amount;Balance\n01.10.2026;Gehalt ACME GmbH;5.000,00;12.000,00\n03.10.2026;Kartenzahlung AMAZON;-129,99;11.870,01",
    "outputLayout": "bank_statement",
    "dateOutputFormat": "MM/DD/YYYY",
    "currency": "EUR",
    "accountNumber": "DE89370400440532013000"
}
```

| Field | Description | Default |
| --- | --- | --- |
| `csvText` | Pasted CSV text | – |
| `csvUrl` | URL of the CSV (used if `csvText` empty) | – |
| `outputLayout` | `bank_statement`, `journal`, `generic` | `bank_statement` |
| `dateOutputFormat` | `MM/DD/YYYY`, `DD/MM/YYYY`, `YYYY-MM-DD` | `MM/DD/YYYY` |
| `dateInputFormat` | `auto`, `DMY`, `MDY`, `YMD` | `auto` |
| `delimiter` | `auto`, `,`, `;`, tab, `\|` | `auto` |
| `currency`, `accountNumber` | Stamped on every row | – |
| `bankAccountGl`, `suspenseAccount` | Accounts for journal layout | `Bank`, `Suspense` |
| `columnMap` | Override detection, e.g. `{"date":"Booking Date"}` | – |

### Output

Dataset row:

```json
{
    "rowNumber": 2,
    "date": "2026-10-03",
    "dateFormatted": "10/03/2026",
    "description": "Kartenzahlung AMAZON",
    "payee": null,
    "reference": null,
    "amount": -129.99,
    "debit": 129.99,
    "credit": null,
    "balance": 11870.01,
    "currency": "EUR",
    "accountNumber": "DE89370400440532013000",
    "transactionType": "WITHDRAWAL",
    "hash": "3f9a1c2e",
    "issues": []
}
```

Files in the run's key-value store: `netsuite_import.csv` (the import file) and `SUMMARY` (totals and detected columns).

### Importing into NetSuite

- **Bank statement layout** → Transactions > Bank > Banking Import History > Import Online Banking Data (CSV format), or map in **Setup > Import/Export > Import CSV Records**.
- **Journal layout** → Import CSV Records > Transactions > Journal Entry. Each transaction has an External ID (`BANK-<date>-<hash>`), so re-imports update rather than duplicate.

### Pricing

Pay per event: a small amount **per transaction row** processed. Set a max cost per run in the Apify Console.

### Use from code or AI agents

```bash
curl "https://api.apify.com/v2/acts/omararida~bank-statement-to-netsuite/run-sync-get-dataset-items?token=<APIFY_TOKEN>" \
  -X POST -H 'Content-Type: application/json' \
  -d '{"csvText":"Date,Description,Amount\n2026-10-01,Opening,100.00","outputLayout":"generic"}'
```

Works through the [Apify MCP server](https://mcp.apify.com).

### Privacy

Statements are processed in your own Apify run and stored only in your run's storage, which you control and can delete.

### Support

Bank format not detected? Open an issue on the **Issues** tab with the header row (no amounts needed) and it will be added.

# Actor input Schema

## `csvText` (type: `string`):

Paste the full CSV text exported from your bank portal, including the header row.

## `csvUrl` (type: `string`):

Public URL of the CSV file (e.g. an Apify key-value store record or a signed download link). Used only when csvText is empty.

## `outputLayout` (type: `string`):

bank_statement = columns for NetSuite bank statement / reconciliation import. journal = balanced journal-entry lines (bank vs suspense). generic = cleaned columns with issue flags.

## `dateOutputFormat` (type: `string`):

Must match the NetSuite user's date preference.

## `dateInputFormat` (type: `string`):

How dates like 03/04/2026 should be read. Auto resolves unambiguous dates and defaults to day-first.

## `delimiter` (type: `string`):

Field separator used in the CSV. Auto-detect handles comma, semicolon, tab and pipe.

## `currency` (type: `string`):

ISO code to stamp on every row (e.g. USD, EGP, AED).

## `accountNumber` (type: `string`):

Stamped on every row (used by NetSuite to match the bank account).

## `bankAccountGl` (type: `string`):

Account name/number used for the bank side of journal lines.

## `suspenseAccount` (type: `string`):

Account used for the other side of each journal line until it is reclassified.

## `columnMap` (type: `object`):

If auto-detection picks the wrong columns, name them here, e.g. {"date": "Booking Date", "amount": "Betrag"}. Keys: date, description, amount, debit, credit, balance, reference, payee.

## `maxRows` (type: `integer`):

Safety cap on the number of transaction rows processed (and charged).

## Actor input object example

```json
{
  "csvText": "Date,Description,Debit,Credit,Balance\n01/10/2026,SALARY ACME LTD,,5000.00,12000.00\n03/10/2026,CARD PAYMENT AMAZON,129.99,,11870.01\n05/10/2026,TRANSFER TO SAVINGS,1000.00,,10870.01",
  "outputLayout": "bank_statement",
  "dateOutputFormat": "MM/DD/YYYY",
  "dateInputFormat": "auto",
  "delimiter": "auto",
  "bankAccountGl": "Bank",
  "suspenseAccount": "Suspense",
  "maxRows": 100000
}
```

# Actor output Schema

## `transactions` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `summary` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "csvText": `Date,Description,Debit,Credit,Balance
01/10/2026,SALARY ACME LTD,,5000.00,12000.00
03/10/2026,CARD PAYMENT AMAZON,129.99,,11870.01
05/10/2026,TRANSFER TO SAVINGS,1000.00,,10870.01`
};

// Run the Actor and wait for it to finish
const run = await client.actor("omararida/bank-statement-to-netsuite").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "csvText": """Date,Description,Debit,Credit,Balance
01/10/2026,SALARY ACME LTD,,5000.00,12000.00
03/10/2026,CARD PAYMENT AMAZON,129.99,,11870.01
05/10/2026,TRANSFER TO SAVINGS,1000.00,,10870.01""" }

# Run the Actor and wait for it to finish
run = client.actor("omararida/bank-statement-to-netsuite").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "csvText": "Date,Description,Debit,Credit,Balance\\n01/10/2026,SALARY ACME LTD,,5000.00,12000.00\\n03/10/2026,CARD PAYMENT AMAZON,129.99,,11870.01\\n05/10/2026,TRANSFER TO SAVINGS,1000.00,,10870.01"
}' |
apify call omararida/bank-statement-to-netsuite --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,omararida/bank-statement-to-netsuite"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/nzoyZwArLI593QaNN/builds/udNuCBf9l4xT8yLiB/openapi.json
