# Money, dates and data conventions
Source: https://www.desktopaccountingapi.com/docs/quickbooks/conventions/

> How the API represents amounts, prices, quantities, dates, timestamps, text, IDs and references, and the validation rules that protect your data.

QuickBooks Desktop has its own types and quirks: two-decimal amounts, five-decimal prices, local-time timestamps, a Windows code page for text. The API keeps those rules visible instead of hiding them, so values round-trip without surprises.

## Field names and shapes

- JSON only (`application/json; charset=utf-8`), except [passthrough](https://www.desktopaccountingapi.com/docs/quickbooks/passthrough/), which also accepts XML.
- Field names are `camelCase`. Enum values are lowercase `snake_case`, such as `"accounts_receivable"`. Error `type` and `code` values are `UPPER_SNAKE_CASE`.
- Every object has `objectType`, such as `"qbd_invoice"`, `"end_user"` or `"list"`.
- Responses always contain every documented field. Missing values are `null`; empty collections are `[]`. Fields that can repeat are always arrays, even with one item. Apart from a QuickBooks object's `id`, `objectType`, `createdAt`, `updatedAt` and `revisionNumber`, any response field can be `null`; see [Damaged and unusual data](#damaged-and-unusual-data).
- Request bodies are strict. An unknown field returns `400 UNKNOWN_PARAMETER` with `param` naming it, so a misspelled `memmo` never gets dropped silently.
- Array query parameters repeat the key: `?customerIds=80000001-1&customerIds=80000002-1`. Comma-joined values are rejected.
- Enums are open: new values can appear in responses. Handle unknown values gracefully.

## Numbers

| QuickBooks type | JSON | Example | Rules |
| --- | --- | --- | --- |
| Amount (totals, balances, line amounts) | decimal string | `"1234.50"` | Up to 13 digits before the point and 2 after. Input may have 0 to 2 decimals and comes back with exactly 2. |
| Price (rates, unit prices) | decimal string | `"12.34567"` | Up to 10 digits before the point and 5 after. Output keeps QuickBooks' digits. |
| Quantity | number | `2.5` | Up to 10 digits before the point and 5 after. |
| Percentage | decimal string | `"7.5"` | `"7.5"` means 7.5 percent. Up to 10 digits before the point and 5 after. |
| Exchange rate | number | `1.3521` | |
| Integer, boolean | integer, boolean | `3`, `true` | |

Three values are JSON numbers although QuickBooks stores them as decimals, matching Conductor: `valueDifference` on inventory adjustments (still limited to 2 decimal places), and `minimumFinanceCharge` and `annualInterestRate` in company preferences.

Money is a string so that `0.1 + 0.2` problems never touch an invoice. Parse it with a decimal type: `decimal.Decimal` in Python, `decimal` in C#, `BigDecimal` in Java, a decimal library in JavaScript. The Python, C# and Java SDKs already return those types.

More decimal places than QuickBooks stores returns `400 DECIMAL_PRECISION_EXCEEDED` with `param` set. We never round for you, because a silently rounded amount is an accounting error that nobody notices.

Output always uses `.` as the decimal separator and no thousands separators, whatever the Windows language settings on the customer's computer. QuickBooks on a computer set to, say, Portuguese or German can write `672,00`, `1.234,56` or `1 234,56`; you receive `"672.00"` and `"1234.56"`.

Amounts are in the transaction's currency. With multicurrency on, objects also carry `exchangeRate` and home-currency amounts such as `balanceRemainingInHomeCurrency`. See [Editions, versions and features](https://www.desktopaccountingapi.com/docs/quickbooks/editions-and-features/#multicurrency).

## Dates and times

| Kind | Format | Example |
| --- | --- | --- |
| Accounting dates (`transactionDate`, `dueDate`, `shippingDate`) | `YYYY-MM-DD`, no time zone | `"2026-10-05"` |
| QuickBooks timestamps (`createdAt`, `updatedAt` on QuickBooks objects) | ISO 8601 with the customer computer's UTC offset | `"2026-10-05T09:14:03-07:00"` |
| Our timestamps (requests, end users, events, `cursorExpiresAt`) | ISO 8601 UTC with milliseconds | `"2026-10-05T16:14:03.120Z"` |

Accounting dates are calendar dates. An invoice dated `2026-10-05` is dated October 5 everywhere; do not convert it to a time zone.

QuickBooks timestamps keep the offset QuickBooks reports. We do not convert them to UTC, because QuickBooks' own filters work on that local clock.

Date filters such as `updatedAfter`, `updatedBefore`, `transactionDateFrom` and `deletedAfter` accept:

- a date: `2026-10-05`. Lower bounds mean the start of that day, upper bounds the end;
- a local date-time without an offset: `2026-10-05T09:00:00`, read in the customer computer's time zone;
- a date-time with an offset: `2026-10-05T16:00:00Z`, converted to the computer's time zone.

Many list and report endpoints also accept date macros such as `this_month`, `last_quarter` or `this_year_to_date`, which QuickBooks evaluates on the customer's computer.

## Text

- US editions of QuickBooks Desktop store text in the Windows-1252 code page, not Unicode. That covers Latin letters with accents (`é`, `ñ`, `ü`, `Å`), `€`, `£`, `©`, `µ`, the no-break space (U+00A0), curly quotes and dashes. They are stored exactly as you write them.
- Any other character returns `400 UNSUPPORTED_CHARACTER` before anything is sent: emoji, Greek, Cyrillic and Asian scripts, control characters, line and paragraph separators (U+2028, U+2029), and fullwidth forms such as `＆` and `＜`. The error names the field in `param`, and `details` gives the code point, the character, its position and, where there is an obvious one, a `suggestion` (`&` for `＆`, a plain space for a narrow no-break space, `µ` for the Greek `μ`).
- We do not fold, strip or replace characters for you, because a silently changed name causes duplicate-name and matching bugs later. One exception changes no text: a letter written as a base letter plus a combining accent (common in text from macOS) is sent in its composed form, so `e` + `◌́` becomes `é`.
- Text you read back is returned as QuickBooks stores it. Characters QuickBooks wrote as Windows-1252 byte references, such as `&#146;` for `’`, come back as the characters they stand for.
- Each text field has a maximum length from the QuickBooks schema, shown in the API reference. Longer values return `400 STRING_TOO_LONG` before anything is sent.
- Send plain text. We escape XML special characters such as `&` and `<` for you.
- QuickBooks stores a line break as a single line feed (`\n`). The API passes a carriage return through to QuickBooks unchanged, and QuickBooks converts `\r\n` to `\n` when it saves the text. So `"line 1\r\nline 2"` is stored and returned by later reads as `"line 1\nline 2"`. Text sent with `\n` alone is stored exactly. If you compare text you sent with text you read back, normalize `\r\n` to `\n` first.

- Name searches (`names`, `fullNames`, `nameContains`) are case-insensitive, as in QuickBooks.

## Damaged and unusual data

Company files damaged by crashes, imports or old QuickBooks versions sometimes return records with elements missing or values in the wrong format. The API reads such responses without failing them and without dropping records:

- A missing value is `null`, even where the QuickBooks schema says the element is always present (an invoice without a customer, a line without an `id`, a transaction without `subtotal`).
- A value that cannot be read, such as an amount `12,3x`, a date `0000-00-00` or a boolean `maybe`, is `null`. An enum value with no letters or digits (QuickBooks has returned `???`) is `"unknown"`.
- Malformed XML text, such as a bare `&` in a memo, is kept as written.

Each of these is reported. The `Daapi-Warnings` response header counts them, and [`GET /v1/requests/{id}`](https://www.desktopaccountingapi.com/docs/guides/request-lifecycle/) lists each one in `warnings` with `code` (`QBD_VALUE_UNREADABLE` or `QBD_MARKUP_REPAIRED`), the `path` of the affected value (`data[2].subtotal`) and a `message` that quotes what QuickBooks sent. If you see them often for one customer, ask them to run Verify Data and Rebuild Data in QuickBooks.

Only a missing or unreadable `id`, `createdAt`, `updatedAt` or `revisionNumber` on a QuickBooks object fails the response, with [`QBD_RESPONSE_UNREADABLE`](https://www.desktopaccountingapi.com/docs/errors/#qbd_response_unreadable), because a record that cannot be identified cannot be updated safely.

## IDs

- QuickBooks IDs (`id` on lists and transactions, line `id`s) pass through unchanged. They look like `80000012-1730312001` and are at most 36 characters. Store them as strings.
- IDs are unique within one company file, not across files. Store them together with the end user ID.
- Our own IDs carry a type prefix: `eu_` end users, `conn_` connections, `req_` requests, `authsess_` auth sessions, `evt_` webhook events, `proj_` projects, `org_` organizations. They are sortable by creation time.

## References

Inputs reference other records by ID, in fields named `<thing>Id`: `customerId`, `itemId`, `classId`, `accountId`. Outputs return a reference object:

```json
"customer": { "id": "80000012-1730312001", "fullName": "Acme Supply:Warehouse job" }
```

`fullName` is the record's full hierarchical name at the time of the response, with levels separated by colons. Inputs do not accept names, because names change and can be ambiguous across hierarchy levels. Look up an ID by name with a list filter such as `fullNames`, then use the ID.

A reference to an ID that does not exist, or that points to the wrong kind of record, returns `422 QBD_REFERENCE_NOT_FOUND` with `param` naming the field.

## Validation errors

| Code | When |
| --- | --- |
| [`INVALID_PARAMETER`](https://www.desktopaccountingapi.com/docs/errors/#invalid_parameter) | A value breaks the schema: wrong type, out of range, bad format |
| [`UNKNOWN_PARAMETER`](https://www.desktopaccountingapi.com/docs/errors/#unknown_parameter) | A field the operation does not accept |
| [`DECIMAL_PRECISION_EXCEEDED`](https://www.desktopaccountingapi.com/docs/errors/#decimal_precision_exceeded) | Too many decimal places |
| [`STRING_TOO_LONG`](https://www.desktopaccountingapi.com/docs/errors/#string_too_long) | Text longer than QuickBooks allows |
| [`UNSUPPORTED_CHARACTER`](https://www.desktopaccountingapi.com/docs/errors/#unsupported_character) | A character QuickBooks cannot store |
| [`FIELD_NOT_CLEARABLE`](https://www.desktopaccountingapi.com/docs/errors/#field_not_clearable) | `null` on a field QuickBooks cannot clear |

All of them come back before the request is queued, with `outcome: "not_applied"`. Nothing reaches QuickBooks.
