Skip to content

How to Create a Developer How-To with Runnable Write Examples for QBO & Xero

Learn how to write developer tutorials for QuickBooks Online and Xero APIs that reduce Time to First Call (TTFC) and handle rate limits effectively.

Nachi Raman Nachi Raman · · 8 min read
How to Create a Developer How-To with Runnable Write Examples for QBO & Xero

When enterprise procurement teams evaluate your B2B SaaS product, the real decision maker is rarely the person holding the budget. The true buyer is a lead architect or staff engineer who evaluates your platform by opening your documentation, finding a code snippet, and attempting to run it. If your API documentation is just a static Swagger dump, you will lose the technical evaluation.

This is especially true for accounting integrations. Writing data to QuickBooks Online (QBO) and Xero is notoriously difficult. These APIs enforce strict double-entry accounting rules, complex tax code mappings, and aggressive rate limits. If an evaluating engineer has to spend three hours reverse-engineering undocumented payloads just to create an invoice, they will abandon the integration.

To reduce friction and accelerate adoption, your product team must provide runnable, copy-pasteable write examples. This guide provides a concrete framework for writing developer tutorials that handle the painful realities of QBO and Xero, ensuring your users get to a successful 200 OK in under five minutes.

Why Time to First Call (TTFC) Dictates Accounting API Adoption

Time to First Call (TTFC) is a developer experience metric that measures the elapsed time from a developer signing up for your service to executing their first successful, authenticated API request that returns a non-error response.

Accounting APIs are not simple key-value stores. Creating a valid invoice in QBO requires referencing existing customer IDs, mapping correct tax rates, and ensuring line items balance perfectly. If you leave developers to figure this out on their own, your TTFC will be measured in days, not minutes.

Industry data proves that providing runnable API examples directly impacts adoption. According to Postman's research on API publishers, providing a pre-configured, runnable collection can improve a developer's TTFC by 1.7x to 56x. When developers can instantly see how a payload is structured and watch it execute against a sandbox environment, they skip hours of trial and error.

If you want to learn more about structuring these tutorials at a high level, read our guide on how to publish an end-to-end developer tutorial with API examples. For this guide, we will focus specifically on the technical hurdles of writing data to accounting ledgers.

The Challenges of Writing Data to QBO and Xero

Before you write your tutorial, you must understand the specific technical hurdles your developers will face when interacting with these two platforms. Your code examples must explicitly solve these problems.

Xero's Strict Rate Limits and Egress Pricing

Xero enforces strict rate limits to protect their infrastructure. The limits are hardcoded at 60 calls per minute and 5,000 calls per day per organization. If a developer attempts to bulk-create 100 invoices in a simple for loop, Xero will immediately return HTTP 429 Too Many Requests errors, breaking the integration.

Furthermore, Xero is fundamentally changing its developer economics. In March 2026, Xero is shifting to a tiered pricing model based on API usage and egress data allotments. According to reports from Accounting Today, developers will face overage charges if they exceed their egress GB limits. This makes efficient API calls mandatory. Your tutorials cannot recommend polling or inefficient bulk writes; they must demonstrate batched operations and intelligent caching.

QBO's Strict Technical Review for UI Accuracy

Intuit (the parent company of QuickBooks) maintains a notoriously strict App Assessment process. Writing data to the QBO API is not enough - the data must look correct to the end user inside the QBO graphical interface.

Intuit's technical requirements mandate that any app writing data to QBO must pass a review to verify UI accuracy. If your developer creates an invoice via the API, but the tax rounding is off by one cent, or the line items do not map to the correct income accounts, Intuit will reject the application. Your tutorial must provide exact, validated JSON payloads that are guaranteed to pass this UI review.

The Complexity of References and Line Items

Both APIs require deep relational mapping. You cannot simply pass a string for a customer name. You must first query the API to find the Customer ID, query again to find the Item ID, query a third time to find the Tax Code ID, and then construct a nested JSON payload containing all of these references. Your runnable examples must demonstrate this multi-step orchestration.

How to Create a Developer How-To with Runnable Write Examples

To build a tutorial that actually converts evaluating engineers into active users, follow this four-step framework.

