What this audit checks
Authentication & access
- Bearer token (OAuth2 access token or Full Access Token) authenticates against the GraphQL endpoint - the
businessesquery returns at least one business without a 401 - OAuth2 refresh succeeds when an access token expires (client_id + client_secret + refresh_token against https://api.waveapps.com/oauth2/token/) - or a long-lived Full Access Token is in use
- Configured business_id resolves to a business the token can read (currencyCode + name returned)
- Token scope grants read access to invoices, customers, accounts and moneyTransactions - a partial scope silently empties downstream cards
AR collection health
- Invoices in OVERDUE status above the collection threshold (cash stuck past due date)
- AR aged 60+ days above 15% of total AR balance (least-collectible bucket concentrating)
- Days Sales Outstanding (DSO) above 60 days (cash sitting too long in receivables)
- SENT/VIEWED invoices never followed by payment after the due date + grace window (silent non-payers)
Books hygiene & income recognition
- moneyTransactions in UNREVIEWED status above threshold (books drift from reality, sales-tax base understated)
- Money transactions with no category / account assigned (uncategorised income or expense)
- Net income (INCOME-type minus EXPENSE-type) regressing >20% vs trailing period
- Draft (DRAFT/SAVED) invoices older than the billing cadence - revenue not yet issued to the customer
Cross-channel: Wave vs ecommerce / PSP reconciliation
- Storefront order has no matching Wave invoice / income transaction after the sync window (sibling = bigcommerce.order / shopify.order / adobe_commerce.order, by poNumber=order_reference or customer email)
- Customer with AR aged 60+ days / OVERDUE invoices still placing new ecom orders (credit risk compounding, sibling = ecommerce customer by email)
- Repeat ecom customer with completed orders absent from the Wave customer master after 7d (sibling = bigcommerce.customer / shopify.customer, by email)
- PSP payout (stripe.payout / paypal.payout) with no reconciled Wave money transaction after 7d, by reference (sibling = payment_gateway)
Data sources
POST https://gql.waveapps.com/graphql/public- Single GraphQL endpoint - all reads (businesses / invoices / customers / accounts / moneyTransactions queries) POST herePOST https://api.waveapps.com/oauth2/token/- OAuth2 token refresh (authorization-code grant) when the access token expires