Skip to content

How to Integrate the Brex API with Xero and QuickBooks (2026 Developer Guide)

A complete engineering guide to syncing Brex transactions into QuickBooks Online and Xero. Learn how to handle strict API rate limits, double-entry ledger mapping, and unified API architecture.

Yuvraj Muley Yuvraj Muley · · 12 min read
How to Integrate the Brex API with Xero and QuickBooks (2026 Developer Guide)

If you are building a B2B SaaS product that touches corporate spend—whether that is an expense management platform, an AP automation tool, or a procurement system—your customers expect you to sync their transactions directly into their general ledger. Raw card swipe data is practically useless to a finance team until it is categorized, matched with a receipt, assigned to a department, and written into an accounting system like QuickBooks Online (QBO) or Xero as a reconciled journal entry.

Building this data pipeline requires bridging a high-volume fintech API with rigid, double-entry accounting ledgers. According to a recent survey of senior finance professionals by Payhawk, 29% cite human error as their top spend management challenge, followed closely by time wasted on manual reconciliation at 28%. Your integration solves this exact pain point, but building it is an engineering minefield.

This guide breaks down the architectural requirements, rate limit handling, and double-entry ledger mapping strategies necessary to reliably connect the Brex API to Xero and QuickBooks Online. We will also examine why point-to-point spend integrations inevitably collapse at scale and how modern engineering teams avoid this technical debt.

The Architecture of a Brex-to-Accounting Integration

The core data flow between a corporate card provider like Brex and an accounting system follows a predictable pattern, but the engineering complexity lies in its bidirectionality. You must read reference data from the accounting system before you can write anything to it.

Brex APIs use the REST architecture, are defined using the OpenAPI specification, and use standard HTTP response codes and verbs. You will primarily work with two endpoints:

  • Transactions API: Returns settled card and cash transactions with amounts, dates, merchant data, and descriptions. Notably, Brex only returns settled transactions through the Transactions API; pending transactions are not available.
  • Expenses API: Provides the business context, including memos, category tags, linked receipts, and approval statuses.

When you map corporate spend to a general ledger, you are usually merging data from the Transactions API (the amount and date) with the Expenses API (the receipt and category). This merge is where most teams underestimate the work. The transaction tells you "$347.82 at AWS," but the expense tells you "charged to Engineering, tagged as Infrastructure, receipt attached, approved by VP Eng."

The Four Phases of a Reliable Accounting Sync Pipeline

To reliably move this merged data into an ERP, your pipeline must execute four distinct phases:

  1. Ingestion: Listening for Brex webhooks (e.g., expense.created, expense_payment_updated) or polling the Brex Transactions API to capture new spend events.
  2. Normalization: Converting the Brex payload into a standardized internal model within your application.
  3. Mapping: Querying the target ERP for the customer's Chart of Accounts (CoA), tax rates, tracking categories, and vendor lists, then applying user-defined rules to route the spend to the correct ledger accounts.
  4. Writing: Formatting the normalized data into a double-entry Journal Entry or Expense payload and executing a POST request to the QBO or Xero API.
flowchart TD
    A["Brex API / Webhooks<br>(Raw Transaction Data)"] --> B["Ingestion Queue<br>(Idempotency & Retries)"]
    B --> C["Mapping Engine<br>(Apply Chart of Accounts)"]
    C --> D["Accounting API<br>(Xero / QBO)"]
    D --> E["Store External ID<br>(Reconciliation State)"]
    D -.->|"Fetch CoA, Tax Rates, Vendors"| C

For a deeper look at the overarching system design, read our guide on how to integrate the Brex API with your accounting stack.

Handling Webhooks and Idempotency

Brex pushes real-time updates via webhooks. When an employee swipes a card, Brex fires an event. If your server is down, or if a network partition occurs, Brex will retry delivering that webhook.

You must implement a strict idempotency layer. Every Brex transaction has a unique id. Before processing a webhook, your system must query its database to check if that id has already been synced. If you fail to build this check, a single retried webhook will result in duplicate journal entries in the customer's accounting system—a scenario that immediately destroys trust with finance teams.

Handling Brex and Accounting API Rate Limits

Rate limits are the single most common production failure in spend-to-ledger integrations. High-volume transactional data from Brex will quickly overwhelm the legacy infrastructure of accounting platforms if you do not throttle your outbound requests. QuickBooks and Xero have very different rate limit profiles, requiring distinct architectural strategies.

