ml-connector
Wave AccountingAsana

Wave Accounting and Asana integration

Wave Accounting runs invoicing and bookkeeping for a small business. Asana runs the work that surrounds those invoices: reviews, approvals, and collections follow-up. Connecting the two means an invoice created in Wave Accounting becomes an Asana task with its key figures attached, and the approval or send action that happens in Asana flows back to Wave. ml-connector handles a GraphQL API on one side and a REST API on the other, moving records by webhook or on a schedule, with the financial values carried in Asana custom fields you map once.

How Wave Accounting works

Wave Accounting exposes customers, invoices, products, chart of accounts, and money transactions through a single GraphQL endpoint at gql.waveapps.com/graphql/public, where reads are queries and writes are mutations. Authentication is OAuth 2.0 authorization code only, with access tokens that expire in about two hours and refresh tokens via the offline_access scope. Every operation is scoped to a business id that must be fetched first, and the connected business needs an active Wave Pro plan for third-party access. Wave pushes invoice, customer, and transaction events by webhook, signed HMAC-SHA256 with a timestamp in the x-wave-signature header. There is no purchase order or AP bill object, and GraphQL errors arrive with an HTTP 200, so the errors array must be checked.

How Asana works

Asana exposes tasks, projects, portfolios, users, teams, goals, and custom fields through its REST API at app.asana.com/api/1.0, using a Personal Access Token or OAuth 2.0 bearer token. It has no native invoice, payment, or GL account objects, so financial data is carried in customer-defined custom fields on tasks and projects. Asana sends push webhooks signed with HMAC-SHA256 keyed on a secret exchanged during a handshake, and those webhooks silently auto-delete after 24 hours of failed delivery or missed heartbeats. Responses return only sparse fields unless opt_fields is passed, so the connector requests the fields it needs explicitly.

What moves between them

The main flow runs from Wave Accounting into Asana. ml-connector reads new, sent, and overdue invoices and creates or updates an Asana task for each one, writing the invoice number, customer name, amount due, and due date into mapped Asana custom fields. Wave customers move the same direction so a person or follow-up owner in Asana can be tied to the right account. Task completion and custom field changes flow back from Asana into Wave, where a completed approval task can trigger the invoice approve or send mutation. The Wave chart of accounts and money transactions stay in Wave and are not written from Asana.

How ml-connector handles it

ml-connector stores both credential sets encrypted, refreshes the Wave access token before its roughly two-hour expiry rather than waiting for a 401, and resolves the Wave business id once through the businesses query because every later call needs it. Because Asana has no finance objects, each invoice is represented as a task and its figures land in custom fields that you map once; custom fields are resolved by GID, not name, since names can be renamed. On the Asana side ml-connector registers a webhook, completes the X-Hook-Secret handshake, verifies the HMAC-SHA256 signature on every event, and re-registers automatically because Asana deletes webhooks after 24 hours of failures. On the Wave side it verifies the x-wave-signature header, rebuilds the signed string as timestamp dot raw body, and rejects events older than five minutes; a scheduled poll with offset pagination backs up anything a webhook missed. Wave invoices have no patch mutation, so updates create, approve, send, or delete rather than edit fields, and because GraphQL errors come back with HTTP 200 the connector checks the errors array, not just the status. Both sides return rate-limit errors, so requests back off and retry, and every record carries a full audit trail and can be replayed if a call fails.

A real-world example

A ten-person creative agency runs Wave Accounting for client invoicing and bookkeeping and runs Asana to coordinate client work across designers and account managers. Before the integration, every invoice raised in Wave was copied by hand into an Asana task so an account manager could confirm the work was delivered before it went out, and overdue invoices were tracked on a spreadsheet that nobody kept current. With Wave Accounting and Asana connected, each new invoice becomes an Asana task automatically with its amount due and due date in custom fields, marking the review task complete sends the invoice from Wave, and overdue invoices raise their own follow-up tasks. The duplicate entry is gone and nothing slips past the due date unnoticed.

What you can do

  • Create or update an Asana task for each new, sent, or overdue Wave invoice.
  • Write Wave invoice numbers, customer names, amounts due, and due dates into mapped Asana custom fields by GID.
  • Approve or send a Wave invoice when its matching Asana review task is completed.
  • Keep Wave customers aligned with the follow-up owners and people in your Asana workspace.
  • Bridge Wave OAuth tokens with an Asana token and resolve the Wave business id once, with retries and a full audit trail on every record.

Questions

How does the integration handle the fact that Asana has no invoice or payment objects?
Asana has no native finance objects, so ml-connector represents each Wave Accounting invoice as an Asana task. The financial values, such as invoice number, amount due, and due date, are written into Asana custom fields that you map once during setup. Those custom fields are matched by GID rather than name, because Asana lets field names be renamed.
Which direction does data move between Wave Accounting and Asana?
The main flow is Wave into Asana, where invoices and customers create or update Asana tasks and carry their figures into custom fields. Task completion flows back from Asana so a finished review can trigger the approve or send action on the matching Wave invoice. The Wave chart of accounts and money transactions stay in Wave and are not written from Asana.
Does it use webhooks or polling to detect changes?
Both, on both sides. Wave sends signed webhooks for invoice and customer events, verified by rebuilding the HMAC-SHA256 signature from the timestamp and raw body in the x-wave-signature header and rejecting anything older than five minutes. Asana sends its own signed push webhooks, and because Asana auto-deletes a webhook after repeated delivery failures, ml-connector re-registers it and also runs a scheduled poll to back up any event that was missed.

Related integrations

Connect Wave Accounting and Asana

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

Get started