How to Export Data from Wave: Methods, API Limits & Portability
Complete guide to exporting data from Wave accounting. Covers native exports, Wave Connect, GraphQL API, receipts, and data you can't get out.
Planning a migration?
Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.
Schedule a free call- 1,500+ migrations completed
- Zero downtime guaranteed
- Transparent, fixed pricing
- Project success responsibility
- Post-migration support included
How to Export Data from Wave: Methods, API Limits & Portability
Wave does not give you a single-button full export. You can get most of your accounting data — transactions, invoices, customers, vendors, and receipts — through the built-in Data Export in Settings. But invoice PDFs cannot be exported in bulk, the public GraphQL API does not document a transaction list/read query, and several objects (estimates, recurring invoice templates, automation rules) have no native bulk export path at all.
For most teams, the best approach is Data Export + Wave Connect + targeted API pulls. Non-technical users can self-serve the baseline export in hours. Engineering resources are needed when you want programmatic extraction, attachment harvesting, or migration-grade validation with relational integrity.
This guide covers every extraction method, object by object, with the real limitations, API constraints, and format issues you need to know before starting an export or migration.
TL;DR: Wave's native Data Export gives you four CSV/XLS files (transactions, bill items, customers, vendors) plus receipt images as a ZIP — enough for basic backup or a simple migration. Wave Connect (Google Sheets add-on) adds chart of accounts, products, and invoice line-item downloads. For programmatic extraction, Wave's GraphQL API at gql.waveapps.com/graphql/public covers invoices, customers, products, accounts, estimates, and sales taxes — but requires a Pro or Wave Advisor subscription ($16–$19/mo) and has undocumented rate limits. The biggest gaps: no bulk invoice PDF export, no documented public API query for transaction history, and no way to export recurring templates or automation rules in bulk.
Wave Data Extractability Model: What Can You Export?
Wave is an accounting platform built for freelancers and micro-businesses. Its data model centers on Accounts (chart of accounts), Transactions (journal entries), Invoices, Estimates, Bills, Customers, Vendors, Products/Services, Receipts, Recurring Invoices, and Payroll (US/Canada only). The extractability of each object depends on which method you use. (support.waveapps.com)
| Object | Native Data Export | Wave Connect (Google Sheets) | GraphQL API | Format | Key Limitations |
|---|---|---|---|---|---|
| Transactions / Journal Entries | Yes | Yes | No documented public read query | CSV / XLS | Native export is all-or-nothing — no date filter. Use Account Transactions report for date-range exports. |
| Invoices (data) | Yes | Yes (with line items, tax amounts, payment date, payment method, and status) | Yes (invoices query) |
CSV / XLS / JSON | Native export includes invoice summary data; Wave Connect adds line items and payment details. |
| Invoice PDFs | No (one at a time only) | No | Yes (pdfUrl field) |
No bulk PDF export from UI. API returns a pdfUrl per invoice for programmatic download. |
|
| Estimates | No | No | Yes (estimates query) |
JSON | No native bulk export. Must export individually as PDF from UI, or query via API. |
| Bills / Bill Items | Yes | No | No documented public read query | CSV / XLS | Bill items file included in accounting export. Not available via Wave Connect. |
| Customers | Yes | Yes | Yes (customers query) |
CSV / XLS / JSON | Fully exportable across all methods. |
| Vendors | Yes | No | Yes (limited) | CSV / XLS | Included in accounting export. Not available via Wave Connect. |
| Products / Services | No | Yes | Yes (products query) |
CSV / JSON | Not in native data export. Must use Wave Connect or API. |
| Chart of Accounts | No | Yes | Yes (accounts query) |
CSV / JSON | Not in native data export. Wave Connect or API required. |
| Receipts (images) | Yes (ZIP) | No | No documented query | Original file types | Exported as a ZIP of uploaded receipt images. No metadata linking receipts to transactions. |
| Sales Taxes | No | No | Yes (salesTaxes query) |
JSON | API-only extraction. |
| Recurring Invoice Templates | No | No | No documented query | N/A | Wave's migration guidance says to end and recreate them. (support.waveapps.com) |
| Payroll | Yes (Canada only) | No | No | CSV | Two files: employee profiles and pay stubs. Only available for Canadian payroll customers. |
| Reports (P&L, Balance Sheet) | No | Yes (via Reports feature) | No | CSV / PDF | Reports can be exported individually with date filters from the Wave UI. |
The GraphQL API exposes pdfUrl and viewUrl fields on invoices — the only way to programmatically download invoice PDFs. The public API docs document transaction creation (including a bulk-create beta) but do not document a public transaction list/read query. For transaction history, rely on native Data Export or report exports. (developer.waveapps.com)
If a client asks "can I get all my data out of Wave?" — the honest answer is: you can get all your transactional data out via native export. But invoice PDFs, estimates, product catalogs, and chart of accounts each require a different extraction method. Recurring templates, automation rules, and audit history have no clean bulk export path.
Wave Export Decision Matrix: Every Way to Get Data Out
There are five distinct ways to extract data from Wave. Each covers different objects, has different complexity, and is suited for different scenarios.
| Method | Data Coverage | Volume Limit | Speed | Complexity | Best For |
|---|---|---|---|---|---|
| Native Data Export (Settings) | Transactions, invoices, bills, customers, vendors, receipts, payroll | No documented limit | Minutes (emailed) | Low | Full backup, simple migration |
| Wave Connect (Google Sheets) | Chart of accounts, customers, products, invoices (with line items, tax, payment details), transactions | Google Sheets limits (~10M cells) | Minutes | Low | Filtered exports, product/CoA extraction |
| Report Export | Individual reports (P&L, Balance Sheet, Trial Balance, Account Transactions) | Per-report | Seconds | Low | Date-range transaction exports, compliance snapshots |
| GraphQL API | Invoices, customers, products, accounts, estimates, sales taxes, attachments | Pagination-limited | Variable (rate-limit dependent) | High | Programmatic extraction, invoice PDF download, migration scripts |
| Third-party ETL (Zapier, Make, Truto) | Varies by connector | Varies by plan | Variable | Medium | Ongoing sync, event-driven export |
Decision flow: Native Data Export, Wave Connect, and Report Export require zero engineering — any business owner or admin can run them. The GraphQL API and third-party ETL tools require developer resources. For most teams, the recommended order is: Data Export → Wave Connect → report exports → API only for gaps. (support.waveapps.com)
Native UI Export: Step-by-Step
Wave's built-in data export is the fastest way to get a full snapshot of your accounting data. It produces a ZIP file containing CSV or XLS files, emailed to your account's primary email address.
How to run the export
- Log in at waveapps.com.
- Click your business name (top right) → Business settings.
- Scroll to Other → click Data Export.
- Select the data files you want: Accounting, Receipts, or Payroll.
- Wave sends an email with a download link. The link is active for 24 hours — after that, you must re-export.
What's in each export file
- Accounting export — four separate files:
- Accounting file: All journal entries and transactions
- Bill items file: Bill line-item details
- Customers file: Customer contact profiles
- Vendors file: Vendor and independent contractor profiles
- Receipts export — a ZIP file containing all uploaded receipt images in their original file types (JPEG, PNG, PDF)
- Payroll export (Canadian businesses only) — two CSV files: employee profiles and pay stubs
Permission requirements
Viewer and Editor user roles do not have access to data export. Only Admin or Owner roles can trigger the export. If you're planning a migration and need to delegate the export task, confirm role access first.
Native data export is all-or-nothing. You cannot filter by date range, customer, or account. If you need transactions for a specific period, export an Account Transactions report instead — it supports date-range filtering. The export also does not include your chart of accounts, products/services, estimates, or recurring invoice templates.
What's missing from native export
- Chart of accounts — not included. Use Wave Connect or the API.
- Products/services catalog — not included. Use Wave Connect or the API.
- Invoice PDFs — not included. Individual invoices can only be exported as PDF one at a time from the Invoices page. (support.waveapps.com)
- Estimates — not included in any bulk export.
- Recurring invoice templates — not included.
- Invoice line-item detail — the accounting export includes transaction-level data, but invoice-specific line items, tax breakdowns, and payment method/date require Wave Connect.
- Sales tax configuration — not included. API-only.
How to Export Wave Data Using Wave Connect (Google Sheets)
Wave Connect is Wave's official Google Sheets add-on. It covers objects that the native export misses — particularly chart of accounts, products, and invoice line items — and lets you filter what you download.
What Wave Connect can download
- Chart of Accounts — account name, type, subtype, currency, and balance
- Customers — name, email, address, currency, and outstanding balance
- Products / Services — name, description, unit price, and income/expense account mapping
- Invoices — including line items (description, quantity, unit price, amount), tax amounts per line, discount lines, payment date, payment method, invoice status, and customer reference
- Transactions — account, date, description, amount, and categorization
Wave Connect also generates multi-period financial reports directly in Google Sheets: Balance Sheet, Income Statement, Cash Flow, and Trial Balance.
Step-by-step
- Install Wave Connect from Google Workspace Marketplace or from Wave: Business name → Integrations → Google Sheets → Add to Sheets.
- In Google Sheets, click Extensions → Wave Connect → Connect Wave Account and authorize.
- To download data: Extensions → Wave Connect → Download → select data type (Customers, Products, Invoices, Chart of Accounts, Transactions).
- Select your business from the dropdown, choose which fields to include, and click Download.
Wave Connect lets you filter invoice and product downloads — unlike the native export, which is all-or-nothing. Use this to extract specific date ranges or product subsets without pulling everything.
Limitations of Wave Connect
- Does not export vendors, bills, payroll, receipts, or estimates. For those, use native Data Export or the API.
- Cannot be used with Personal business profiles — only works with business accounts.
- Subject to Google Sheets limits — a single sheet can hold approximately 10 million cells. For businesses with thousands of invoices with many line items, this can become a constraint.
- No export to Excel directly — data lands in Google Sheets. To get an
.xlsxfile, download the sheet via File → Download → Microsoft Excel (.xlsx).
Exporting Reports for Date-Filtered Data
Wave's report export fills a specific gap: getting date-filtered transaction data without pulling everything.
- In Wave, click Reports in the left menu.
- Select the report you need (e.g., Account Transactions, Trial Balance, Profit & Loss).
- Set your date range or other filters.
- Click Export and choose CSV or PDF.
This is the fastest way to export date-scoped transaction history and the primary path for establishing opening balances during a migration (via Trial Balance export). Report exports are available in the web browser only.
Is There an API to Bulk Export Wave Data?
Yes. Wave exposes a GraphQL API at https://gql.waveapps.com/graphql/public. It is the most flexible extraction method, but comes with significant constraints. (developer.waveapps.com)
Authentication: OAuth 2.0 vs. Full Access Tokens
Wave supports two authentication paths:
-
OAuth 2.0 — the production method. You register an application at developer.waveapps.com, obtain a
client_idandclient_secret, and exchange an authorization code for an access token. OAuth requires an active Pro ($16/mo for annual, $19/mo for monthly) or Wave Advisor subscription. Users on the free Starter plan cannot complete the OAuth grant flow. -
Full Access Tokens — available from the developer portal without a Pro subscription. These are per-user tokens tied to your developer account. They grant the same API access as OAuth tokens and can query your own business data. Wave documents these for "testing," but they can be used for production extraction against your own account. The key difference: Full Access Tokens cannot be issued to third-party users or customers, so they are unsuitable for building integrations that access other people's Wave data.
curl -X POST "https://gql.waveapps.com/graphql/public" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "query": "query { user { id defaultEmail } }", "variables": {} }'Discovering your schema: introspection query
Before writing extraction queries, run a GraphQL introspection query to discover available types and fields. This is especially important because Wave's schema can change without versioned URL changes:
query IntrospectBusiness {
__type(name: "Business") {
name
fields {
name
type {
name
kind
ofType { name kind }
}
}
}
}To list all available top-level query fields:
query {
__schema {
queryType {
fields {
name
description
}
}
}
}Run these queries periodically to detect schema changes before they silently break your extraction scripts.
Available queries
The API schema includes queries for:
user— authenticated user infobusinesses— list businesses accessible to the token holderbusiness(id)→customers,invoices,products,accounts,salesTaxes,estimates
Each object supports pagination and field selection. Unlike REST APIs, GraphQL requires you to explicitly declare every field you want to extract. If your query doesn't request a field, the API silently omits it from the response.
All requests are scoped to a businessId. You must first query the businesses node to retrieve your ID, then use that ID to fetch related objects.
Critical gap: The public API docs document transaction creation (including a bulk-create beta) but do not document a public transaction list/read query. For transaction history, you must rely on native Data Export or report exports. (developer.waveapps.com)
Pagination model
Wave's GraphQL API uses page-number-based pagination with page and pageSize parameters. Responses include a pageInfo object:
{
"pageInfo": {
"currentPage": 1,
"totalPages": 15,
"totalCount": 742
}
}Official examples use a pageSize of 50 records per page. There is no documented maximum page size — exceeding the supported maximum will likely return an error or silently cap results. (developer.waveapps.com)
Rate limits
Wave's rate limits are not published in official developer documentation. No rate-limit headers (X-RateLimit-Remaining, Retry-After) are documented in the API response. This is a significant operational risk for bulk extraction scripts. (developer.waveapps.com)
Empirical observations from extraction scripts: In our experience running paginated exports against the Wave API, we have observed HTTP 429 responses when sustaining more than approximately 4–5 requests per second over a 60-second window. The throttling behavior appears to be per-token, not per-IP. After receiving a 429, a 10–30 second backoff consistently resolves the issue. These are practitioner observations, not a Wave SLA — your experience may differ based on query complexity and account type.
Conservative guidance: Start at 1–2 requests per second and monitor for HTTP 429 responses or silent errors. Implement exponential backoff. At 2 requests per second with 50 records per page, you can estimate roughly 360,000 records per hour under ideal conditions. Real-world throughput will be lower due to query complexity, network latency, and throttling.
Wave's GraphQL schema can change without versioned URL changes. There are no versioned API endpoints — the schema at gql.waveapps.com/graphql/public is the only one. Monitor the developer portal for changes and run introspection queries periodically. A schema change mid-export can silently break field extraction.
Complete extraction script: business discovery through CSV output
This script handles the full extraction workflow: discovering your business ID, paginating through all invoices, handling rate limits with exponential backoff, and writing the output to a CSV file.
import requests
import time
import csv
import json
import sys
API_URL = "https://gql.waveapps.com/graphql/public"
ACCESS_TOKEN = "<YOUR_ACCESS_TOKEN>" # Full Access Token or OAuth token
HEADERS = {
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json"
}
# Step 1: Discover your business ID
BUSINESS_QUERY = """
query {
businesses(page: 1, pageSize: 10) {
edges {
node {
id
name
}
}
}
}
"""
def get_business_id():
"""Fetch and display available businesses, return the first one."""
response = requests.post(API_URL, headers=HEADERS, json={"query": BUSINESS_QUERY})
response.raise_for_status()
data = response.json()
businesses = data["data"]["businesses"]["edges"]
for biz in businesses:
print(f"Business: {biz['node']['name']} — ID: {biz['node']['id']}")
return businesses[0]["node"]["id"]
# Step 2: Paginated invoice extraction with retry logic
INVOICE_QUERY = """
query($businessId: ID!, $page: Int!, $pageSize: Int!) {
business(id: $businessId) {
invoices(page: $page, pageSize: $pageSize) {
pageInfo { currentPage totalPages totalCount }
edges {
node {
id
invoiceNumber
invoiceDate
dueDate
status
pdfUrl
customer { id name email }
total { value currency { code } }
items {
description
quantity
price
subtotal { value }
taxes { amount { value } salesTax { name rate } }
}
}
}
}
}
}
"""
def export_invoices(business_id, page_size=50):
"""Paginate through all invoices with exponential backoff."""
all_invoices = []
page = 1
retries = 0
max_retries = 5
while True:
variables = {
"businessId": business_id,
"page": page,
"pageSize": page_size
}
response = requests.post(
API_URL,
headers=HEADERS,
json={"query": INVOICE_QUERY, "variables": variables}
)
if response.status_code == 429 or response.status_code >= 500:
retries += 1
if retries > max_retries:
print(f"Max retries exceeded on page {page}. Exiting.")
sys.exit(1)
wait = min(2 ** retries * 5, 120) # 10s, 20s, 40s, 80s, 120s
print(f"Rate limited or server error ({response.status_code}). "
f"Waiting {wait}s before retry {retries}/{max_retries}...")
time.sleep(wait)
continue
response.raise_for_status()
data = response.json()
if "errors" in data:
print(f"GraphQL errors: {json.dumps(data['errors'], indent=2)}")
sys.exit(1)
invoices = data["data"]["business"]["invoices"]
edges = invoices["edges"]
all_invoices.extend([e["node"] for e in edges])
page_info = invoices["pageInfo"]
print(f"Page {page_info['currentPage']}/{page_info['totalPages']} "
f"— {len(all_invoices)}/{page_info['totalCount']} invoices")
if page >= page_info["totalPages"]:
break
page += 1
retries = 0
time.sleep(0.5) # Conservative: ~2 req/sec
return all_invoices
# Step 3: Write to CSV
def write_invoices_csv(invoices, filename="wave_invoices_export.csv"):
"""Flatten invoice data to CSV with one row per line item."""
with open(filename, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerow([
"InvoiceID", "InvoiceNumber", "InvoiceDate", "DueDate",
"Status", "CustomerID", "CustomerName", "CustomerEmail",
"TotalValue", "Currency", "PdfUrl",
"ItemDescription", "ItemQty", "ItemPrice", "ItemSubtotal"
])
for inv in invoices:
customer = inv.get("customer") or {}
total = inv.get("total") or {}
currency = total.get("currency") or {}
items = inv.get("items") or [{}]
for item in items:
writer.writerow([
inv.get("id"), inv.get("invoiceNumber"),
inv.get("invoiceDate"), inv.get("dueDate"),
inv.get("status"),
customer.get("id"), customer.get("name"),
customer.get("email"),
total.get("value"), currency.get("code"),
inv.get("pdfUrl"),
item.get("description"), item.get("quantity"),
item.get("price"),
(item.get("subtotal") or {}).get("value")
])
print(f"Wrote {len(invoices)} invoices to {filename}")
if __name__ == "__main__":
business_id = get_business_id()
invoices = export_invoices(business_id)
write_invoices_csv(invoices)
# Optional: save raw JSON for complete data preservation
with open("wave_invoices_export.json", "w") as f:
json.dump(invoices, f, indent=2)Adapt the query fields and CSV columns for customers, products, estimates, or accounts by swapping the GraphQL query and flattening logic.
Downloading invoice PDFs programmatically
The pdfUrl field returned by the invoices query provides a direct download URL for each invoice PDF. To bulk-download:
import os
def download_invoice_pdfs(invoices, output_dir="wave_pdfs"):
"""Download PDF for each invoice using the pdfUrl field."""
os.makedirs(output_dir, exist_ok=True)
for inv in invoices:
pdf_url = inv.get("pdfUrl")
if not pdf_url:
continue
inv_number = inv.get("invoiceNumber", inv["id"])
filepath = os.path.join(output_dir, f"invoice_{inv_number}.pdf")
response = requests.get(pdf_url, headers=HEADERS)
if response.status_code == 200:
with open(filepath, "wb") as f:
f.write(response.content)
print(f"Downloaded {filepath}")
else:
print(f"Failed to download invoice {inv_number}: {response.status_code}")
time.sleep(0.5) # Respect rate limitsWebhooks for incremental sync
Wave's documented webhooks cover invoice.created, invoice.updated, invoice.sent, invoice.viewed, invoice.completed, invoice.payment_status_changed, estimate.created, estimate.updated, estimate.sent, estimate.viewed, estimate.completed, and checkout.paid events. They do not give you general customer, vendor, product, or transaction change streams.
Sample webhook payload structure for invoice.created:
{
"accountId": "uuid-string",
"businessId": "uuid-string",
"eventType": "invoice.created",
"data": {
"invoiceId": "raw-uuid-string"
}
}Note the ID format mismatch: webhook payloads use raw UUIDs (e.g., a1b2c3d4-...), while the public GraphQL API uses global IDs (e.g., QnVzaW5lc3M6... — base64-encoded). The GraphQL schema marks several internalId fields as deprecated. If you mix webhooks and API exports, normalize IDs early. Build long-term mappings on the global Node.id from the API, and use the raw UUID from webhooks only for lookup. (developer.waveapps.com)
How to Export Receipts and Attachments from Wave
Attachments in Wave are fragmented across features, and each follows different export rules.
Receipts
Wave includes receipt images in its native Data Export. The Receipts export produces a ZIP file containing all uploaded receipt images in their original file types (JPEG, PNG, PDF). (support.waveapps.com)
The gap: no metadata linking. The receipt images export as standalone files without a manifest mapping each image to its corresponding transaction. You'll need to cross-reference manually or by filename.
Invoice and estimate attachments
Invoice and estimate attachments are a Pro feature. Wave supports JPG, PNG, GIF, PDF, DOC/DOCX, XLS/XLSX, and CSV — up to 25 files, 20 MB total, and 10 files per upload. Files over 5 MB appear on the invoice or estimate page but are not included as email attachments. (support.waveapps.com)
These attachments are not included in the native Data Export. The GraphQL API exposes attachment metadata through ARAttachment fields like fileName, fileSize, and downloadUrl. To bulk-export them, your extraction script must:
- Query the API for invoice records including attachment fields.
- Parse the JSON response to extract download URLs.
- Execute HTTP GET requests against those URLs to download the actual files.
- Save files with a naming convention that maps back to the Wave invoice or transaction ID — otherwise the attachments become orphaned from your ledger.
The public API schema does not document a dedicated bulk attachment export mutation or a standalone attachment create flow.
What Data Cannot Be Exported from Wave?
Several categories of data have no supported export path — or require manual workarounds.
| Data Type | Exportable? | Workaround |
|---|---|---|
| Audit logs / change history | No | None. Wave does not expose an audit trail. |
| Recurring invoice templates | No documented query | End and recreate them in the destination. (support.waveapps.com) |
| Customer payment credentials | No | Wave's migration guidance says credit card info is not included when moving data. Customers must re-enter it. (support.waveapps.com) |
| Transaction history (API) | No public read query | Use Data Export and Account Transactions / GL report exports. |
| Automation rules / bank rules | No | Must be manually recreated in the destination system. |
| User permissions / collaborators | No | No API endpoint. Collaborator management is UI-only. |
| Integration configurations | No | Must be manually reconfigured. |
| Deleted / archived transactions | No | Once deleted in Wave, data is not recoverable via export or API. |
| Saved views / report filters | No | Must be manually recreated. |
| Payment processing history (Stripe-backed) | Partial | Transaction-level data exports, but detailed payment gateway data (disputes, refund metadata) lives in Stripe, not Wave. |
The absence of audit logs and the inability to export user permissions are the most significant gaps for compliance-conscious organizations. If your regulatory environment requires a provable audit trail, you'll need to supplement Wave's exports with external logging.
Cross-business exports: Wave's Data Export only covers the business profile you're currently in. If you manage multiple Wave businesses, you must repeat the process for each one. (support.waveapps.com)
Data Format, Encoding, and Post-Export Cleanup
Wave exports produce a mix of CSV/XLS files, Google Sheets rows, PDFs, ZIP files, and JSON responses depending on the method. Treat this as a multi-format export, not a normalized backup.
Encoding
- CSV/XLS exports use UTF-8 encoding. Special characters in customer names, product descriptions, or memo fields are preserved.
- The API returns JSON with UTF-8 string encoding per the GraphQL spec.
Common data quality issues
- Category inconsistencies — Wave allows freeform category and product naming. Exports frequently contain variations like "Consulting," "consulting," "Consulting Income," and "Consult Services" for the same logical category. Clean these before importing into a target system.
- Date formats — API timestamps are in UTC (e.g.,
2023-10-15T14:30:00Z). If your business operates in EST, a transaction recorded at 10:00 PM EST on October 15th will appear as October 16th in UTC. Script timezone offsets before importing to avoid shifting revenue across month-end boundaries. For CSV re-import, ISO 8601 (YYYY-MM-DD) is safest. - Currency handling — Wave's primary currencies are USD and CAD. If you invoice in other currencies, UI exports may flatten foreign amounts to your base currency equivalent. Verify the API response includes the original amount and currency code if foreign currency detail matters for your migration. Wave's own migration guidance tells teams to handle foreign-currency items carefully. (support.waveapps.com)
- Orphaned references — Bill items may reference vendors that have been modified or merged. Customer references on invoices may not match the current customer list if names were edited after invoice creation.
Post-export validation checklist
- Verify row counts: compare exported record count to Wave's UI count for each object.
- Spot-check 5–10 transactions against the Wave UI for amount, date, and category accuracy.
- Check for encoding issues: open CSV in a text editor (not Excel) to confirm special characters render correctly.
- Validate that receipt images open and are not corrupted.
- Cross-reference invoice totals: sum the exported invoice amounts and compare to a Wave Sales Tax report or Profit & Loss.
- Export a Trial Balance report and confirm it matches the sum of your transaction export.
- Copy emailed export files into your own storage immediately — the Data Export download link expires after 24 hours.
For a broader finance-system QA framework, see our Accounting Data Migration Checklist: The 10-Point Plan.
Export for Migration vs. Backup vs. Compliance
Your extraction method and scope change based on your end goal.
Migration
When migrating from Wave to another accounting platform, you need:
- Chart of accounts mapped to the target platform's account structure. Wave uses a flat category model — most targets use hierarchical charts with account types and subtypes. Specific mapping requirements by destination:
- QuickBooks Online — requires account type (Bank, Expense, Income, etc.) and detail type for each account. Accepts IIF or CSV import. Max 250 accounts.
- Xero — requires account code (numeric), account type, and tax type. Accepts CSV import with specific column headers:
*Code,*Name,*Type,Description,Tax Code. - FreshBooks — uses a fixed chart of accounts that cannot be customized. Map Wave categories to FreshBooks' predefined expense and income categories.
- Opening balances as of your migration cutoff date. Export a Trial Balance report for that date.
- Transaction history — decide how far back to migrate. Most migrations carry forward 1–2 fiscal years; older data stays in Wave as a read-only archive.
- Customer and vendor records — export and deduplicate before import. QuickBooks accepts CSV with
Name,Email,Phone,Addresscolumns. Xero requiresContactNameas the only mandatory field. - Invoice line items — if you need invoice detail (not just totals), use Wave Connect's invoice download with line items enabled.
- ID mapping — Wave's internal IDs will not match the destination system. The API returns Wave's internal IDs; native exports use human-readable identifiers. Build a mapping table during import.
A flat CSV of invoices is useless if you don't also have the Wave Customer IDs to link those invoices to the correct accounts in the new system. For migration-grade exports, the API is the primary tool for maintaining relational integrity.
Wave itself is focused on US and Canadian businesses, with primary currency options of USD and CAD. If your destination is more global, factor in currency mapping during the migration. (support.waveapps.com)
For teams moving between Wave and QuickBooks, our QuickBooks to Wave Migration guide covers the architectural mismatches in detail.
Backup
For backup purposes, run the full native Data Export (Accounting + Receipts + Payroll if applicable) on a regular schedule. Wave does not offer scheduled or automated exports — this is a manual process. Store the exported ZIP files in a secure, versioned location (cloud storage with retention policies).
Wave's subscription terms indicate that terminated accounts may have data deleted, subject to the privacy policy. The privacy policy states Wave retains data "for as long as your account is active or as needed to provide you services" and for a period afterward as required by law — but does not specify a fixed retention window in days or months. Export early rather than at the end of your contract. (waveapps.com)
Compliance (GDPR / DSAR)
Wave is available in the US and Canada, so GDPR Article 20 data portability obligations apply primarily to businesses with EU-based customers.
- Data Subject Access Requests (DSARs): You can export customer-specific data by filtering the customers file from native export and pulling their invoices via Wave Connect or the API. Wave does not have a single-click "Export User Data" button.
- Right to erasure: Wave does not expose a bulk deletion API. Customer deletion must be handled through the UI.
- Audit trail for compliance: Wave does not export audit logs. If your compliance framework requires chain-of-custody documentation, you must create that externally.
Wave's privacy policy states users can request data portability, but notes that some information may not be stored in an online-accessible format. (waveapps.com)
For a deeper look at compliance-focused migration frameworks, see our GDPR Compliant Data Migration blueprint.
Wave Portability Audit: How Portable Is Wave Data?
Portability rating: Mostly Portable.
Wave earns this — not "Fully Portable" — for specific, measurable reasons.
Cleanly exportable (~85% of data by volume):
- All transactions, journal entries, and bill items via native export
- Customer and vendor records
- Invoice data with line items (via Wave Connect or API)
- Receipt images
- Chart of accounts (via Wave Connect or API)
- Products/services catalog (via Wave Connect or API)
- Financial reports with date filtering
Exportable with transformation or workarounds (~10%):
- Invoice PDFs must be downloaded individually or scripted via API
pdfUrl - Estimates require API extraction or individual PDF export
- Products/services and chart of accounts are not in native export — require a second extraction step
- Category naming inconsistencies need cleanup before import
Not exportable (~5%):
- Audit history
- Recurring invoice template configurations
- Bank connection settings and bank rules
- User permissions and collaborator assignments
- Integration configurations
- Saved report views and filters
- Customer payment credentials
Switching cost assessment: For a typical freelancer or micro-business with under 1,000 invoices, exporting from Wave is a half-day self-serve process using native export plus Wave Connect. For businesses with 5,000+ invoices needing full PDF archives and line-item preservation, budget 1–2 days of engineering time for API scripting. Wave does not impose contractual restrictions on data export — there are no ToS clauses restricting export frequency or penalizing data extraction.
The real switching cost is less about a locked ledger and more about stitching separate exports back into a reliable target model. The process is fragmented, and some operating state (recurring billing, bank rules, integrations) must be rebuilt manually in the destination.
For a detailed technical comparison of Wave's architecture against competitors, see QuickBooks vs Wave (2026): The CTO's Technical Comparison.
Timeline and Resourcing for a Full Data Export
Realistic time estimates for a complete Wave data extraction:
| Dataset Size | Likely Approach | Typical Effort | Minimum Team |
|---|---|---|---|
| Small (<1,000 invoices, <5,000 transactions) | UI exports + Wave Connect + report QA | 4–6 hours | 1 ops/finance owner (Admin role) |
| Medium (1,000–10,000 invoices) | Add API pulls for invoices, attachments, or structured validation | 1–2 days | PM/analyst + optional developer |
| Large (10,000+ invoices, bulk PDF needs) | Scripted export, staged validation, attachment batching | 3–5 days | 1 developer + QA/reconciliation owner |
Minimum team composition
- No-code export (native + Wave Connect): 1 person with Admin access. No developer required.
- API-based export: 1 developer with GraphQL experience, OAuth 2.0 familiarity, and access to a Pro or Wave Advisor subscription (or a Full Access Token from the developer portal).
- Full migration with transformation: 1 developer + 1 PM/accountant for validation. Consider a managed migration service if internal bandwidth is constrained.
Phase breakdown
- Scoping — Inventory all data objects, decide which to export, confirm destination requirements (import format, required fields, account structure).
- Access provisioning — Ensure Admin role access for native export. If using the API, register an app at developer.waveapps.com, generate a Full Access Token or complete the OAuth flow. Confirm that a Pro subscription is active if using OAuth.
- Extraction — Run native export + Wave Connect downloads. Export reports for date-scoped data. Script API extraction for objects not covered by native methods (invoice PDFs, estimates, sales taxes, attachments).
- Validation — Cross-reference exported data against the Wave UI. Check row counts, totals, and sample records. Run the post-export validation checklist above.
- Cleanup — Deduplicate customers/vendors, normalize categories, fix date formats, map IDs for the target platform.
When a Managed Export Makes Sense
For straightforward backups or simple single-platform migrations, Wave's self-serve tools are sufficient. The complexity stacks up when the project involves:
- Transforming Wave's flat category model into a structured chart of accounts for QuickBooks or Xero
- Preserving invoice line items across platforms
- Downloading thousands of invoice PDFs via API
- Maintaining data integrity during a live cutover
- Managing undocumented rate limits with built-in retry queues
That's engineering work. Writing a custom extraction script for a one-time migration is often a poor use of in-house engineering time.
FAQ
Can I export all my data from Wave? Not from one button. Wave splits exports across Data Export, Wave Connect, report exports, per-document PDFs, and the GraphQL API. You can export the vast majority of your transactional data, but estimates, recurring templates, audit logs, user permissions, and customer payment credentials cannot be bulk-exported through any supported method. (support.waveapps.com)
Does Wave export include attachments and receipts?
Receipts export as a ZIP of original files from native Data Export. Invoice and estimate attachments are separate — they are not included in the native export but can be accessed via the GraphQL API's ARAttachment fields, which return download URLs for programmatic retrieval. There is no single-click method to export all attachments with their linked transaction metadata. (support.waveapps.com)
Does the Wave API require a paid subscription? OAuth-based API access requires an active Pro ($16/mo annual, $19/mo monthly) or Wave Advisor subscription. Users on the free Starter plan cannot complete the OAuth grant flow. However, Full Access Tokens can be generated from the developer portal without a Pro subscription — these work for extracting your own business data but cannot be issued to third-party users. (developer.waveapps.com)
What format does Wave export data in? Depending on the method: CSV or XLS files from native Data Export, Google Sheets rows from Wave Connect, CSV or PDF from report exports, and JSON from the GraphQL API. All text data uses UTF-8 encoding. (support.waveapps.com)
How do I export Wave data to Excel?
Native Data Export produces CSV/XLS files that open directly in Excel. Wave Connect downloads data into Google Sheets, which you can then download as .xlsx via File → Download → Microsoft Excel (.xlsx). Report exports can be downloaded as CSV files, which Excel opens natively. The GraphQL API returns JSON, which requires transformation to CSV or XLSX using a script or tool like Python's csv module or openpyxl.
How do I export Wave data to migrate to another accounting platform? Start with Wave's native Data Export for transactions, bills, customers, and vendors. Use Wave Connect to download your chart of accounts, products, and invoices with line items. Export a Trial Balance report for your migration cutoff date to establish opening balances. Map Wave's flat category structure to the target platform's chart of accounts before import — this mapping step is where most Wave migrations break. See the Migration section above for destination-specific import format requirements for QuickBooks, Xero, and FreshBooks.
Frequently Asked Questions
- Can I export all my data from Wave?
- Not from one button. Wave splits exports across Data Export, Wave Connect, report exports, per-document PDFs, and the GraphQL API. You can export most transactional data, but estimates, recurring templates, audit logs, user permissions, and customer payment credentials cannot be bulk-exported through any supported method.
- Does Wave export include attachments and receipts?
- Receipts export as a ZIP of original files from the native Data Export. Invoice and estimate attachments are separate — they are not included in the native export but can be accessed via the GraphQL API's attachment fields, which return download URLs for programmatic retrieval.
- Does the Wave API require a paid subscription?
- Yes. API access via OAuth requires an active Pro ($16–$19/month) or Wave Advisor subscription. Users on the free Starter plan cannot grant API access tokens. For personal testing, Wave documents that Full Access Tokens can be used without a Pro subscription.
- What format does Wave export data in?
- Depending on the method: CSV or XLS files from native Data Export, Google Sheets rows from Wave Connect, CSV or PDF from report exports, and JSON from the GraphQL API. All text data uses UTF-8 encoding.
- How do I export Wave data to migrate to another accounting platform?
- Start with native Data Export for transactions, bills, customers, and vendors. Use Wave Connect for chart of accounts, products, and invoices with line items. Export a Trial Balance report for your cutoff date. Map Wave's flat categories to the target platform's chart of accounts before import.