QuickBooks Online Rate Limits

QuickBooks Online enforces aggressive rate limits. QBO limits API calls to 500 requests per minute per company (realm ID), with a strict maximum of 10 concurrent requests. Batch operations get 40 requests per minute, while resource-intensive endpoints drop to 200 requests per minute.

Intuit also updated its batch endpoint throttling in late 2025. API calls to the Batch endpoint are now throttled at 120 requests per minute per realm ID.

500 requests per minute sounds generous until you paginate through a large QuickBooks company. If one enterprise customer has a massive QuickBooks account with tens of thousands of invoices or vendors, you will burn through the per-minute limit during a single paginated sync.

Another under-documented pain point: QuickBooks Online designs the access token to be valid for only one hour. The refresh token expires after 101 days. If your token refresh logic fails silently, your customer's connection breaks and they must re-authorize manually.

Xero API Rate Limits

Xero is far more restrictive than QuickBooks. As detailed in our guide to integrating with the Xero API, they enforce a concurrent limit of 5 API calls in progress at a time (per-organization, per-app). The minute limit is just 60 API calls per minute. The daily limit is 5,000 API calls per day. There is also an app-wide minute limit of 10,000 calls per minute across all tenancies for a single app.

60 calls per minute is exactly one call per second. In Xero, syncing a single invoice with 3 items can take up to 6 API calls. If a customer has 200 Brex transactions to reconcile this month and each write involves fetching the Chart of Accounts, matching a vendor, and writing the expense, you will hit the daily limit incredibly fast.

Furthermore, Xero access tokens expire after 30 minutes. To maintain uninterrupted access, you must request the offline_access scope to receive a refresh token, which should be renewed proactively before expiry.

Rate Limit Comparison Table

Constraint QuickBooks Online Xero
Requests per minute 500 60
Concurrent requests 10 5
Daily limit None 5,000 per org
Batch endpoint 120/min ~50 items/request
Token expiry 1 hour 30 minutes
Refresh token expiry 101 days Rolling

Designing for HTTP 429 Errors

If you blast 1,000 concurrent Brex transactions at the QBO API, it will reject your payloads and return HTTP 429 (Too Many Requests) errors. Repeated violations can result in temporary connection bans. Your system must expect and gracefully handle HTTP 429 responses. This requires an asynchronous queueing system (like RabbitMQ, Kafka, or a managed queue service) and an exponential backoff algorithm.

When using a unified API platform like Truto to interact with these systems, it is important to understand the boundary of responsibility. Truto does not absorb, throttle, or automatically retry rate-limited API calls. When an upstream API like Xero returns an HTTP 429, Truto passes that exact error back to your application.

However, Truto normalizes the disparate rate limit headers from hundreds of APIs into standardized IETF headers:

  • ratelimit-limit: The maximum number of requests permitted in the current window.
  • ratelimit-remaining: The number of requests left in the current window.
  • ratelimit-reset: The time at which the rate limit window resets.

Your application code must read these headers, pause the specific customer's queue worker, and retry the payload after the ratelimit-reset timestamp has passed. For architectural patterns on handling these queues, review our documentation on best practices for handling API rate limits.

Mapping Corporate Spend to the General Ledger

The most complex technical hurdle in an accounting integration is the schema mismatch. Brex provides a flat JSON object representing a purchase. QBO and Xero require strict double-entry accounting structures.

Double-entry accounting is non-negotiable. Every transaction pushed to a ledger must have at least two line items—a debit and a credit—that balance exactly to zero. You cannot simply push "$50 for Software" to Xero. You must debit the "IT Software" expense account by $50 and credit the "Brex Clearing" liability or bank account by $50.

Here is the core mapping problem visualized:

Brex Transaction:
  amount: $347.82
  merchant: "Amazon Web Services"
  category: "Software"
  department: "Engineering"
  receipt: attached
  status: settled
 
  ↓ Must become ↓
 
QuickBooks Journal Entry:
  Debit:  6200 - Cloud Infrastructure (Expense)   $347.82
  Credit: 2100 - Brex Corporate Card (Liability)   $347.82
  Class: Engineering
  Tax Code: Non-taxable
  Memo: "AWS - Monthly compute, receipt attached"

The mapping logic is inherently customer-specific. "Software" in Brex does not map to the same GL account for every customer. Company A might route it to 6200 - Cloud Infrastructure. Company B puts it under 5400 - IT Expenses. Company C has a custom account 7100 - SaaS Subscriptions.