Step 1: Abstract the Authentication Boilerplate

OAuth 2.0 authorization code flows are the death of TTFC. If your tutorial starts with "First, build an OAuth callback handler to exchange your authorization code for a bearer token," you have already lost the reader.

Your runnable examples should assume the developer already has a valid access token. If you are building the integration infrastructure in-house, provide a CLI tool or a developer portal button that generates a temporary sandbox token.

If you are using a unified API platform like Truto, authentication is handled entirely outside of the developer's code. Truto proactively refreshes OAuth tokens with a 30-second buffer before expiry, meaning the developer never has to write token refresh logic. Your tutorial can simply instruct them to pass their Truto API key and the Integrated Account ID.

Step 2: Provide Deterministic, Copy-Pasteable JSON Payloads

Do not provide abstract schema definitions. Provide real, hardcoded JSON payloads that will execute successfully against a standard sandbox environment.

Here is an example of what a raw Xero Invoice payload looks like in a high-quality tutorial. Notice how it explicitly comments on the required reference IDs.

{
  "Invoices": [
    {
      "Type": "ACCREC",
      "Contact": {
        "ContactID": "00000000-0000-0000-0000-000000000000" // Replace with a valid ContactID
      },
      "LineItems": [
        {
          "Description": "Annual SaaS Subscription",
          "Quantity": 1.0,
          "UnitAmount": 1200.00,
          "AccountCode": "200", // Must match an existing revenue account in Xero
          "TaxType": "OUTPUT"
        }
      ],
      "Date": "2026-10-01",
      "DueDate": "2026-10-31",
      "Status": "AUTHORISED"
    }
  ]
}

Step 3: Demonstrate Idempotency

Financial data requires strict idempotency. If a network timeout occurs during an invoice creation, the developer's code might retry the request, resulting in duplicate invoices and ruined financial reporting.

Your runnable examples must show how to use idempotency keys. In Xero, this is often handled by passing a unique InvoiceNumber. If the invoice number already exists, Xero returns a validation error rather than creating a duplicate. In your code samples, explicitly demonstrate how to generate and pass these unique identifiers.

Step 4: Include Runnable Request Code with Error Handling

A bare curl command is not enough. Provide a complete script in Node.js or Python that makes the request, parses the response, and handles the specific errors the accounting API is likely to throw.

// Example: Writing an Invoice to Xero with basic error parsing
async function createXeroInvoice(accessToken, tenantId, invoicePayload) {
  const response = await fetch('https://api.xero.com/api.xro/2.0/Invoices', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Xero-tenant-id': tenantId,
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(invoicePayload)
  });
 
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After');
    throw new Error(`Rate limited by Xero. Retry after ${retryAfter} seconds.`);
  }
 
  if (!response.ok) {
    const errorData = await response.json();
    console.error("Xero Validation Failed:", JSON.stringify(errorData, null, 2));
    throw new Error("Failed to create invoice. Check payload references.");
  }
 
  const data = await response.json();
  return data.Invoices[0];
}

Handling Xero Rate Limits and QBO Errors in Your Code Samples

Your tutorials must prepare developers for production realities. Failing to document how to handle HTTP 429s and validation errors is a severe disservice to your users.

Architecting Exponential Backoff for Xero

Because Xero enforces a strict 60 requests per minute limit, any script that bulk-syncs data will eventually hit a wall. Your tutorial must include a section on exponential backoff.

If you are routing requests through Truto, the platform normalizes upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) following the IETF specification.

Warning

Important Architectural Note: Truto does not automatically retry, throttle, or apply backoff on rate limit errors. When Xero or QBO returns an HTTP 429, Truto passes that error directly to the caller. The caller is strictly responsible for inspecting the ratelimit-reset header and implementing their own retry logic.

Provide a runnable backoff wrapper in your tutorial so developers do not have to write it from scratch. You can read more about this pattern in our guide on best practices for handling API rate limits and retries.

