Accounting Margin & QuickBooks Setup
Import Cloudflare AI Gateway costs and sync invoices to QuickBooks Online for agency margin reports
Overview
Accounting combines local invoice revenue with provider usage costs so the agency can see real margin by month, client, provider, and feature. It also syncs invoices to QuickBooks Online as a bookkeeping mirror.
Source Of Truth
- Stripe and local Billing 2.0 remain the source of truth for invoices, hosted payment links, payment state, and client billing history.
- Cloudflare AI Gateway logs are imported into
provider_usage_ledgerfor provider cost rows. Cloudflare skips rows taggedfeature=voicebecause the call-close ledger writes immediate per-agent attributions — use the Cloudflare dashboard to audit upstream realtime logs and tune local voice rates. - Command Center requests are tagged
feature=commandandagentId=command; Command tool results also write zero-costcommand_toolrows so internal tool usage shows under the client instead ofUnassigned. - Completed voice calls write local
voice_cost_estimaterows intoprovider_usage_ledgerbyclientId,agentId, andcallSidso Accounting can show client and agent cost before a Cloudflare log import runs. - QuickBooks Online is the agency bookkeeping mirror. The app syncs local invoices into the agency's QuickBooks company and stores returned QuickBooks IDs locally.
Cloudflare AI Gateway Cost Import
Set these env vars on the API service:
CF_AI_GATEWAY_ACCOUNT_ID=your_cloudflare_account_id
CF_AI_GATEWAY_SLUG=your_gateway_slug
CF_AI_GATEWAY_TOKEN=your_gateway_auth_token
# Read-scoped Cloudflare API token for imports
CF_AI_GATEWAY_LOGS_TOKEN=your_cloudflare_ai_gateway_read_token
The import uses Cloudflare's AI Gateway logs API to pull provider, model, token counts, cost, and metadata per AI call. The app expects AI calls to include flat cf-aig-metadata values (clientId, agentId, feature) for per-client/per-agent cost attribution.
Reference:
- Cloudflare AI Gateway logs API
- AI Gateway observability — logging
- AI Gateway observability — custom metadata
Voice Cost Estimates
Set these optional env vars when your vendor pricing changes:
VOICE_COST_GEMINI_PER_MINUTE_USD=0.04
VOICE_COST_GROK_PER_MINUTE_USD=0.04
VOICE_COST_PIPELINE_PER_MINUTE_USD=0.056
VOICE_COST_TWILIO_CALL_PER_MINUTE_USD=0.014
VOICE_COST_TWILIO_SMS_PER_MESSAGE_USD=0.0079
Each completed call records an AI row (feature=voice_ai) and a telephony row (feature=voice_telephony). The Accounting page groups those rows by client, provider, feature, and agent.
Reference:
QuickBooks Online Agency Connection
Create an Intuit app and add these env vars to the API service:
QUICKBOOKS_ENVIRONMENT=sandbox
QUICKBOOKS_CLIENT_ID=your_intuit_client_id
QUICKBOOKS_CLIENT_SECRET=your_intuit_client_secret
QUICKBOOKS_REDIRECT_URI=https://YOUR_API_HOST/admin/accounting/quickbooks/callback
QUICKBOOKS_WEBHOOK_VERIFIER_TOKEN=your_intuit_webhook_verifier_token
In the Intuit app, enable the accounting scope:
com.intuit.quickbooks.accounting
Set the redirect URI exactly as configured in QUICKBOOKS_REDIRECT_URI.
Reference:
QuickBooks Webhook
Configure Intuit webhooks at:
https://YOUR_API_HOST/admin/accounting/quickbooks/webhook
Enable at least Customer, Item, Invoice, and Payment notifications. The webhook validates the intuit-signature header with QUICKBOOKS_WEBHOOK_VERIFIER_TOKEN and records the latest event snapshot on the agency QuickBooks connection.
Keep webhook work light — Intuit expects a quick 200 response.
Reference: QuickBooks Webhooks
Operator Flow
- Open Admin → Accounting.
- Pick the month and year.
- Click Import Usage to pull Cloudflare AI Gateway cost rows.
- Click Connect on QuickBooks and authorize the agency QuickBooks company.
- Return to Accounting and click Sync Period Invoices.
- Confirm each client row shows synced versus pending QuickBooks invoices.
Verification
Run syntax checks:
node --check models/provider-usage-ledger.js
node --check models/quickbooks-connection.js
node --check utils/cloudflare-ai-gateway-usage.js
node --check utils/quickbooks-agency.js
node --check utils/accounting-summary.js
node --check routes/admin-accounting.js
Run the web type check:
npm --prefix web run type-check
Manual Sandbox Check
- Use a QuickBooks sandbox company.
- Create a test client billing invoice in the app.
- Connect QuickBooks from Accounting.
- Sync period invoices.
- Confirm the local invoice stores
quickBooks.invoiceId. - Confirm the invoice appears in the QuickBooks sandbox company.
