ml-connector
Wave AccountingLooker

Wave Accounting and Looker integration

Wave Accounting holds your invoicing, expenses, and chart of accounts. Looker turns raw warehouse data into business intelligence and reports. Connecting Wave to Looker ensures your accounting data reaches your analytics warehouse without manual export or transform steps. Invoice and transaction records flow automatically on a schedule you control, keeping your financial dashboards current and accurate.

How Wave Accounting works

Wave Accounting exposes invoices, customers, transactions, vendors, products, and accounts through a GraphQL API at https://gql.waveapps.com/graphql/public. Wave requires OAuth2 with access tokens that expire after 2 hours, using a refresh token flow with offline_access scope. Wave Pro subscription is required for third-party API access. Wave webhooks fire for invoice.created, invoice.updated, invoice.paid, payment.created, customer.created, customer.updated, transaction.created, product.created, and product.updated events. Webhook events carry HMAC-SHA256 signatures that must be verified against the x-wave-signature header. Wave retries failed deliveries and expects HTTP 200 for successful receipt or HTTP 500 to trigger a retry. Note that Wave invoices are created, approved, sent, or deleted - there is no patch operation - and bills and accounts payable are not exposed via the API.

How Looker works

Looker is deployed at https://<instance>.cloud.looker.com/api/4.0/ or https://<instance>.looker.com:19999/api/4.0/ depending on deployment date. Looker authenticates via OAuth2 client credentials, exchanging client_id and client_secret for a bearer token that expires after 1 hour with no refresh endpoint. Access control is role and permission-set based, not scope-based. Looker Scheduled Plans deliver data on a cron schedule to webhook, email, S3, or SFTP destinations, though no inbound webhooks or real-time change events exist. REST API queries return up to 5000 rows per call and can be streamed for larger datasets. Looker does not natively store ERP data and has no native write path to financial records - it models and exposes warehouse data only.

What moves between them

Wave Accounting events flow into Looker at regular intervals or immediately on webhook. Invoice.created, invoice.updated, and invoice.paid events are transformed into dimensional tables mapping invoices to customers and accounts. Transaction records flow the same way so expense and revenue detail populates your financial fact tables. Customer and product updates keep dimension tables fresh. The flow is one-way from Wave into Looker because Looker has no write capability to financial data. Wave webhooks provide near-real-time notification, but since Looker requires OAuth2 refresh on each query and has a 1-hour token window, data loads are scheduled at fixed intervals to batch requests and avoid repeated authentication.

How ml-connector handles it

ml-connector stores Wave and Looker OAuth credentials encrypted and manages token refresh for both systems - Wave's 2-hour access tokens using refresh tokens, and Looker's 1-hour tokens by re-authenticating on expiry. It listens for Wave webhooks and validates each signature against the x-wave-signature HMAC-SHA256 header with a 5-minute replay window. On receipt, the integration transforms Wave's GraphQL invoice, transaction, and customer objects into the dimensional structure your Looker models define - mapping invoice line items to GL accounts and customers, joining transactions to vendors and products. Because Looker Scheduled Plans run on fixed cron cadences rather than real-time ingestion, ml-connector batches webhook events and loads them together at your chosen sync window, typically after business hours or at the close of each business day. Wave's lack of a patch operation means new invoice versions arrive as separate created and updated events - ml-connector deduplicates these by invoice ID. Rate limits are handled with exponential backoff. Every record carries an audit trail showing its Wave origin, transformation step, and load timestamp in Looker.

A real-world example

A services firm uses Wave Accounting for invoicing and expense tracking and Looker to power weekly financial dashboards for leadership. Before the integration, the accountant exported invoices from Wave once a day and wrote SQL to load them into the warehouse model. With Wave and Looker connected, each invoice automatically flows into the Looker warehouse on a schedule tied to daily reconciliation. The invoice dashboard reflects the latest sent and paid invoices within minutes, and the weekly revenue and expense reports run without manual prep work. The firm cuts invoice-to-dashboard latency from hours to minutes and eliminates the daily export step entirely.

What you can do

  • Load Wave invoices, customers, and transactions into your Looker warehouse models on a schedule you control.
  • Verify Wave webhook signatures with HMAC-SHA256 and accept invoice.created, invoice.updated, invoice.paid, and transaction.created events in real time.
  • Map Wave invoice line items to your Looker GL account and customer dimensions for consistent financial analysis.
  • Authenticate Wave with OAuth2 refresh tokens and Looker with OAuth2 client credentials, managing token expiry and re-authentication automatically.
  • Audit every record from Wave into Looker with timestamps and transformation details for compliance and troubleshooting.

Questions

Does Looker receive real-time invoice updates from Wave or are they batched on a schedule?
Wave webhooks notify ml-connector immediately when invoices are created, updated, or paid. However, since Looker tokens expire after 1 hour and have no refresh endpoint, ml-connector batches these events and loads them into Looker on a fixed cron schedule - typically daily after hours - rather than on each webhook. This approach minimizes authentication overhead and aligns with typical financial reporting cadences.
Can Wave bills and purchase orders sync to Looker?
No. Wave Accounting's API does not expose bills or accounts payable - only invoices issued, customer payments, expenses, and transactions. Purchase orders are not a Wave feature. The integration covers invoices, customers, products, and the chart of accounts only.
How does the integration handle Wave's invoice versioning and the lack of a patch operation?
Wave invoices are created, approved, sent, or deleted - there is no update field. When an invoice changes, Wave sends both an invoice.updated webhook and a new complete record. ml-connector deduplicates by Wave invoice ID and replaces the prior version in Looker with the latest, so your warehouse always reflects the current invoice state without duplicates.

Related integrations

Connect Wave Accounting and Looker

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

Get started