ml-connector
Wave AccountingStripe

Wave Accounting and Stripe integration

Wave Accounting handles your accounting, invoicing, and expense tracking. Stripe handles online payments, subscriptions, and billing. Connecting the two means a customer created or updated in Wave flows into Stripe automatically, and each Wave invoice can be turned into a Stripe invoice so payments are tracked in both systems. Your finance team no longer re-enters invoice data, and reconciliation between Wave and Stripe stays clean.

How Wave Accounting works

Wave Accounting exposes customers, invoices, products, accounts, and transactions through a GraphQL API at https://gql.waveapps.com/graphql/public. Access requires OAuth 2.0 Authorization Code Flow with a Wave Pro subscription (as of May 2026) and access tokens that expire every 2 hours. Wave sends webhooks for invoice creation, updates, payment events, and customer changes, and expects HTTP 200 to confirm receipt (500 to retry). Webhook signatures use HMAC-SHA256 in the x-wave-signature header with a 5-minute replay window. Bills, purchase orders, and payroll are not accessible via the GraphQL API.

How Stripe works

Stripe exposes customers, invoices, charges, payment intents, subscriptions, and products through a REST API at https://api.stripe.com/v1. Requests use API Key (Secret key sk_live_ for production) sent via HTTP Basic Auth or Bearer token. Stripe sends webhooks for payment, invoice, customer, and subscription events with HMAC-SHA256 signatures in the Stripe-Signature header, at-least-once delivery, and retries up to 3 days. Prices are immutable after creation; updates to customers and invoices use POST not PUT/PATCH. Stripe has no vendors, POs, GL accounts, or employees.

What moves between them

Wave customers and invoices flow into Stripe one-way. When a customer is created or updated in Wave (or via webhook), ml-connector creates or updates the matching Stripe customer. When a Wave invoice is created, ml-connector builds a Stripe invoice with line items pulled from the Wave invoice and creates it in Stripe. Payment events from both systems are logged but Wave is the source of truth for invoice and customer attributes. The flow is asynchronous and decoupled: Wave changes are read either through webhooks or polling, transformed into Stripe API operations, and queued for execution.

How ml-connector handles it

ml-connector stores Wave OAuth credentials and Stripe API keys encrypted, refreshing the Wave access token whenever it is near expiry (2-hour window). On the Wave side, it listens for webhooks on invoice.created, invoice.updated, customer.created, and customer.updated events, validates signatures using HMAC-SHA256 and the 5-minute replay window, and returns HTTP 200 on success (500 to trigger a retry). It transforms Wave invoice line items into Stripe invoice items, respecting Wave's constraint that invoices cannot be patched (so updates create a new Stripe invoice). On the Stripe side, it uses the API Key for direct REST calls with no polling required. Because Stripe prices are immutable after creation, ml-connector archives old prices rather than updating them. Every record carries a full audit trail and can be replayed if a Stripe call fails (e.g., a customer update that references a non-existent price). Wave requires a connected business to have a Wave Pro subscription, so the integration validates that the OAuth scope includes the required permissions before attempting to fetch invoices or customers.

A real-world example

A small SaaS company uses Wave Accounting for invoicing and expenses and Stripe to accept online payments from customers. Before the integration, the billing team created invoices in Wave, then manually entered those invoices into Stripe for payment collection, leading to duplicates and missed charges when a Wave invoice was not mirrored into Stripe. With Wave and Stripe connected, each Wave customer is instantly available in Stripe and each invoice auto-syncs, so new invoices are ready for payment as soon as they are approved in Wave. The two systems stay in sync, the manual re-entry step is gone, and reconciliation at month-end is straightforward.

What you can do

  • Sync Wave customers to Stripe on create and update, keeping customer profiles aligned across both systems.
  • Create Stripe invoices from Wave invoices with proper line items and tax amounts.
  • Handle Wave OAuth token refresh automatically (2-hour expiry) and Stripe API key authentication.
  • Validate Wave webhook signatures (HMAC-SHA256) and return proper HTTP status codes so Wave retries failed deliveries.
  • Replay failed invoice or customer syncs so transient Stripe API failures do not break the flow.

Questions

Which direction does data move between Wave Accounting and Stripe?
Wave to Stripe one-way. Customers and invoices created or updated in Wave flow into Stripe automatically via webhooks. Stripe payment events are logged but Wave remains the source of truth for invoice and customer attributes. No data moves from Stripe back into Wave.
How does the integration handle Wave's 2-hour OAuth token expiry and Stripe's API key authentication?
ml-connector stores both credential sets encrypted in its database. It monitors the Wave access token and refreshes it before expiry (using the refresh token) so authentication failures are prevented. Stripe API keys are presented directly on each REST request via HTTP Basic Auth, with no expiry to manage.
What happens if Wave requires a Pro subscription or Stripe API calls fail temporarily?
ml-connector validates that the connected Wave business has an active Pro subscription (required as of May 2026) before syncing. If a Stripe call fails, ml-connector queues the operation with the full record state and retries at intervals so manual intervention is not needed. Failed records are visible in the audit log for troubleshooting.

Related integrations

Connect Wave Accounting and Stripe

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

Get started