ml-connector
VismaGoogle BigQuery

Visma and Google BigQuery integration

Visma runs your accounting across AP/AR, purchasing, and the general ledger. Google BigQuery is where you analyze that financial data at scale. Moving records from Visma into BigQuery lets you build month-end close reports, cash flow forecasts, and compliance archives without manual exports and re-imports. ml-connector handles the different authentication models on each side and keeps your data warehouse synchronized on a schedule you control.

How Visma works

Visma.net ERP exposes suppliers, supplier invoices, purchase orders, purchase receipts, payments, customers, customer invoices, GL accounts, dimensions, journal transactions, and employees through REST JSON APIs at https://api.finance.visma.net. All API calls require OAuth 2.0 authentication via Visma Connect using client_credentials flow, along with a company ID header. Visma offers both webhook notifications (sent once, with no automatic retry) and polling via delta queries on the lastModifiedDateTime parameter. Older deprecated endpoints are at https://integration.visma.net/API/controller/api/v1/. All mutations require ETag/If-Match headers for optimistic locking. Visma test clients are rate-limited to 500 calls per hour per company.

How Google BigQuery works

Google BigQuery is a serverless cloud data warehouse accessible via REST APIs at https://bigquery.googleapis.com/bigquery/v2. Authentication uses OAuth 2.0 with a Google Cloud service account; you provide a private key that ml-connector exchanges for a 3600-second bearer token via JWT flow. Data goes into tables you define within datasets you own. BigQuery has no outbound webhooks or event subscriptions, so ml-connector polls by querying timestamp columns or _PARTITIONTIME. Streaming inserts use best-effort deduplication with insertId. Storage Read API is available for large-volume reads. Service accounts require bigquery.dataEditor and bigquery.jobUser roles at minimum.

What moves between them

The main flow runs from Visma into BigQuery. ml-connector polls Visma on a monthly cycle aligned to your close, pulling all new and modified supplier invoices, purchase orders, purchase receipts, customer invoices, GL transactions, and employee records since the last run. Each batch is streamed into separate BigQuery tables (one per entity type) with deduplication keys so re-runs do not duplicate rows. Reference data such as GL accounts, suppliers, and customers flows the same direction to keep your warehouse dimension tables fresh. All data moves read-only from Visma into BigQuery; no writes flow back to Visma from the warehouse.

How ml-connector handles it

ml-connector stores your Visma OAuth credentials and BigQuery service account key encrypted and obtains a fresh Visma token at the start of each poll cycle via the client_credentials grant, passing the required company ID header on every list call. It queries Visma's lastModifiedDateTime parameter to pull only records changed since the previous run, reducing API volume and billing on both sides. For BigQuery, ml-connector retrieves the service account key from your project, signs a JWT with it, and exchanges the JWT for a bearer token valid for one hour; tokens are refreshed automatically on expiry. Each Visma entity (SupplierInvoice, PurchaseOrder, etc.) maps to a separate BigQuery table, and ml-connector includes a deduplication key on insert so a retry does not create duplicate rows. Rate limits on the Visma test environment (500 calls per hour) are observed; Visma webhooks are not used because they offer no automatic retry and Visma requires poll-based delta sync for high-volume data. Every record carries a timestamp and audit ID so you can trace where each row came from and when, and failed batches can be re-run against a checkpoint.

A real-world example

A mid-sized Nordic manufacturing company uses Visma.net ERP for AP, AR, and general ledger across three operations. The finance team needs to close the books by the 5th of each month, but payables and sales data arrive throughout the month and have historically required manual exports and spreadsheet reconciliation. With Visma and BigQuery connected, the month-end close workflow starts automatically on the 3rd of the month: invoices, POs, and GL transactions flow into BigQuery tables overnight, a set of SQL queries in BigQuery calculate days payable outstanding, days sales outstanding, and cash position by cost center, and the close team has validated reports ready by 8 AM on the 1st, eliminating three days of manual data assembly.

What you can do

  • Stream all Visma supplier invoices, purchase orders, and purchase receipts into BigQuery tables with automatic deduplication.
  • Sync Visma GL accounts, dimensions, and chart-of-accounts changes into BigQuery to keep your warehouse dimensions current.
  • Pull Visma customer invoices and credit notes into BigQuery to support revenue and AR analytics without manual export.
  • Authenticate Visma via OAuth 2.0 client credentials and BigQuery via service account JWT, refreshing tokens on expiry.
  • Poll Visma on a monthly or weekly cadence using lastModifiedDateTime delta queries, with a full audit trail and replay capability on any failed batch.

Questions

Why poll Visma instead of using Visma webhooks?
Visma webhooks are sent once only with no automatic retry mechanism, so if ml-connector is down during a webhook window, the notification is lost and data consistency is broken. Polling with lastModifiedDateTime ensures no records are skipped and allows you to restart a failed sync from a checkpoint.
How does ml-connector handle Visma's ETag requirement and optimistic locking?
ml-connector does not write back to Visma, so ETag validation is not required on the Visma side. However, the read operations respect Visma's API contract and are tested against live Visma instances, so any future write capability (for example, payment posting) would honor If-Match semantics.
What happens if BigQuery access tokens or Visma OAuth tokens expire mid-sync?
ml-connector tracks token expiry before each API call. If a Visma token approaches expiry, a new one is obtained via client_credentials grant at the start of the next poll cycle. BigQuery tokens are refreshed automatically when they reach one hour; if an insert fails due to token expiry during a large batch, the batch is replayed from the last checkpoint.

Related integrations

Connect Visma and Google BigQuery

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

Get started