# Writes, concurrency and rate limits

> QuickBooks replaces the whole entity unless you ask it not to. Xero caps you by the day. NetSuite governs by concurrency and may reject a write for reasons that are not in your payload at all.

Source: https://lopifi.com/apis/writes-and-limits
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

**What happens when you write, and how fast can you go?** Never construct a QuickBooks update payload from scratch. Read, mutate, write back the whole record with its SyncToken.

## Divergences between Xero, QuickBooks Online and NetSuite

### A QuickBooks update deletes the lines you omit

POST an Invoice with only the fields you meant to change and every line on it disappears. The call succeeds. The invoice is now empty and the customer's balance has moved.

**Handling:** Read the current record, mutate it, write the whole thing back with the current SyncToken — or use sparse updates and accept their narrower semantics. A SyncToken mismatch is a real user-visible outcome, not a retryable error: someone else changed the record.

### NetSuite writes can fail for reasons you cannot see

A user event script, a workflow condition, a mandatory custom field or a subsidiary restriction can reject a payload that is structurally perfect. The error text often names an internal field id and nothing else.

**Handling:** Surface the raw NetSuite error to the operator, not a rewritten message. Keep the payload alongside it so support can reproduce. Never retry a rejection automatically.

### The rate limits differ in shape, not just in size

Xero's daily cap (5,000 per organisation, 1,000 on Starter) makes backfill a multi-day job. NetSuite's concurrency governance means parallelism is capped hard and two workers each politely using three connections will trip a five-connection limit. QBO's 500-a-minute rate is the most forgiving of the three per minute — but its reads are now counted per month against a partner-tier allowance.

**Handling:** One token-bucket limiter per source and tenant, shared across every worker, with retries flowing through it. Retry 429 and 5xx with exponential backoff and jitter; never retry a 400.

### Idempotency is opt-in on two and absent on NetSuite

A timeout on a write leaves you unsure whether the document exists. Xero honours an Idempotency-Key header, and QBO a requestid query parameter — unique per company, up to 50 characters (36 in a batch) — that returns the original response instead of writing twice. Both only work if you send them. NetSuite's REST record service has neither, so a blind retry may create a duplicate invoice with a new number, which someone will eventually pay.

**Handling:** Send the Xero key and the QBO requestid on every write, generated once per user action and reused on retry. For NetSuite, write a client-generated reference into a field it stores (tranid, externalid, a custom field) before the call, and search on it after any ambiguous failure instead of retrying blind.
