A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Wave API is how an app or AI agent works with a Wave business: creating an invoice, recording a customer, posting an accounting transaction, or reading the chart of accounts. Access is granted through an OAuth bearer token whose scopes follow a resource and operation pattern, like invoice:write, so a token can read or write only the resources it was granted. A query reads and a mutation writes, and Wave can push a signed event to a registered endpoint when something changes, like an invoice being created.
How an app or AI agent connects to Wave determines what it can reach. There is one route for making calls and a separate route for receiving events, and each is governed by the token behind it and the permissions that token carries.
Wave exposes a single GraphQL endpoint at https://gql.waveapps.com/graphql/public. Every operation is a POST to that one URL: a query reads data, a mutation writes it, and the request body names exactly the fields it wants back. A call authenticates with an OAuth bearer token, and the scopes on that token decide which resources it can read or write. Lists are returned as cursor-paginated connections.
Wave POSTs a signed event to an HTTPS endpoint when something happens in a business, like an invoice being created or a payment being received. The receiver verifies the x-wave-signature header, an HMAC-SHA256 of the payload computed with the subscription's signing secret, to confirm the request came from Wave. Webhook delivery requires an active Wave Pro subscription on the business and the matching scope on the OAuth grant.
Wave uses the OAuth 2.0 authorization-code flow. An application redirects a Wave user to grant access, then exchanges the returned code for an access token sent as a bearer token on every request. Access tokens are short-lived (around two hours), and requesting the offline_access scope returns a refresh token for long-term access. This is the method for any application published to other Wave users.
A full access token is generated in the Wave developer portal and grants unrestricted access to the account that created it. It is intended for development and for automating a single owner's own account, not for connecting to other users. Because it carries every permission, a leaked full access token reaches everything in that account.
The Wave API is split into areas an agent can act on, like businesses, customers, invoices, products, the chart of accounts, and accounting transactions. Each area has its own operations, and a write in some areas changes financial records or removes data permanently.
Operations for the authenticated user and the businesses they can reach.
Operations for working with a business's customers.
Operations for working with invoices.
Operations for the products and services a business sells.
Operations for the chart of accounts that bookkeeping posts to.
Operations for accounting transactions in the ledger.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
BusinessesOperations for the authenticated user and the businesses they can reach.3 | ||||||
| POST | query user | Read the authenticated user, the starting point for finding which businesses a token can reach. | read | user:read | Current | |
Read-only. Returns the identity behind the token, not other collaborators. Acts onuser Permission (capability) user:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | query businesses | List the businesses the authenticated user can access, walked with a cursor. | read | business:read | Current | |
Read-only. The usual entry point for mapping a token to the businesses it controls. Acts onbusiness Permission (capability) business:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | query business | Read a single business by id, including its settings and related collections. | read | business:read | Current | |
Read-only. A business id scopes most other queries and mutations. Acts onbusiness Permission (capability) business:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CustomersOperations for working with a business's customers.3 | ||||||
| POST | query customers | List the customers of a business, walked with a cursor. | read | customer:read | Current | |
Read-only. Returns customer contact and billing details. Acts oncustomer Permission (capability) customer:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation customerCreate | Create a customer for a business. | write | customer:write | Current | |
A core write. The mutation returns the new customer, a didSucceed flag, and any inputErrors. Acts oncustomer Permission (capability) customer:writeVersionAvailable since the API’s base version Webhook event customer.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation customerPatch | Update fields on an existing customer. | write | customer:write | Current | |
A write. Only the supplied fields are changed. Acts oncustomer Permission (capability) customer:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
InvoicesOperations for working with invoices.3 | ||||||
| POST | query invoices | List the invoices of a business, walked with a cursor. | read | invoice:read | Current | |
Read-only. Returns invoice status, line items, and amounts. Acts oninvoice Permission (capability) invoice:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation invoiceCreate | Create an invoice for a customer, with line items and amounts. | write | invoice:write | Current | |
A core write. Returns the new invoice, a didSucceed flag, and any inputErrors. Acts oninvoice Permission (capability) invoice:writeVersionAvailable since the API’s base version Webhook event invoice.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation invoiceDelete | Delete an invoice from a business. | write | invoice:write | Current | |
A destructive write. Removes the invoice record. Acts oninvoice Permission (capability) invoice:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Products & servicesOperations for the products and services a business sells.2 | ||||||
| POST | query products | List the products and services a business sells, walked with a cursor. | read | product:read | Current | |
Read-only. Returns product names, prices, and linked income accounts. Acts onproduct Permission (capability) product:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation productCreate | Create a product or service for a business. | write | product:write | Current | |
A core write. The product can then be referenced on invoice line items. Acts onproduct Permission (capability) product:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
AccountsOperations for the chart of accounts that bookkeeping posts to.2 | ||||||
| POST | query accounts | List the chart of accounts for a business, walked with a cursor. | read | account:read | Current | |
Read-only. Accounts are referenced when posting a transaction to the books. Acts onaccount Permission (capability) account:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | query salesTaxes | List the sales taxes configured for a business. | read | sales_tax:read | Current | |
Read-only. Sales taxes are applied to invoice line items. Acts onsales_tax Permission (capability) sales_tax:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
TransactionsOperations for accounting transactions in the ledger.2 | ||||||
| POST | query moneyTransactions | List accounting transactions in a business's ledger, walked with a cursor. | read | transaction:read | Current | |
Read-only. Returns posted ledger entries and the accounts they affect. Acts onmoney_transaction Permission (capability) transaction:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | mutation moneyTransactionCreate | Record an accounting transaction in a business's ledger. | write | transaction:write | Current | |
A core bookkeeping write. Posts a double-entry transaction across accounts; returns a didSucceed flag and any inputErrors. Acts onmoney_transaction Permission (capability) transaction:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Wave can notify an app when something happens in a business, like an invoice being created or a payment being received. It sends a signed event to a registered endpoint, so an integration learns about activity without polling.
| Event | What it signals | Triggered by |
|---|---|---|
invoice.created | An invoice was created in a business. The payload identifies the business and the invoice so an integration can fetch its details. | mutation invoiceCreate |
customer.created | A customer was created in a business. | mutation customerCreate |
merchant.payment_received | A business received a payment from a customer, for example against an outstanding invoice. | In-app only |
Wave is a single GraphQL endpoint, so the size of a request is shaped by the query an agent sends rather than by fixed page sizes, and lists are walked with cursors.
Wave does not publish official per-method rate-limit values, response headers, or Retry-After signaling in its developer documentation. Commonly cited figures from integration guides are around 60 requests per minute per access token and a few thousand per day per application, but these are not officially documented, so an integration should treat them as approximate, back off on an HTTP 429, and avoid bursts.
Lists are returned as GraphQL connections and walked with a cursor. A query asks for a page with a pageSize argument and a page number or an after cursor, and the response carries pageInfo so a caller knows whether more pages remain. Because the response shape is set by the query, an agent fetches only the fields it needs.
There is no fixed page size across the API. The amount returned is shaped by the query an agent writes (the fields and the requested page), so request size is controlled by the caller rather than by a global maximum.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 200 | inputErrors | A mutation ran but its input failed validation. Wave returns the failure inside the response, as an inputErrors array of code, message, and path entries, alongside a didSucceed flag, rather than as a transport error. | Check didSucceed and read inputErrors to find which field failed and why, then correct the input and resend. |
| 200 | errors | A GraphQL-level problem, like an unknown field or a malformed query. Wave returns a top-level errors array with a message and location, and HTTP 200, because the request reached the GraphQL layer. | Read the message and location, fix the query, and resend. |
| 401 | unauthenticated | No valid token was provided, or the access token has expired (tokens last around two hours). | Refresh the access token using the refresh token, or run the OAuth flow again, then retry. |
| 403 | forbidden | The token is valid but lacks the scope the operation needs, or the business does not have the subscription a feature requires. | Request the matching scope in the OAuth grant, or confirm the business has the required Wave Pro subscription, then retry. |
| 429 | rate_limited | Too many requests arrived too quickly for the token or the application. | Back off and retry with exponential backoff, and smooth the request rate. |
Wave's GraphQL API carries no dated version string in the request. It evolves continuously, with changes communicated through the developer documentation and field-level deprecation notices in the schema.
Wave's GraphQL API carries no dated version string in the request. The schema evolves continuously, and changes are communicated through the developer documentation and field-level deprecation notices in the schema rather than by minting a new version.
From this date, a business connected through a third-party OAuth integration must maintain an active Wave Pro subscription, and webhook delivery requires it as well.
Track schema deprecation notices and the developer documentation for changes.
Wave developer documentation ↗Bollard AI sits between a team's AI agents and Wave. Grant each agent exactly the access it needs, read or write, resource by resource, and every call is checked and logged.