Batch & IntegrationsAccounting Connections

Accounting Connections

Connect an accounting platform via OAuth2 to deliver converted files or post accounting transactions — with an honest statement of what platforms allow.

What connections do — honestly

/v1/connections links transmute to your accounting platform so batch results are delivered there on completion: the generated CSV/OFX/XML file lands in the platform's file library for one-click import by a user.

The honest scope: no accounting platform exposes a public API that writes bank statement lines directly. Delivery-to-file-library is what their public APIs actually permit, and transmute never claims otherwise.

PlatformFile deliveryPosting transactions (opt-in, when enabled for your account)
XeroAutomatic — file lands in the Xero file library via its Files APIBankTransaction (SPEND / RECEIVE)
QuickBooks OnlineManual import runbook — we generate the right file, you import itDeposit / Purchase
SageManual import runbook — samebank_transaction (OTHER_RECEIPT / OTHER_PAYMENT)

Posting is a different capability from file delivery: a posted transaction is an accounting entry, not a bank statement line, and your platform's own reconciliation still matches it. transmute posts what your mapping says — it does not reconcile, match contacts or compute tax.

Set up a connection (Xero)

Requires the opt-in connections:manage scope:

curl -sS -X POST https://api.transmute.403fin.io/v1/connections \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"provider": "xero"}'
# → {"id": "...", "authorizeUrl": "https://login.xero.com/..."}

Open authorizeUrl in a browser and approve access; the OAuth callback completes the connection. Then reference the connection when enqueuing a batch job with a file target (to: "csv", "ofx", ...), and each result file is pushed on completion.

GET /v1/connections lists connections; DELETE /v1/connections/{id} disconnects (revoking our access).

Post transactions into your books

Posting needs three things, in order. It is available once posting is enabled for your account.

  1. A connection granted with posting. For Xero, reconnect with the posting permission; QuickBooks Online and Sage connect for posting only:
curl -sS -X POST https://api.transmute.403fin.io/v1/connections \
  -H "Authorization: Bearer $TRANSMUTE_KEY" -H "Content-Type: application/json" \
  -d '{"provider": "xero", "capabilities": ["post"], "replaces": "conn_..."}'

A new connection is created; the replaced one is revoked once you approve. transmute uses the permissions the platform says it granted — a file-delivery connection can never post (connection-reconsent-required).

  1. A ledger mapping per bank account (connections:manage): pick the bank account and the money-in / money-out accounts from GET /v1/connections/{id}/accounts (fetched live, never stored), then PUT /v1/connections/{id}/mappings. Optional rules — "if the memo contains rent, book to 469" — are typed by you and must carry "source": "user"; transmute never suggests or learns rules from your messages.

  2. A preview (transactions:post): POST /v1/connections/{id}/transactions/dry-run shows the account each transaction books to and the exact object that would be sent, and posts nothing. A preview is required before the first post and after every mapping edit (dry-run-required).

Then post with POST /v1/connections/{id}/transactions — or convert to the accounting-transaction target in a batch with "delivery": {"connection": "conn_...", "deliverAs": "transactions"}. Each transaction gets a stable reference (for statement lines, the same reference an OFX export would carry), and transmute records it before sending, so re-sending the same statement never double-books. If the platform does not answer clearly, the result is unconfirmed and the next attempt reads the transaction back before deciding to resend. Each plan has a monthly post allowance (post-quota-exceeded).

A correct-but-wrong mapping cannot be detected by us — we post exactly what the mapping says. Review the preview.

Failure modes

  • connection-failed 422 — the connection is broken (revoked/expired authorization). Re-connect.
  • provider-error 502 — the platform's API failed on delivery. Retryable; the file remains fetchable via GET /v1/jobs/{id} for the job TTL.

Privacy

Posting keeps only a record per transaction: a SHA-256 key, a status, the platform's transaction id and timestamps — never the transaction itself, never the chart of accounts, never a platform error body. Records expire after 45 days and are deleted when you disconnect.

Delivery is payload transit at your explicit instruction — it extends no retention (the normal batch TTL and purge apply unchanged). Provider tokens are stored encrypted (AES-256-GCM), never appear in any response or log, and delivery errors never echo provider payloads.