wave-api 0.1.0

Typed Rust client for the Wave Accounting GraphQL API
Documentation

wave-api

Typed Rust client for the Wave Accounting GraphQL API.

No code generation, no raw GraphQL strings in user code. All connection types are flattened into Page<T> results, monetary values use rust_decimal::Decimal, and mutations use a builder pattern for inputs.

Features

  • OAuth2 authentication with automatic token refresh on UNAUTHENTICATED errors
  • Strongly typed queries, mutations, inputs, and enums
  • Pagination — GraphQL connections are flattened into simple Page<T> results
  • Decimal precision — all monetary values use rust_decimal::Decimal
  • Builder pattern for mutation inputs with optional field skipping

Quick Start

Add to your Cargo.toml:

[dependencies]
wave-api = "0.1"
use wave_api::{WaveClient, OAuthConfig};

let client = WaveClient::with_oauth(OAuthConfig {
    client_id: "...".into(),
    client_secret: "...".into(),
    access_token: "...".into(),
    refresh_token: "...".into(),
    redirect_uri: "http://localhost:3099/callback".into(),
    on_token_refresh: None,
});

let businesses = client.list_businesses(Default::default()).await?;
for biz in &businesses.items {
    println!("{}: {}", biz.id, biz.name);
}

API Coverage

Queries

Resource Methods
User get_user
Business list_businesses, get_business
Customer list_customers, get_customer
Invoice list_invoices, get_invoice
Account list_accounts, get_account
Product list_products, get_product
Vendor list_vendors, get_vendor
Sales Tax list_sales_taxes, get_sales_tax
Constants list_currencies, list_countries, list_account_types, list_account_subtypes

Mutations

Resource Methods
Customer create_customer, patch_customer, delete_customer
Invoice create_invoice, patch_invoice, delete_invoice, clone_invoice, approve_invoice, send_invoice, mark_invoice_sent
Account create_account, patch_account, archive_account
Product create_product, patch_product, archive_product
Sales Tax create_sales_tax, patch_sales_tax, archive_sales_tax
Transaction create_money_transaction, create_money_transactions

Examples

Set up a .env file with your Wave OAuth credentials:

WAVE_CLIENT_ID=...
WAVE_CLIENT_SECRET=...
WAVE_ACCESS_TOKEN=...
WAVE_REFRESH_TOKEN=...
WAVE_REDIRECT_URI=http://localhost:3099/callback
WAVE_BUSINESS_ID=...

Then run any of the examples:

# List all businesses
cargo run --example list_businesses

# Create an invoice
cargo run --example create_invoice

# Profit & Loss report
cargo run --example profit_and_loss -- --start-date 2025-01-01 --end-date 2025-12-31

Authentication

wave-api uses OAuth2. You'll need to register an application with Wave to obtain a client ID and secret. See oauth_flow.py for a helper that runs the authorization code flow locally.

When an API call receives an UNAUTHENTICATED error, the client automatically refreshes the access token using the refresh token and retries the request once. You can provide an on_token_refresh callback to persist new tokens:

let client = WaveClient::with_oauth(OAuthConfig {
    // ...
    on_token_refresh: Some(Arc::new(|new_access, new_refresh| {
        println!("New tokens: {new_access}, {new_refresh}");
    })),
});

Error Handling

All methods return Result<T, WaveError>. The error enum covers:

  • Http — network / HTTP errors
  • Json — serialization / deserialization failures
  • GraphQL — errors returned by the Wave API
  • MutationFailed — mutation didSucceed: false with inputErrors
  • Auth — missing or invalid credentials
  • TokenRefresh — refresh token flow failed

License

MIT