# Pre-accounting automation for accounting firms

Pre-accounting and bookkeeping automation products collect source documents, bank transactions, and online sales for an accounting firm's SME clients, then hand booking-ready entries to each client's ledger for the accountant to review and post. This guide uses the [Accounting API](/apis/accounting/reference) alongside the [Ecommerce API](/apis/ecommerce/reference) to onboard many client companies, read each client's reference data, and create draft bills, expenses, invoices, and journal entries with attachments.

## One integration for every ledger

Accounting firms rarely standardize on one ledger. One client runs on Xero, another on QuickBooks, a third on Exact Online, and the ecommerce clients also connect Shopify, WooCommerce, or Amazon. The Apideck Unified API lets a pre-accounting product build the collection, categorization, and review workflow once instead of per ledger.

- No per-ledger auth, pagination, or rate-limit code.
- One shared model for `ledger-accounts`, `suppliers`, `customers`, `tax-rates`, and `tracking-categories` across clients.
- One request shape for creating draft bills, expenses, invoices, and journal entries.
- Ecommerce orders come through the same Vault consumer as the client's ledger.

## Resource mapping

Pre-accounting workflows ingest a handful of source document types and map each to one unified resource. The same mapping holds across every supported ledger that covers the resource.

| Source document | Unified resource |
| --- | --- |
| Vendor invoice PDF or email | [`POST /accounting/bills`](/apis/accounting/reference#operation/billsAdd) |
| Receipt for an already-paid card or cash purchase | [`POST /accounting/expenses`](/apis/accounting/reference#operation/expensesAdd) |
| Sales invoice drafted on behalf of the client | [`POST /accounting/invoices`](/apis/accounting/reference#operation/invoicesAdd) |
| Ecommerce sales summary, FX adjustment, payroll journal | [`POST /accounting/journal-entries`](/apis/accounting/reference#operation/journalEntriesAdd) |
| Scanned receipt or exported PDF for any of the above | [`POST /accounting/attachments/{reference_type}/{reference_id}`](/apis/accounting/reference#operation/attachmentsUpload) |
| Ecommerce order, used to build the sales journal | [`GET /ecommerce/orders`](/apis/ecommerce/reference#operation/ordersAll) |

## Walkthrough

### 1. One Vault consumer per client company

Model each client company as its own Vault consumer. If a client runs multiple legal entities on separate ledger instances, create one consumer per entity so authentication, rate limits, and audit trails stay scoped correctly. Store the mapping between your internal `client_id` and the Apideck `consumer_id` in your own database.

```json
{
  "consumer_id": "client_01HRX0E8GCQ1Y3W4ZK9F7V2M6B",
  "metadata": {
    "account_name": "Northwind Retail BV",
    "user_name": "Firm bookkeeping team",
    "email": "bookkeeper@firm.example",
    "image": "https://assets.firm.example/northwind.png"
  }
}
```

Send this to [`POST /vault/consumers`](/apis/vault/reference#operation/consumersAdd), then launch Vault for the firm's bookkeeper to connect the client's ledger and any ecommerce or payment providers. Consumer `metadata` only drives the Vault display, so keep the engagement partner and the firm's internal client code in your own database to filter review queues per team.

### 2. Pull reference data once per client, cache it

Before you can post anything, you need the client's chart of accounts, VAT rates, vendor list, customer list, and tracking dimensions. Fetch these once per connection, cache them keyed by `consumer_id` and `service_id`, and refresh on a schedule or on [`vault.connection.updated`](/apis/webhook/reference) webhooks.

```http
GET /accounting/ledger-accounts?limit=200 HTTP/1.1
Host: unify.apideck.com
Authorization: Bearer {API_KEY}
x-apideck-app-id: {APP_ID}
x-apideck-consumer-id: {CONSUMER_ID}
x-apideck-service-id: xero
```

Repeat for [`GET /accounting/tax-rates`](/apis/accounting/reference#operation/taxRatesAll), [`GET /accounting/suppliers`](/apis/accounting/reference#operation/suppliersAll), [`GET /accounting/customers`](/apis/accounting/reference#operation/customersAll), and [`GET /accounting/tracking-categories`](/apis/accounting/reference#operation/trackingCategoriesAll). Tracking categories are read-only on several ledgers (including Xero), so create new dimensions in the ledger UI when the connector lacks write coverage. Store the returned IDs in a per-client mapping table that your categorization logic reads from.

```json
{
  "client_id": "northwind",
  "service_id": "xero",
  "mappings": {
    "default_expense_account_id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J1",
    "default_sales_account_id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J2",
    "ecommerce_clearing_account_id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J3",
    "stripe_fees_account_id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J4",
    "card_clearing_account_id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J5",
    "default_tax_rate_id": "tax_std_21",
    "tracking_dimension_department_id": "trk_01H8X9Y2A3B4C5D6E7F8G9H0K1"
  }
}
```

Keep this cache behind a thin service so the extraction pipeline (OCR, email ingestion, ecommerce sync) can look up the right account for a vendor or product category without a round trip to the ledger.

### 3. Create a draft bill from a vendor invoice

When OCR extracts a vendor invoice, resolve the supplier against the cached supplier list. If there is no match, create one with [`POST /accounting/suppliers`](/apis/accounting/reference#operation/suppliersAdd) first (on connectors where suppliers are writable), then post the bill as a draft so the accountant can review it before it hits the books.

```json
{
  "bill_number": "VND-2041-00318",
  "supplier": { "id": "sup_01HRYA7V4N3Q0K8M2P5T9W1Z6D" },
  "bill_date": "2025-02-04",
  "due_date": "2025-03-06",
  "currency": "EUR",
  "reference": "preacct-4a7c0b9e",
  "line_items": [
    {
      "description": "Managed hosting, February 2025",
      "ledger_account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J1" },
      "tax_rate": { "id": "tax_std_21" },
      "total_amount": 420.0,
      "tracking_categories": [
        { "id": "trk_01H8X9Y2A3B4C5D6E7F8G9H0K1", "name": "Operations" }
      ]
    }
  ],
  "sub_total": 420.0,
  "total_tax": 88.2,
  "total": 508.2,
  "status": "draft"
}
```

Send this to `POST /accounting/bills` ([Bills create](/apis/accounting/reference#operation/billsAdd)). Store the returned bill `id` next to the source document ID in your database, then upload the original PDF as an attachment. The upload body is the raw file, with its type in `Content-Type` and the file name in `x-apideck-metadata`:

```bash
curl -X POST "https://unify.apideck.com/accounting/attachments/bill/bill_01HRZCK8P2T4Q7V3N6M9D5F0J8" \
  -H "Authorization: Bearer {API_KEY}" \
  -H "x-apideck-app-id: {APP_ID}" \
  -H "x-apideck-consumer-id: {CONSUMER_ID}" \
  -H "x-apideck-service-id: quickbooks" \
  -H "x-apideck-metadata: {\"name\":\"vnd-2041-00318.pdf\",\"description\":\"Vendor invoice scan\"}" \
  -H "Content-Type: application/pdf" \
  --data-binary "@/tmp/vnd-2041-00318.pdf"
```

See [Attachments upload](/apis/accounting/reference#operation/attachmentsUpload) for the full operation. Several ledger connectors expose attachments as read-only through the unified API (Xero, Exact Online, Odoo, Workday, Yuki, and Zoho Books among them), and others have no attachment coverage at all (Acumatica, Moneybird, Procountor, Visma Netvisor, Wave, and FreshBooks among them). For those, keep the source PDF in your own DMS and link to it from the entry: `source_document_url` on bills and expenses (Xero only), the bill's `notes`, or the expense or journal entry `memo`.

### 4. Create a draft expense for an already-paid receipt

For paid card receipts (fuel, meals, SaaS auto-charges), use expenses instead of bills on connectors that support the resource, so the entry is recorded as paid from day one. `account` is the account the payment came out of, and each line's `account` is the expense account it is booked to.

```json
{
  "transaction_date": "2025-02-07T13:42:00Z",
  "account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J5", "type": "ledger_account" },
  "supplier": { "id": "sup_01HRYA7V4N3Q0K8M2P5T9W1Z7E" },
  "payment_type": "credit_card",
  "currency": "EUR",
  "reference": "preacct-9f82e1dd",
  "line_items": [
    {
      "description": "Client lunch, Amsterdam",
      "account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J6" },
      "tax_rate": { "id": "tax_std_09" },
      "total_amount": 48.5
    }
  ],
  "total_amount": 48.5,
  "memo": "Awaiting accountant review",
  "type": "expense",
  "status": "draft"
}
```

Send this to `POST /accounting/expenses` ([Expenses create](/apis/accounting/reference#operation/expensesAdd)). `payment_type` accepts `cash`, `check`, `credit_card`, or `other`. Not every ledger supports expenses as a dedicated resource. Exact Online, FreshBooks, MYOB, Pennylane, Visma Netvisor, and several others have no expense write coverage; on those connectors, fall back to a bill that you then mark as paid, or to a journal entry. Check the connector table below before dispatching.

### 5. Build a sales journal from ecommerce orders

For clients selling on Shopify, WooCommerce, or a marketplace such as Amazon, pull orders through the Ecommerce API and summarize each settlement period into one journal entry rather than posting every order as an invoice. This keeps the ledger clean and matches how most bookkeepers reconcile ecommerce payouts.

```http
GET /ecommerce/orders?filter[updated_since]=2025-02-01T00:00:00Z&limit=200 HTTP/1.1
Host: unify.apideck.com
Authorization: Bearer {API_KEY}
x-apideck-app-id: {APP_ID}
x-apideck-consumer-id: {CONSUMER_ID}
x-apideck-service-id: shopify
```

See [Orders list](/apis/ecommerce/reference#operation/ordersAll). Orders carry `sub_total`, `shipping_cost`, `total_tax`, `total_amount`, `refunded_amount`, and `payment_status`, but no payout ID or processor fee. Group paid orders by the settlement period in your own pipeline, take the fee and payout amounts from the payment provider's settlement report, then post one journal entry to the ledger:

```json
{
  "title": "Shopify sales 2025-02-01 to 2025-02-07",
  "memo": "Summary of 143 orders, settlement period 2025-02-01 to 2025-02-07",
  "posted_at": "2025-02-07T00:00:00Z",
  "currency": "EUR",
  "source_id": "shopify-settlement-2025-02-07",
  "journal_symbol": "SALES",
  "line_items": [
    {
      "description": "Gross sales",
      "ledger_account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J2" },
      "type": "credit",
      "total_amount": 12480.0,
      "tax_rate": { "id": "tax_std_21" }
    },
    {
      "description": "Shipping revenue",
      "ledger_account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J7" },
      "type": "credit",
      "total_amount": 320.0
    },
    {
      "description": "Processor fees",
      "ledger_account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J4" },
      "type": "debit",
      "total_amount": 384.0
    },
    {
      "description": "Payout clearing",
      "ledger_account": { "id": "acct_01H8X9Y2A3B4C5D6E7F8G9H0J3" },
      "type": "debit",
      "total_amount": 12416.0
    }
  ],
  "status": "draft"
}
```

Send this to `POST /accounting/journal-entries` ([Journal entries create](/apis/accounting/reference#operation/journalEntriesAdd)). Attach the payout CSV from the payment provider using the attachments endpoint with `reference_type` set to `journal-entry` on connectors that support attachment writes (QuickBooks, Intuit Enterprise Suite, NetSuite, Sage Intacct, MYOB, Microsoft Dynamics 365 Business Central, FreeAgent, and Sage Business Cloud).

### 6. Flag entries for accountant review

Pre-accounting products should never post straight to the live books without review. Two patterns work well together:

- Post every entry with `status: "draft"` and let the accountant promote it in the ledger UI.
- Mirror a review queue in your own product. Store the Apideck `id`, the source document hash, and a `confidence_score` from your categorizer. Only call back into the ledger (for example to update tracking categories) after a human approves.

For ledgers that don't return a native draft state, treat the entry as pending in your own system until a webhook or scheduled poll confirms it has been reviewed on the ledger side.

### 7. Avoid double posting

Give every source document a stable key: the SHA-256 of the PDF plus the client ID, or the payment provider's payout ID. Your own database is the primary guard. Keep a uniqueness constraint on `(consumer_id, service_id, source_key)` and store the created record's `id` against it, so a retry finds the existing row before calling the ledger.

For bills, invoices and journal entries, also send an [`Idempotency-Key` header](/guides/idempotency-keys) derived from the source key (for example a UUIDv5 of it). Resending a timed-out create with the same key and body writes the record at most once, within 24 hours or the connector's shorter window (6 minutes on Xero). Reusing a key with a different body returns 422, and connectors that cannot honour the key reject the request with 400. Expenses do not accept the header.

When a create times out outside that window, or for expenses, check the ledger with the filter that matches what you wrote:

| Resource | Field you set | Lookup filter |
| --- | --- | --- |
| Bill | `reference` | `filter[reference]` on [Bills list](/apis/accounting/reference#operation/billsAll) |
| Invoice | `number` | `filter[number]` on [Invoices list](/apis/accounting/reference#operation/invoicesAll) |
| Journal entry | `source_id` | `filter[source_id]` on [Journal entries list](/apis/accounting/reference#operation/journalEntriesAll) |
| Expense | `reference` | None. Rely on your own store. |

```http
GET /accounting/journal-entries?filter[source_id]=shopify-settlement-2025-02-07 HTTP/1.1
Host: unify.apideck.com
Authorization: Bearer {API_KEY}
x-apideck-app-id: {APP_ID}
x-apideck-consumer-id: {CONSUMER_ID}
x-apideck-service-id: xero
```

If a record comes back, skip the create. Connectors that do not store `source_id` reject `filter[source_id]` with `UnsupportedFiltersError`; on those, list recent entries with `filter[updated_since]` and match on your stored `id` or the `memo`.

## Connector-specific behavior

The table below covers every connector in the catalog. "Source" means the connector is used for reading ecommerce or payment data that your product summarizes into the ledger. "Ledger" means the connector is the client's book of record. Verify any read-only or limited coverage against the live coverage matrix before relying on it in production.

| Connector | Notes |
| --- | --- |
| access-financials | Ledger. Invoices, credit notes, suppliers, customers, and payments are writable. Ledger accounts and tracking categories are read-only. Bills, expenses, and journal entries are not in coverage, so AP postings and raw GL entries are out of scope. Fits clients where the firm only mirrors AR. |
| acumatica | Ledger. Supports bills, invoices, journal entries, invoice items, purchase orders, suppliers, customers, ledger accounts, and payments. Tax rates are read-only. Attachments, expenses, and tracking categories are not in coverage; keep source PDFs in your DMS and link to them from the entry's description. |
| amazon-seller-central | Source. Read orders through the Ecommerce API. Not a ledger. |
| api-explorer | Internal catalog entry used by the Apideck playground, not a client-connectable integration. |
| banqup | Limited. Customers and invoices are read-only, everything else is not in coverage. Use for syncing invoice status into your review queue, not for posting new entries. |
| bigcommerce | Source. Standard Ecommerce API coverage for orders and customers. |
| bol-com | Source. Standard Ecommerce API coverage for orders. |
| campfire | Ledger. Supports bills, invoices, journal entries, credit notes, ledger accounts, suppliers, customers, and departments for writes. Tracking categories, subsidiaries, balance sheet, and P&L are read-only. Bill payments and payments are limited; use journal entries for settlement allocations. Invoice items are read-only. Attachments are not in coverage. |
| clearbooks-uk | Mostly read-only. Bills, invoices, credit notes, suppliers, customers, and ledger accounts are read-only. Use the connector to pull reference data for your review UI; posting is not supported. |
| coverage | Internal catalog entry, not a client-connectable integration. |
| digits | Mostly read-only. Journal entries, customers, suppliers, tracking categories, balance sheet, and P&L are available for reads. Use for firm-side reporting rather than posting. |
| dualentry | Ledger. Supports bills, expenses, invoices, journal entries, credit notes, customers, suppliers, and payments. Attachments have limited support. Ledger accounts, tax rates, and subsidiaries are read-only, so build mappings during onboarding. |
| ebay | Source. Standard Ecommerce API coverage for orders. |
| etsy | Source. Standard Ecommerce API coverage for orders. |
| exact-online | Ledger. Supports bills, invoices, journal entries, suppliers, bill payments, and payments for writes. Customers, credit notes, ledger accounts, tax rates, and attachments are read-only. Expenses are not in coverage; use bills with the right payment status instead. Upload PDFs through the Exact UI or the native Document API. |
| exact-online-nl | Ledger. Same resource shape as `exact-online`: bills, invoices, journal entries, suppliers, bill payments, and payments are writable; customers, ledger accounts, tax rates, and attachments are read-only. Expenses are not in coverage. |
| exact-online-uk | Ledger. Bills are read-only; invoices, journal entries, suppliers, bill payments, and payments are writable. Use journal entries for AP postings. Attachments and ledger accounts are read-only. |
| freeagent | Ledger. Expenses, invoices, journal entries, credit notes, customers, payments, and attachments are writable. Bills and suppliers are read-only, so AP capture is one-way. Ledger accounts are read-only. |
| freshbooks | Ledger. Bills, invoices, invoice items, suppliers, customers, ledger accounts, tax rates, and payments are writable. Journal entries are read-only, so avoid raw GL postings. Expenses and attachments are not in coverage. |
| intuit-enterprise-suite | Ledger. Full write coverage for bills, expenses, invoices, journal entries, credit notes, purchase orders, departments, locations, tracking categories, and attachments. Behaves similarly to QuickBooks Online with multi-entity extensions. |
| kashflow | Mostly read-only. Invoices, credit notes, customers, suppliers, tax rates, ledger accounts, journal entries, and payments are read-only. Use for extraction into your review queue only. |
| lightspeed | Source. Standard Ecommerce API coverage for retail POS orders. |
| lightspeed-ecommerce | Source. Standard Ecommerce API coverage for orders. |
| magento | Source. Standard Ecommerce API coverage for orders and products. |
| microsoft-dynamics-365-business-central | Ledger. Supports bills, expenses, invoices, journal entries, credit notes, suppliers, customers, purchase orders, and attachments. Tax rates, ledger accounts, locations, tracking categories, and payments are read-only; record settlements through journal entries. |
| mollie | Not covered by the Ecommerce API orders resource and not a ledger. Take orders and settlement totals from Mollie directly. |
| moneybird | Ledger. Supports bills, expenses, invoices, journal entries, invoice-item reads, ledger accounts, suppliers, customers, and tracking categories for writes. Subsidiaries and tax rates are read-only. Attachments are not in coverage via the unified API. |
| mrisoftware | Ledger (property management). Supports bills, journal entries, and suppliers for writes. Customers, departments, locations, subsidiaries, purchase orders, ledger accounts, tracking categories, and tax rates are read-only. Invoices, credit notes, and expenses are not in coverage. |
| myob | Ledger. Supports bills, invoices, journal entries, customers, ledger accounts, tax rates, payments, bill payments, and attachments. Credit notes are read-only. Suppliers and tracking categories are not in coverage; manage vendors in the MYOB UI. |
| myob-acumatica | Ledger. Supports bills, invoices, journal entries, credit notes, customers, suppliers, purchase orders, bill payments, and payments. Tax rates are read-only. Attachments and tracking categories are not in coverage. |
| netsuite | Ledger. Full write support for bills, expenses, invoices, journal entries, credit notes, suppliers, customers, ledger accounts, tax rates, tracking categories, subsidiaries, purchase orders, and attachments. Departments and locations are read-only but can be referenced on entries. Set `subsidiary.id` when posting into multi-entity accounts. |
| odoo | Ledger. Supports bills, expenses, invoices, journal entries, credit notes, suppliers, customers, bill payments, and payments. Ledger accounts, tax rates, departments, locations, subsidiaries, tracking categories, and attachments are read-only. |
| overview | Internal catalog entry, not a client-connectable integration. |
| pennylane | Ledger. Supports bills, invoices, journal entries, suppliers, customers, ledger accounts, purchase orders, invoice items, and tracking categories. Attachments and bill payments have limited support. Tax rates are read-only. Expenses are not in coverage. |
| picqer | Source. Standard Ecommerce API coverage for orders. |
| prestashop | Source. Standard Ecommerce API coverage for orders and customers. |
| procountor-fi | Ledger. Supports bills, invoices, journal entries, invoice items, customers, suppliers, and purchase orders. Payments, tax rates, and ledger accounts are read-only. Attachments, expenses, and credit notes are not in coverage. |
| quickbooks | Ledger. Full write support for bills, expenses, invoices, journal entries, credit notes, customers, suppliers, ledger accounts, tax rates, departments, locations, tracking categories (Classes), purchase orders, and attachments. Use Classes to map project or department tracking. |
| rillet | Ledger. Supports bills, expenses, invoices, journal entries, credit notes, suppliers, customers, and payments. Bill payments have limited support. Ledger accounts, tax rates, and subsidiaries are read-only, so cache them during onboarding. |
| sage-business-cloud-accounting | Ledger. Supports bills, expenses, invoices, credit notes, suppliers, customers, ledger accounts, payments, bill payments, and attachments. Journal entries and invoice items are read-only, so post custom entries through bills, invoices, or expenses. Tax rates and subsidiaries are read-only. |
| sage-intacct | Ledger. Full write support for bills, expenses, invoices, journal entries, credit notes, customers, suppliers, ledger accounts, tracking categories (dimensions), and attachments. Departments, locations, subsidiaries, and tax rates are read-only. Use for multi-entity firm clients. |
| sage-intacct-rest | Ledger. Same resource coverage as `sage-intacct` on the REST transport, plus writable departments, locations, and subsidiaries. Attachments supported. |
| shopify | Source. Standard Ecommerce API coverage for orders, products, and customers. Summarize payouts into a journal entry on the client's ledger. |
| shopify-public-app | Source. Same shape as `shopify`, distributed as a Shopify public app connection. |
| shopware | Source. Standard Ecommerce API coverage for orders. |
| stripe | Source and partial ledger. Invoices, credit notes, customers, tax rates, and invoice items are writable. Payments and expenses are read-only. Treat Stripe primarily as a sales and payout source for a connected ledger. |
| tiktok | Source. Standard Ecommerce API coverage for orders. |
| visma-netvisor | Ledger. Supports bills, invoices, credit notes, suppliers, customers, purchase orders, invoice items, and payments. Journal entries are read-only. Attachments and tracking categories are not in coverage. |
| walmart | Source. Standard Ecommerce API coverage for orders. |
| wave | Ledger. Supports invoices, customers, ledger accounts, and invoice items. Suppliers and tax rates are read-only. Bills, expenses, journal entries, and attachments are not in coverage. Use for clients that only need sales postings. |
| wix | Source. Standard Ecommerce API coverage for orders. |
| woocommerce | Source. Standard Ecommerce API coverage for orders and products. |
| workday | Ledger. Supports bills, expenses, invoices, journal entries, customers, suppliers, purchase orders, ledger accounts, and tax rates for writes. Attachments, bill payments, departments, and subsidiaries are read-only. Tracking categories are not in coverage. |
| xero | Ledger. Full write support for bills, expenses, invoices, journal entries, credit notes, customers, suppliers, ledger accounts, tax rates, payments, and bill payments. Attachments and tracking categories are read-only; create new tracking dimensions in Xero itself and then cache them. |
| yuki | Ledger. Supports invoices, journal entries, suppliers, and tracking categories for writes. Bills, ledger accounts, and attachments are read-only. Expenses, customers, credit notes, and bill payments are not in coverage. |
| zoho-books | Ledger. Full write support for bills, expenses, invoices, journal entries, credit notes, customers, suppliers, ledger accounts, tax rates, payments, and bill payments. Attachments are read-only. Tracking categories are not in coverage; use ledger-account structure for categorization instead. |

### QuickBooks and Intuit Enterprise Suite

Both expose Classes as the unified `tracking-categories` resource. For multi-entity firms, Intuit Enterprise Suite also writes Departments and Locations through the unified model, which QuickBooks Online does not surface the same way.

### NetSuite

Multi-subsidiary postings need the header `subsidiary.id` on bills, invoices, and journal entries; bill and invoice lines also accept `subsidiary_id`. Pull the list with [`GET /accounting/subsidiaries`](/apis/accounting/reference#operation/subsidiariesAll) during onboarding and store the mapping with the rest of the per-client cache.

### Xero and Exact Online

Attachments are read-only through the unified API. Keep the original PDF in your own document store and link to it from the entry so the accountant can click through from the ledger. On Xero, bills and expenses accept the link in `source_document_url`. On Exact Online, put it in the bill's `notes` or the journal entry's `memo`.

### Odoo

Many reference resources (ledger accounts, tax rates, tracking categories, departments, locations, attachments) are read-only. Create the master data in Odoo during onboarding, then read the IDs into your mapping cache before posting bills, expenses, invoices, or journal entries.

## Next steps

- [Handling Bills and Expenses for NetSuite, QuickBooks, Xero, and Exact Online](/guides/expenses-bills)
- [Mark Invoices and Bills as Paid](/guides/mark-invoices-as-paid)
- [Accounting API reference](/apis/accounting/reference)
- [Ecommerce API reference](/apis/ecommerce/reference)
- [Vault consumers](/apis/vault/reference#tag/Consumers)