This means your integration must dynamically fetch the destination system's Chart of Accounts, Vendors, Tax Rates, and Tracking Categories (Xero) or Classes (QuickBooks). Then, you must expose a configuration UI where your customer maps their Brex spend categories to their specific GL segments. Your backend must cache these mappings and apply them dynamically during the sync.

The QBO Journal Entry Payload

To write a Brex transaction into QuickBooks Online, you typically hit the /v3/company/<realmID>/journalentry endpoint. Your payload must look something like this:

{
  "Line": [
    {
      "Id": "0",
      "Description": "GitHub Subscription - Brex Card",
      "Amount": 50.00,
      "DetailType": "JournalEntryLineDetail",
      "JournalEntryLineDetail": {
        "PostingType": "Debit",
        "AccountRef": {
          "value": "65" 
        }
      }
    },
    {
      "Id": "1",
      "Description": "GitHub Subscription - Brex Card",
      "Amount": 50.00,
      "DetailType": "JournalEntryLineDetail",
      "JournalEntryLineDetail": {
        "PostingType": "Credit",
        "AccountRef": {
          "value": "32" 
        }
      }
    }
  ]
}

Notice the AccountRef.value fields ("65" and "32"). These are internal QBO IDs representing specific accounts in the customer's chart of accounts.

The Xero Bank Transaction Payload

For Xero, you often use the POST /api.xro/2.0/BankTransactions endpoint, which represents spend slightly differently but still enforces balancing logic against specific AccountCodes.

{
  "Type": "SPEND",
  "BankAccount": {
    "Code": "BREX-01"
  },
  "Contact": {
    "Name": "GitHub"
  },
  "LineItems": [
    {
      "Description": "Software Subscription",
      "Quantity": 1.0000,
      "UnitAmount": 50.00,
      "AccountCode": "429",
      "TaxType": "NONE"
    }
  ]
}

If the AccountCode is invalid, or if the TaxType conflicts with the account's strict settings, Xero will reject the payload with a 400 Bad Request. Your integration must parse these vendor-specific error messages and surface them in your UI so the customer can fix their mapping configuration.

Xero vs. QuickBooks: Key Ledger Differences

Concept QuickBooks Online Xero
Department tracking Classes + Locations Tracking Categories (max 2)
Expense entry Purchase / Expense object Bill / Bank Transaction
Vendor matching Vendor entity required Contact entity (shared with customers)
Tax handling TaxCode on line items TaxType on line items, auto-calculated
Multi-currency Requires QBO Plus or Advanced Native, per-organization base currency
Journal entries JournalEntry endpoint ManualJournals endpoint (read-only Journals)

Watch out for API quirks. For example, Xero's Journal API is read-only. The /Journals endpoint does not support POST or PUT. To create journal entries, use /ManualJournals instead. This is the kind of API quirk that costs you a day of debugging if you don't know about it upfront.

For QuickBooks, watch out for subscription-tier limitations. Account creation limits vary by plan (Essentials vs Plus vs Advanced). Classes and locations are only available in Plus and Advanced plans with tier-specific limits. If your customer is on QBO Essentials, your integration will silently fail when it tries to write a Class.

Why Point-to-Point Spend Integrations Fail at Scale

Building a single, reliable integration between Brex and QuickBooks Online is a significant engineering investment. Research indicates that building one custom integration from scratch easily costs upwards of $10,000 in initial development and testing.

But B2B SaaS companies do not stop at one integration. Brex-to-QuickBooks is one integration. Brex-to-Xero is a second. Once you ship QBO, enterprise prospects will demand NetSuite. Each requires separate auth flows, separate field mappings, separate pagination handling, and separate rate limit strategies.

The math works against you quickly. Poor integrations and lack of resources contribute to hundreds of lost orders each year, leading to annual revenue losses in the range of $250,000 to $500,000 for 57 percent of surveyed companies. And that's just the revenue impact—it doesn't count the engineering time consumed by maintenance.