sequenceDiagram
    participant Developer App
    participant Truto Proxy
    participant Xero API
    
    Developer App->>Truto Proxy: POST /proxy/xero/Invoices
    Truto Proxy->>Xero API: POST /api.xro/2.0/Invoices
    Xero API-->>Truto Proxy: 429 Too Many Requests
    Truto Proxy-->>Developer App: 429 (with ratelimit-reset header)
    Note over Developer App: Developer code pauses execution<br>based on ratelimit-reset value
    Developer App->>Truto Proxy: Retry POST /proxy/xero/Invoices
    Truto Proxy->>Xero API: POST /api.xro/2.0/Invoices
    Xero API-->>Truto Proxy: 200 OK
    Truto Proxy-->>Developer App: 200 OK

Handling QBO Stale Object Errors

QuickBooks Online uses a SyncToken system for optimistic concurrency control. Whenever you update a record in QBO, you must provide the current SyncToken. If another process has updated the record since you last fetched it, the SyncToken will not match, and QBO will throw a Stale Object Error.

Your write examples must demonstrate the read-before-write pattern required by QBO. Instruct the developer to fetch the target invoice, extract the SyncToken, apply their updates to the payload, and then execute the POST request.

Scaling Your Tutorials with a Unified Accounting API

Writing a dedicated, end-to-end tutorial for Xero is time-consuming. Writing a second one for QuickBooks Online is frustrating. Writing a third for NetSuite is a massive drain on your engineering resources.

Every accounting platform has entirely different payload structures. Xero calls them ContactID, QBO calls them CustomerRef, and Sage calls them contact_id. If you force your developers to integrate point-to-point, you must maintain separate documentation, separate tutorials, and separate mock payloads for every single provider.

This is why modern B2B SaaS companies use a unified API architecture. A unified API abstracts the differences between QBO, Xero, NetSuite, and Sage into a single, standardized JSON schema.

graph TD
    A[Developer App] -->|Standardized Unified JSON| B(Unified Accounting API)
    B -->|Translates to QBO XML/JSON| C[QuickBooks Online]
    B -->|Translates to Xero JSON| D[Xero]
    B -->|Translates to SuiteQL| E[NetSuite]

Instead of writing ten different tutorials, you write one. You show the developer how to POST a unified Invoice object to the /unified/accounting/invoices endpoint. The unified API engine handles the provider-specific field mapping, date formatting, and authentication injection.

If you are building an integration layer for your product, you should read our guide on how to build a developer cookbook for unified accounting APIs to see exactly how to structure this documentation.

By normalizing the data model, you drastically reduce the cognitive load on the evaluating engineer. They do not need to learn Xero's idiosyncrasies or QBO's SyncToken logic. They learn your unified schema once, and their code instantly works across every accounting provider you support. For a deeper dive into this architecture, review our analysis of the best unified accounting API for B2B SaaS.

Strategic Next Steps for DevRel and Product Teams

Your API documentation is a sales asset. If your tutorials are difficult to run, evaluating engineers will recommend your competitors. To fix your TTFC, audit your current documentation today. Find your most critical write operations (like creating an invoice or syncing an expense) and rewrite the documentation to include hardcoded, copy-pasteable JSON payloads and robust error-handling scripts.

Stop relying on generated Swagger docs to do the heavy lifting. Abstract the authentication, explicitly document the rate limit headers, and prove to the developer that your platform respects their time.

FAQ

What is Time to First Call (TTFC) in API integrations?
Time to First Call (TTFC) is a metric measuring the time from a developer signing up for an API to executing their first successful, authenticated request. It is a critical indicator of developer experience and onboarding friction.
How do I handle Xero API rate limits in my code?
Xero enforces a strict limit of 60 calls per minute. Your code must inspect the rate limit headers returned in HTTP 429 responses and implement an exponential backoff strategy to pause execution before retrying.
Why does QuickBooks Online reject API write requests?
QBO often rejects requests due to missing reference IDs, unbalanced line items, or Stale Object Errors caused by mismatched SyncTokens. Additionally, Intuit requires strict technical reviews to ensure data written via the API renders correctly in their UI.
Does Truto automatically retry failed API calls?
No. Truto normalizes upstream rate limit information into standardized IETF headers but passes HTTP 429 errors directly to the caller. The developer is responsible for implementing their own retry and backoff logic.

More from our Blog