# Exact Online — Accounting API: connection

> Canonical URL: https://developers.apideck.com/apis/accounting/exact-online/connection

# Exact Online: Bank feeds

This guide explains how bank feeds work on an Exact Online connection: what a bank feed
account is in Exact's own terms, the one setting that decides whether your statements reach the
bookkeeper, how to set it up, and how to send and read statements.

> **The single rule to remember.** A bank movement only appears in Exact Online's reconciliation
> screen when it is booked against the **unallocated account of its own bank journal**. Post it
> anywhere else and it is booked correctly, shows up in the ledger — and is invisible to the person
> who has to reconcile it. Everything below follows from that.

---

## 1. What a bank feed account is here

Exact Online has no separate "bank feed" object. A bank feed account **is a bank journal**
(*dagboek* / *journal*), the same thing you see in Exact under **Master data → Financial →
Journals**. A bank journal carries three things that matter for feeds:

| On the journal | In Exact's UI | In Unify |
|---|---|---|
| The bank account it belongs to | *Bank account* | `journals.iban` |
| The ledger account it books to | *G/L Account* | `journals.default_account` |
| The account unreconciled movements park in | *G/L Account: Unallocated* | `journals.clearing_account` |

`bank-feed-accounts` lists these journals read-only. **Creating one through
`bank-feed-accounts` is not supported** — that operation cannot supply the bank account or the
unallocated account. Create it through `journals` instead, which exposes all three.

(Posting a statement to an account with no unallocated account set is refused outright — see §3.
The operation is withdrawn so that such an account cannot be created through Unify in the first
place.)

---

## 2. Setting up an account

### Option A — in Exact Online

Create the bank account first (**Master data → Financial → Bank accounts**), then the journal
(**Master data → Financial → Journals**, type *Bank*). Set **G/L Account: Unallocated** on the
journal. Exact fills it with a default; leave that default alone unless your bookkeeper wants a
specific account.

### Option B — through Unify

```http
POST /accounting/journals
```

```json
{
  "name": "Business account EUR",
  "code": "31",
  "type": "bank",
  "iban": "NL91ABNA0417164300",
  "default_account": { "id": "<ledger account id>" },
  "clearing_account": { "id": "<unallocated ledger account id>" }
}
```

`clearing_account` is what the statements will be posted to. If you omit it, Exact assigns its own
default and the feed still works — set it explicitly only when the bookkeeper wants a particular
account.

Then read the accounts back and keep the `id`:

```http
GET /accounting/bank-feed-accounts
```

---

## 3. Sending statements

```http
POST /accounting/bank-feed-statements
```

```json
{
  "bank_feed_account_id": "<id from bank-feed-accounts>",
  "transactions": [
    {
      "posted_date": "2026-09-30T00:00:00.000Z",
      "description": "Card payment - Office supplies",
      "amount": 42.5,
      "credit_or_debit": "debit",
      "source_transaction_id": "txn_8f21c0"
    }
  ]
}
```

What happens to each field:

- **`amount` + `credit_or_debit`** — `debit` books money out, `credit` books money in. Send the
  amount as a positive number and let `credit_or_debit` carry the direction; a sign on `amount` is
  ignored in favour of `credit_or_debit`.
- **`source_transaction_id`** — stored verbatim and read back unchanged. Use your own provider's
  transaction id here; it is how you recognise the line later.
- **`start_balance` / `end_balance`** — accepted but not used. Exact computes the statement's
  opening and closing balance from the journal's own running total.
- **`counterparty`, `merchant_category_code`** — no equivalent in Exact; neither stored nor returned.
- **`description`** — falls back to `reference` when absent.

Every line lands on the journal's unallocated account, uncategorized, exactly where the
reconciliation screen looks for it. **If the account has no unallocated account configured, the
request is rejected with a `400`** rather than silently booked somewhere useless.

> **Unify does not de-duplicate.** Posting the same statement twice creates two statements in
> Exact. Track what you have already sent on your side.

---

## 4. Reading statements back

**By id.** The create call returns the statement's `id`; read it back with that:

```http
GET /accounting/bank-feed-statements/{id}
```

This returns the statement with its `transactions` array, each carrying the
`source_transaction_id` you sent.

**By account.** For a list, always filter — an unfiltered read spans every bank account in the
administration:

```http
GET /accounting/bank-feed-statements?filter[bank_feed_account_id]=<id>
```

The filter accepts either the account `id` or the journal's short code as it appears in Exact
(`31` in the example above).

`status` always reads as `success`. Exact has no delivery or acceptance state for a posted
statement, so anything that can be read back is reported as posted; `pending` and `rejected` never
occur.

---

## 5. Reconciliation

Reconciliation itself stays in Exact Online: the bookkeeper opens the bank journal's
reconciliation screen, and matches each unallocated line against an invoice, a bill or a ledger
account. Unify delivers the movements; it does not match them, and there is no API operation to
reconcile a line.

---

## 6. Troubleshooting

**"The statements posted fine, but there is nothing to reconcile."** The lines were booked to an
account other than the journal's unallocated account. Check `clearing_account` on the journal
(`GET /accounting/journals/{id}`) against **G/L Account: Unallocated** in Exact's journal screen —
they must be the same account. This is by far the most common cause.

**"`400` — the journal declares no unallocated account."** The journal has no *G/L Account:
Unallocated* set. Set one in Exact, or send `clearing_account` when creating the journal.

**"The same transactions appear twice."** A statement was posted more than once. Unify does not
de-duplicate on `source_transaction_id`.

**"I get statements from accounts I did not ask for."** The read was unfiltered. Add
`filter[bank_feed_account_id]`.


[API reference](https://developers.apideck.com/apis/accounting/reference.md) · [Coverage matrix](https://developers.apideck.com/apis/accounting/coverage)
