ml-connector
VismaStripe

Visma and Stripe integration

Visma.net ERP holds your customer accounts and invoice records. Stripe processes payments and manages the payment lifecycle. Connecting the two streamlines AR by removing manual invoice entry into Stripe, and ensures Visma's AR ledger reflects the actual payment status of each invoice. New invoices in Visma flow to Stripe for collection, payment confirmations and disputes flow back into Visma, and Stripe charges are reconciled against the invoice register without re-keying.

How Visma works

Visma.net ERP exposes customers, invoices, accounts, dimensions, and transaction journals through REST APIs over HTTPS. Authentication uses OAuth2 client credentials against Visma Connect, with tenant_id and company_id headers required on all calls. Visma supports both webhooks for real-time notification and polling via lastModifiedDateTime on list endpoints, though webhook delivery is one-time only with no automatic retry. Older implementations may use the deprecated integration.visma.net API endpoint instead of the canonical api.finance.visma.net base URL.

How Stripe works

Stripe exposes payments, charges, invoices, customers, and payment methods through REST APIs secured with API Key authentication sent via HTTP Basic Auth or Bearer token. Stripe sends real-time webhook events including charge., invoice., and dispute. notifications to a registered HTTPS endpoint with at-least-once delivery and automatic retry for up to 3 days. Stripe API does not support bulk updates or traditional PUT operations; updates use POST to the resource URL. Stripe is a payment processor, not an ERP; it has no vendors, purchase orders, GL accounts, employees, or general ledger capabilities.

What moves between them

Customer invoices flow from Visma to Stripe on a schedule or on-demand when marked for payment processing. Stripe's charge.completed, charge.failed, and dispute.created events flow back into Visma to update the payment status and disputed flag on the corresponding customer invoice. Dispute notifications include the dispute reason and amount so Visma accounting can tag and investigate. The sync is primarily one-directional (Visma to Stripe), with Stripe events feeding back into Visma's AR state only, not modifying Stripe data.

How ml-connector handles it

ml-connector stores both the Visma OAuth2 credentials (client_id, client_secret, tenant_id, company_id) and the Stripe API key encrypted, and refreshes the Visma bearer token when a call returns 401. On the Visma side, it polls for invoices modified since the last sync using the lastModifiedDateTime query parameter, then maps each invoice to a Stripe customer by matching Visma customer name to Stripe customer description or custom field. Invoice amounts, tax, and due dates are sent to Stripe, and ml-connector tracks the returned Stripe invoice_id for lookup on payment events. On the Stripe side, ml-connector registers a webhook endpoint that receives charge and dispute events, validates the Stripe-Signature header (HMAC-SHA256), and writes payment status and dispute details back into Visma's customer invoice record using optimistic locking via ETag. Stripe webhook delivery is guaranteed at least once, so ml-connector uses the idempotency key pattern to detect and skip duplicates. Because Stripe issues new bearer tokens on every call and Visma refresh tokens are not issued to service applications, ml-connector obtains a fresh Visma token on every token expiry rather than storing a refresh token.

A real-world example

A Nordic B2B software company uses Visma.net ERP to manage customer accounts and issue invoices, and Stripe to collect payments online and via invoice. Before the integration, the AR team exported new invoices from Visma every few days, manually entered them into Stripe for payment processing, and then re-entered Stripe payment receipts back into Visma to update invoice status. This manual process was slow, error-prone, and created a one- to two-day lag between payment in Stripe and AR reconciliation in Visma. With Visma and Stripe connected, new invoices appear in Stripe immediately, payment confirmations and disputes post to Visma's AR ledger automatically, and invoice payment status is always current. Month-end AR reconciliation now takes minutes instead of hours.

What you can do

  • Push Visma customer invoices to Stripe for payment collection without manual entry, using invoice amount, tax, and due date.
  • Receive Stripe charge.completed and charge.failed webhook events and post payment confirmations to the corresponding Visma invoice.
  • Capture Stripe disputes and post dispute reason and amount to Visma for tracking and investigation.
  • Authenticate Visma with OAuth2 client credentials and Stripe with API Key, validating Stripe webhook signatures on every event.
  • Poll Visma at regular intervals for new and modified invoices, with webhook event processing and full audit trail on every sync.

Questions

Why is Stripe marked as read-mostly if ml-connector posts invoice data to it?
Stripe's primary role in this integration is payment processing and webhook generation. While ml-connector does write invoices to Stripe for collection, Stripe itself does not write back to Visma's AR data in a way that changes invoice terms or amounts. Disputes and charge events write to Visma, not the other way around. Stripe charges and payment intents are read by ml-connector to match against invoices but are never modified.
Does the integration handle currency differences between Visma and Stripe?
Both Visma and Stripe support multi-currency invoices, but the currency code must match when syncing. ml-connector copies the invoice currency from Visma to Stripe and validates that both sides accept the same currency code before posting. If a currency code is unsupported on the Stripe side, the sync is blocked and logged for manual review.
How does the integration handle the fact that Stripe webhook delivery is not ordered?
Because Stripe events can arrive out of order, ml-connector always re-fetches the charge or dispute details from the Stripe API before writing to Visma, using the event webhook only as a notification trigger. This ensures Visma receives the final state of the charge or dispute, not an intermediate state, even if events arrive out of sequence.

Related integrations

Connect Visma and Stripe

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

Get started