The hidden costs of 1:1 integrations:

  • API Pricing Changes: Both Intuit and Xero have recently overhauled their developer pricing. While the QuickBooks API was historically free, Intuit introduced a tiered pricing model in 2025. Xero is retiring its current revenue share model and introducing five tiers based on connections and data egress volume. Xero has also added a hard policy constraint: data obtained through Xero's APIs cannot be used to train AI models.
  • OAuth Token Management: If two background workers attempt to refresh a QBO token simultaneously, a race condition occurs, invalidating the token and forcing the end-user to re-authenticate manually.
  • Schema Drift: Accounting APIs frequently update their endpoints. Intuit recently tightened Batch endpoint limits and applied new limits to data created via the Class and Department APIs. Xero is migrating all apps to granular scopes after March 2026. Your engineering team has to drop product work to fix the broken sync.
  • Pagination Inconsistencies: Brex might use cursor-based pagination, while an older ERP uses offset/limit. Your ingestion engine has to maintain separate state logic for every API it touches.

Using a Unified API to Sync Brex with Any Accounting Platform

To escape the trap of maintaining dozens of custom API connectors, engineering teams utilize unified APIs. A unified API abstracts the authentication lifecycle, standardizes pagination, and normalizes disparate data models into standard RESTful CRUD operations.

Instead of writing custom logic for QBO's JournalEntry and Xero's BankTransaction, you write a single integration against a unified Expense or Journal model. The unified API handles the translation layer.

flowchart TB
    A["Your Application"] --> B["Unified Accounting API<br>(Single endpoint for expenses,<br>invoices, journal entries)"]
    B --> C["QuickBooks Online"]
    B --> D["Xero"]
    B --> E["NetSuite"]
    B --> F["Zoho Books"]

Truto's architecture takes this further by requiring zero integration-specific code in the database or runtime logic. Complex third-party APIs are exposed as standardized proxy APIs. This means your application interacts with NetSuite, Xero, and QBO using the exact same HTTP requests, while Truto handles the underlying placeholder-driven request building and response extraction.

Furthermore, Truto provides robust third-party webhook ingestion. Instead of building separate listener endpoints for Brex, QBO, and Xero events, Truto ingests the third-party webhooks, verifies the payloads, normalizes the event data, and delivers a unified webhook directly to your application. So when an EXPENSE_PAYMENT_UPDATED event fires from Brex, you receive it in a consistent format regardless of the source platform.

For the broader picture of why B2B SaaS customers demand automated ledger syncing, read our guide on What Are Accounting Integrations?.

Where to Start: A Practical Decision Framework

Before writing any code, answer three questions:

  1. How many accounting platforms do your customers use today? If it's just QuickBooks, a direct integration may be viable. If it's two or more, you're already in unified API territory.
  2. What's your transaction volume per customer per month? High volume against Xero's 5,000 daily call limit demands careful batching, or an abstraction layer that handles it.
  3. Who owns the mapping configuration? If your customers need to map Brex categories to their own GL accounts, you need a configuration UI and a mapping persistence layer. A unified API can provide this out of the box.

The gap between a working demo and a production-grade spend integration is wider than most teams expect. Rate limits, token lifecycle management, ledger mapping, and API deprecations are each individually manageable—but they compound. Whether you build directly against the Brex, QuickBooks, and Xero APIs or use a unified layer, the architecture decisions you make now will determine whether this integration scales with your customer base or becomes the bottleneck that slows down every deal.

FAQ

What are the QuickBooks Online API rate limits for transaction syncing?
QuickBooks Online enforces 500 requests per minute per company (realm ID), with a maximum of 10 concurrent requests per app. Batch operations are throttled at 120 requests per minute, and resource-intensive endpoints are limited to 200 per minute. Exceeding these triggers HTTP 429 errors.
What are the Xero API rate limits in 2026?
Xero limits apps to 60 API calls per minute, 5,000 calls per day, and 5 concurrent requests per organization per app. There is also an app-wide limit of 10,000 calls per minute across all tenants. Exceeding any limit returns HTTP 429 with a Retry-After header.
How do you map Brex transactions to a double-entry accounting ledger?
You must dynamically fetch the destination system's Chart of Accounts, Vendors, Tax Rates, and Tracking Categories. Each Brex transaction must produce a balanced journal entry (debit and credit) with the correct GL account, tax code, and department classification, configured per customer.
Does the Brex API return pending transactions?
No. Brex only returns settled transactions through its Transactions API. For near-real-time notifications, use the Webhooks API with EXPENSE_PAYMENT_UPDATED events.
Does Truto automatically retry rate-limited API calls?
No. Truto normalizes upstream HTTP 429 errors into standard IETF headers and passes them to the caller, giving developers full control over their own exponential backoff and retry logic.

More from our Blog