ml-connector
Wave AccountingBasware

Wave Accounting and Basware integration

Wave Accounting keeps the books, the vendor list, and the chart of accounts for a small business. Basware receives, codes, matches, and approves vendor invoices through a full AP automation workflow. Connecting the two lets Basware code invoices against the same accounts and suppliers Wave already uses, and lets the approved invoices flow back into Wave as journal entries without re-keying. ml-connector handles the different APIs on each side and moves the data on a schedule you control. Because Wave has no structured accounts-payable or purchase-order workflow, the heavy invoice processing stays in Basware and only the finished accounting result lands in Wave.

How Wave Accounting works

Wave Accounting exposes customers, vendors, invoices, products, chart-of-accounts records, and money transactions through a single GraphQL endpoint at gql.waveapps.com, where reads are queries and writes are mutations. It authenticates with a 3-legged OAuth2 authorization-code token that expires in about two hours, refreshed with the offline_access scope, and every call is scoped to a businessId fetched right after authorization. List queries use offset-based pagination with page and pageSize. Wave can push invoice, customer, transaction, and product events by webhook signed with HMAC-SHA256 in an x-wave-signature header. Wave has no purchase order, structured bill, or standalone payment object, and the connected business must hold an active Wave Pro subscription for third-party access.

How Basware works

Basware exposes coded vendor invoices as accounting documents, plus purchase orders, requisitions, and contracts, through a regional REST P2P API under a region-specific base URL for EU, US, AU, or CA. It authenticates with an OAuth2 client-credentials token, requested with HTTP Basic credentials and valid for about one hour with no refresh token. Master data such as vendors, GL accounts, and accounting dimensions is loaded through dedicated import endpoints, and list reads page with a continuation token passed in a request header. Basware pushes AccountingDocuments and export-ready events by webhook signed with HMAC-SHA256 in an X-BWAPI-Signature-256 header, and payment confirmation flows back into Basware rather than out of it. API credentials are provisioned by a Basware consultant, not self-served.

What moves between them

Master data moves from Wave Accounting into Basware: the vendor list and the chart of accounts are imported so Basware can code invoices to suppliers and GL accounts that already exist in Wave. Coded vendor invoices move the other way, from Basware into Wave: once an accounting document is coded and approved, ml-connector reads it and posts it into Wave as a money transaction against the matching accounts. Accounting documents are read on the AccountingDocuments push notification and a scheduled poll backfills anything missed, while vendor and account imports run on the cadence you set. After each entry posts in Wave, ml-connector acknowledges the transfer back to Basware so the document is marked as moved to the ERP.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the Wave side it runs the OAuth2 authorization-code grant, refreshes the roughly two-hour token before it expires using the offline_access scope, and fetches the businessId once so every query and mutation is scoped to it. On the Basware side it requests a client-credentials token with HTTP Basic auth against the region-specific base URL for the customer's instance, and renews it after about an hour since there is no refresh token. Vendors and accounts are pushed into Basware first through the master-data import endpoints, so every invoice codes to a supplier and GL account that exists in Wave. When Basware sends an AccountingDocuments notification, ml-connector verifies the X-BWAPI-Signature-256 HMAC over the raw UTF-8 body, reads the coded document, paging with the continuation-token header, and posts it into Wave with the moneyTransactionCreate mutation. That mutation carries an externalId set to a stable id like basware-invoice plus the document id, which dedupes against a re-read document and a BullMQ jobId, so an invoice is never booked twice. GraphQL errors come back with HTTP 200, so the errors array is checked on every Wave call, not just the status code. Basware silently skips master data that is identical to the last import, so a field must change to retrigger it, and once an entry lands in Wave the transfer is acknowledged back to Basware. Every record carries a full audit trail and can be replayed if a downstream call fails.

A real-world example

A growing professional-services firm of about forty people runs its books in Wave Accounting and has outgrown emailing PDF supplier invoices around for approval. It adopts Basware to receive, code, match, and approve those invoices through a controlled workflow. Before the integration, an accountant re-typed every approved invoice from Basware into Wave by hand and kept a second copy of the vendor list and the account codes in sync between the two systems, which drifted and produced mis-coded entries. With Wave Accounting and Basware connected, the vendor list and chart of accounts are imported into Basware automatically, and each approved invoice posts back into Wave as a journal entry on the correct account. The duplicate data-entry step is gone and the books reflect approved spend without manual transcription.

What you can do

  • Import the Wave Accounting vendor list and chart of accounts into Basware so invoices code to real suppliers and accounts.
  • Post coded and approved Basware accounting documents into Wave as money transactions against the matching GL accounts.
  • Trigger on the Basware AccountingDocuments webhook and backfill with a scheduled poll so nothing is missed.
  • Bridge Wave's authorization-code OAuth2 token and Basware's region-specific client-credentials token, with proactive renewal on both sides.
  • Dedupe with an externalId and BullMQ jobId, acknowledge each transfer back to Basware, and keep a full audit trail on every record.

Questions

Which direction does data move between Wave Accounting and Basware?
Both directions, but for different records. The vendor list and chart of accounts move from Wave Accounting into Basware as master data so invoices can be coded correctly. Coded and approved accounting documents move from Basware into Wave, where ml-connector posts them as money transactions against the matching GL accounts.
Why does invoice processing stay in Basware instead of Wave?
Wave has no purchase-order object and no structured accounts-payable or bill workflow in its GraphQL API, so it cannot receive, code, match, or approve supplier invoices. Basware is built for exactly that lifecycle. ml-connector keeps the heavy AP processing in Basware and posts only the finished accounting result into Wave as a journal entry.
How does the integration handle the two different logins and Basware regions?
Wave uses a 3-legged OAuth2 authorization-code token that lasts about two hours and is refreshed with the offline_access scope, while Basware uses a client-credentials token requested with HTTP Basic auth that lasts about an hour with no refresh. ml-connector renews each before it expires and targets the region-specific Basware base URL for the customer's EU, US, AU, or CA instance. Basware credentials are provisioned by a Basware consultant, so they are entered into the connector config rather than self-served.

Related integrations

Connect Wave Accounting and Basware

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started