nxus-qbd 0.8.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +269 -91
  2. package/dist/client.d.ts +81 -77
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +77 -71
  5. package/dist/client.js.map +1 -1
  6. package/dist/contracts.d.ts +1 -1
  7. package/dist/contracts.d.ts.map +1 -1
  8. package/dist/generated/count-capabilities.d.ts +64 -0
  9. package/dist/generated/count-capabilities.d.ts.map +1 -0
  10. package/dist/generated/count-capabilities.js +64 -0
  11. package/dist/generated/count-capabilities.js.map +1 -0
  12. package/dist/generated/index.d.ts +1 -1
  13. package/dist/generated/index.d.ts.map +1 -1
  14. package/dist/generated/index.js +1 -1
  15. package/dist/generated/index.js.map +1 -1
  16. package/dist/generated/resource-capabilities.d.ts +506 -0
  17. package/dist/generated/resource-capabilities.d.ts.map +1 -0
  18. package/dist/generated/resource-capabilities.js +506 -0
  19. package/dist/generated/resource-capabilities.js.map +1 -0
  20. package/dist/generated/types.gen.d.ts +29410 -20818
  21. package/dist/generated/types.gen.d.ts.map +1 -1
  22. package/dist/generated/types.gen.js +80 -0
  23. package/dist/generated/types.gen.js.map +1 -1
  24. package/dist/helpers/enums.d.ts +29 -0
  25. package/dist/helpers/enums.d.ts.map +1 -0
  26. package/dist/helpers/enums.js +38 -0
  27. package/dist/helpers/enums.js.map +1 -0
  28. package/dist/helpers/errors.d.ts +14 -3
  29. package/dist/helpers/errors.d.ts.map +1 -1
  30. package/dist/helpers/errors.js +274 -23
  31. package/dist/helpers/errors.js.map +1 -1
  32. package/dist/helpers/index.d.ts +4 -2
  33. package/dist/helpers/index.d.ts.map +1 -1
  34. package/dist/helpers/index.js +4 -2
  35. package/dist/helpers/index.js.map +1 -1
  36. package/dist/helpers/pagination.d.ts +11 -1
  37. package/dist/helpers/pagination.d.ts.map +1 -1
  38. package/dist/helpers/pagination.js.map +1 -1
  39. package/dist/helpers/response.d.ts +93 -0
  40. package/dist/helpers/response.d.ts.map +1 -0
  41. package/dist/helpers/response.js +84 -0
  42. package/dist/helpers/response.js.map +1 -0
  43. package/dist/index.d.ts +10 -10
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +17 -8
  46. package/dist/index.js.map +1 -1
  47. package/dist/models/core/auth_session.d.ts +1 -1
  48. package/dist/models/core/auth_session.d.ts.map +1 -1
  49. package/dist/models/core/connections.d.ts +1 -1
  50. package/dist/models/core/connections.d.ts.map +1 -1
  51. package/dist/models/core/index.d.ts +3 -3
  52. package/dist/models/core/index.d.ts.map +1 -1
  53. package/dist/models/core/index.js +3 -3
  54. package/dist/models/core/index.js.map +1 -1
  55. package/dist/models/core/qwc_auth_setup.d.ts +1 -1
  56. package/dist/models/core/qwc_auth_setup.d.ts.map +1 -1
  57. package/dist/models/index.d.ts +6 -6
  58. package/dist/models/index.d.ts.map +1 -1
  59. package/dist/models/index.js +5 -5
  60. package/dist/models/index.js.map +1 -1
  61. package/dist/models/qbd/account.d.ts +2 -2
  62. package/dist/models/qbd/account.d.ts.map +1 -1
  63. package/dist/models/qbd/account.js +1 -1
  64. package/dist/models/qbd/account.js.map +1 -1
  65. package/dist/models/qbd/account_tax_line_info.d.ts +1 -1
  66. package/dist/models/qbd/account_tax_line_info.d.ts.map +1 -1
  67. package/dist/models/qbd/ar_refund_credit_card.d.ts +1 -1
  68. package/dist/models/qbd/ar_refund_credit_card.d.ts.map +1 -1
  69. package/dist/models/qbd/bar_code.d.ts +1 -1
  70. package/dist/models/qbd/bar_code.d.ts.map +1 -1
  71. package/dist/models/qbd/bill.d.ts +1 -1
  72. package/dist/models/qbd/bill.d.ts.map +1 -1
  73. package/dist/models/qbd/bill_payment_or_credit.d.ts +1 -1
  74. package/dist/models/qbd/bill_payment_or_credit.d.ts.map +1 -1
  75. package/dist/models/qbd/billing_rate.d.ts +1 -1
  76. package/dist/models/qbd/billing_rate.d.ts.map +1 -1
  77. package/dist/models/qbd/build_assembly.d.ts +1 -1
  78. package/dist/models/qbd/build_assembly.d.ts.map +1 -1
  79. package/dist/models/qbd/charge.d.ts +1 -1
  80. package/dist/models/qbd/charge.d.ts.map +1 -1
  81. package/dist/models/qbd/check.d.ts +1 -1
  82. package/dist/models/qbd/check.d.ts.map +1 -1
  83. package/dist/models/qbd/check_bill_payment.d.ts +1 -1
  84. package/dist/models/qbd/check_bill_payment.d.ts.map +1 -1
  85. package/dist/models/qbd/class_.d.ts +1 -1
  86. package/dist/models/qbd/class_.d.ts.map +1 -1
  87. package/dist/models/qbd/credit_card_bill_payment.d.ts +1 -1
  88. package/dist/models/qbd/credit_card_bill_payment.d.ts.map +1 -1
  89. package/dist/models/qbd/credit_card_charge.d.ts +1 -1
  90. package/dist/models/qbd/credit_card_charge.d.ts.map +1 -1
  91. package/dist/models/qbd/credit_card_credit.d.ts +1 -1
  92. package/dist/models/qbd/credit_card_credit.d.ts.map +1 -1
  93. package/dist/models/qbd/credit_memo.d.ts +1 -1
  94. package/dist/models/qbd/credit_memo.d.ts.map +1 -1
  95. package/dist/models/qbd/currency.d.ts +2 -1
  96. package/dist/models/qbd/currency.d.ts.map +1 -1
  97. package/dist/models/qbd/currency.js +2 -1
  98. package/dist/models/qbd/currency.js.map +1 -1
  99. package/dist/models/qbd/custom_field_definitions.d.ts +1 -1
  100. package/dist/models/qbd/custom_field_definitions.d.ts.map +1 -1
  101. package/dist/models/qbd/custom_fields.d.ts +2 -2
  102. package/dist/models/qbd/custom_fields.d.ts.map +1 -1
  103. package/dist/models/qbd/custom_fields.js +1 -1
  104. package/dist/models/qbd/custom_fields.js.map +1 -1
  105. package/dist/models/qbd/customer.d.ts +2 -2
  106. package/dist/models/qbd/customer.d.ts.map +1 -1
  107. package/dist/models/qbd/customer.js +1 -1
  108. package/dist/models/qbd/customer.js.map +1 -1
  109. package/dist/models/qbd/customer_type.d.ts +1 -1
  110. package/dist/models/qbd/customer_type.d.ts.map +1 -1
  111. package/dist/models/qbd/date_driven_term.d.ts +1 -1
  112. package/dist/models/qbd/date_driven_term.d.ts.map +1 -1
  113. package/dist/models/qbd/deposit.d.ts +1 -1
  114. package/dist/models/qbd/deposit.d.ts.map +1 -1
  115. package/dist/models/qbd/employee.d.ts +2 -2
  116. package/dist/models/qbd/employee.d.ts.map +1 -1
  117. package/dist/models/qbd/employee.js +1 -1
  118. package/dist/models/qbd/employee.js.map +1 -1
  119. package/dist/models/qbd/estimate.d.ts +1 -1
  120. package/dist/models/qbd/estimate.d.ts.map +1 -1
  121. package/dist/models/qbd/index.d.ts +66 -66
  122. package/dist/models/qbd/index.d.ts.map +1 -1
  123. package/dist/models/qbd/index.js +66 -66
  124. package/dist/models/qbd/index.js.map +1 -1
  125. package/dist/models/qbd/inventory_adjustment.d.ts +1 -1
  126. package/dist/models/qbd/inventory_adjustment.d.ts.map +1 -1
  127. package/dist/models/qbd/inventory_site.d.ts +1 -1
  128. package/dist/models/qbd/inventory_site.d.ts.map +1 -1
  129. package/dist/models/qbd/invoice.d.ts +2 -1
  130. package/dist/models/qbd/invoice.d.ts.map +1 -1
  131. package/dist/models/qbd/invoice.js +2 -1
  132. package/dist/models/qbd/invoice.js.map +1 -1
  133. package/dist/models/qbd/item.d.ts +2 -2
  134. package/dist/models/qbd/item.d.ts.map +1 -1
  135. package/dist/models/qbd/item.js +1 -1
  136. package/dist/models/qbd/item.js.map +1 -1
  137. package/dist/models/qbd/item_discount.d.ts +1 -1
  138. package/dist/models/qbd/item_discount.d.ts.map +1 -1
  139. package/dist/models/qbd/item_fixed_asset.d.ts +1 -1
  140. package/dist/models/qbd/item_fixed_asset.d.ts.map +1 -1
  141. package/dist/models/qbd/item_group.d.ts +1 -1
  142. package/dist/models/qbd/item_group.d.ts.map +1 -1
  143. package/dist/models/qbd/item_inventory.d.ts +1 -1
  144. package/dist/models/qbd/item_inventory.d.ts.map +1 -1
  145. package/dist/models/qbd/item_inventory_assembly.d.ts +1 -1
  146. package/dist/models/qbd/item_inventory_assembly.d.ts.map +1 -1
  147. package/dist/models/qbd/item_non_inventory.d.ts +1 -1
  148. package/dist/models/qbd/item_non_inventory.d.ts.map +1 -1
  149. package/dist/models/qbd/item_other_charge.d.ts +1 -1
  150. package/dist/models/qbd/item_other_charge.d.ts.map +1 -1
  151. package/dist/models/qbd/item_payment.d.ts +1 -1
  152. package/dist/models/qbd/item_payment.d.ts.map +1 -1
  153. package/dist/models/qbd/item_receipt.d.ts +1 -1
  154. package/dist/models/qbd/item_receipt.d.ts.map +1 -1
  155. package/dist/models/qbd/item_sales_tax.d.ts +1 -1
  156. package/dist/models/qbd/item_sales_tax.d.ts.map +1 -1
  157. package/dist/models/qbd/item_sales_tax_group.d.ts +1 -1
  158. package/dist/models/qbd/item_sales_tax_group.d.ts.map +1 -1
  159. package/dist/models/qbd/item_service.d.ts +1 -1
  160. package/dist/models/qbd/item_service.d.ts.map +1 -1
  161. package/dist/models/qbd/item_subtotal.d.ts +1 -1
  162. package/dist/models/qbd/item_subtotal.d.ts.map +1 -1
  163. package/dist/models/qbd/journal_entry.d.ts +1 -1
  164. package/dist/models/qbd/journal_entry.d.ts.map +1 -1
  165. package/dist/models/qbd/other_name.d.ts +1 -1
  166. package/dist/models/qbd/other_name.d.ts.map +1 -1
  167. package/dist/models/qbd/payment_method.d.ts +1 -1
  168. package/dist/models/qbd/payment_method.d.ts.map +1 -1
  169. package/dist/models/qbd/payroll_item_non_wage.d.ts +1 -1
  170. package/dist/models/qbd/payroll_item_non_wage.d.ts.map +1 -1
  171. package/dist/models/qbd/payroll_item_wage.d.ts +1 -1
  172. package/dist/models/qbd/payroll_item_wage.d.ts.map +1 -1
  173. package/dist/models/qbd/price_level.d.ts +1 -1
  174. package/dist/models/qbd/price_level.d.ts.map +1 -1
  175. package/dist/models/qbd/purchase_order.d.ts +1 -1
  176. package/dist/models/qbd/purchase_order.d.ts.map +1 -1
  177. package/dist/models/qbd/receive_payment.d.ts +1 -1
  178. package/dist/models/qbd/receive_payment.d.ts.map +1 -1
  179. package/dist/models/qbd/report.d.ts +1 -1
  180. package/dist/models/qbd/report.d.ts.map +1 -1
  181. package/dist/models/qbd/sales_order.d.ts +1 -1
  182. package/dist/models/qbd/sales_order.d.ts.map +1 -1
  183. package/dist/models/qbd/sales_receipt.d.ts +1 -1
  184. package/dist/models/qbd/sales_receipt.d.ts.map +1 -1
  185. package/dist/models/qbd/sales_tax_code.d.ts +1 -1
  186. package/dist/models/qbd/sales_tax_code.d.ts.map +1 -1
  187. package/dist/models/qbd/sales_tax_payment_check.d.ts +1 -1
  188. package/dist/models/qbd/sales_tax_payment_check.d.ts.map +1 -1
  189. package/dist/models/qbd/ship_method.d.ts +1 -1
  190. package/dist/models/qbd/ship_method.d.ts.map +1 -1
  191. package/dist/models/qbd/special_item.d.ts +1 -1
  192. package/dist/models/qbd/special_item.d.ts.map +1 -1
  193. package/dist/models/qbd/tenant_me.d.ts +1 -1
  194. package/dist/models/qbd/tenant_me.d.ts.map +1 -1
  195. package/dist/models/qbd/term.d.ts +1 -1
  196. package/dist/models/qbd/term.d.ts.map +1 -1
  197. package/dist/models/qbd/time_tracking_activity.d.ts +1 -1
  198. package/dist/models/qbd/time_tracking_activity.d.ts.map +1 -1
  199. package/dist/models/qbd/transaction.d.ts +1 -1
  200. package/dist/models/qbd/transaction.d.ts.map +1 -1
  201. package/dist/models/qbd/unit_of_measure_set.d.ts +1 -1
  202. package/dist/models/qbd/unit_of_measure_set.d.ts.map +1 -1
  203. package/dist/models/qbd/vendor.d.ts +1 -1
  204. package/dist/models/qbd/vendor.d.ts.map +1 -1
  205. package/dist/models/qbd/vendor_credit.d.ts +1 -1
  206. package/dist/models/qbd/vendor_credit.d.ts.map +1 -1
  207. package/dist/models/qbd/vendor_type.d.ts +1 -1
  208. package/dist/models/qbd/vendor_type.d.ts.map +1 -1
  209. package/dist/models/qbd/workers_comp_code.d.ts +1 -1
  210. package/dist/models/qbd/workers_comp_code.d.ts.map +1 -1
  211. package/dist/resources/base.d.ts +159 -29
  212. package/dist/resources/base.d.ts.map +1 -1
  213. package/dist/resources/base.js +417 -151
  214. package/dist/resources/base.js.map +1 -1
  215. package/dist/resources/connections.d.ts +17 -4
  216. package/dist/resources/connections.d.ts.map +1 -1
  217. package/dist/resources/connections.js +39 -13
  218. package/dist/resources/connections.js.map +1 -1
  219. package/dist/resources/custom-fields.d.ts +35 -32
  220. package/dist/resources/custom-fields.d.ts.map +1 -1
  221. package/dist/resources/custom-fields.js +121 -119
  222. package/dist/resources/custom-fields.js.map +1 -1
  223. package/dist/resources/reports.d.ts +23 -10
  224. package/dist/resources/reports.d.ts.map +1 -1
  225. package/dist/resources/reports.js +40 -29
  226. package/dist/resources/reports.js.map +1 -1
  227. package/dist/transport.d.ts +61 -10
  228. package/dist/transport.d.ts.map +1 -1
  229. package/dist/transport.js +522 -113
  230. package/dist/transport.js.map +1 -1
  231. package/package.json +8 -4
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # nxus-qbd
1
+ # nxus-qbd v1.0.0
2
2
 
3
3
  Official TypeScript SDK for the [Nxus](https://nx-us.net/docs/) QuickBooks Desktop API.
4
4
 
@@ -45,25 +45,33 @@ const nxus = new NxusClient({
45
45
  timeout: 120_000,
46
46
  });
47
47
 
48
- const page = await nxus.transactions.list({
49
- connectionId: "your-connection-id",
50
- limit: 100,
51
- DetailLevel: "all",
52
- timeout: 30_000,
53
- });
48
+ const page = await nxus.transactions.list(
49
+ {
50
+ limit: 100,
51
+ DetailLevel: "all",
52
+ },
53
+ {
54
+ connectionId: "your-connection-id",
55
+ timeout: 30_000,
56
+ },
57
+ );
54
58
  ```
55
59
 
56
60
  Paginated/list requests can also send a backend timeout hint without changing
57
61
  the SDK's local abort timer:
58
62
 
59
63
  ```ts
60
- const page = await nxus.transactions.list({
61
- connectionId: "your-connection-id",
62
- limit: 100,
63
- DetailLevel: "all",
64
- timeout: 30_000,
65
- timeoutSeconds: 45,
66
- });
64
+ const page = await nxus.transactions.list(
65
+ {
66
+ limit: 100,
67
+ DetailLevel: "all",
68
+ timeoutSeconds: 45,
69
+ },
70
+ {
71
+ connectionId: "your-connection-id",
72
+ timeout: 30_000,
73
+ },
74
+ );
67
75
  ```
68
76
 
69
77
  When `timeoutSeconds` is provided on a `.list()` call, the SDK sends it as the
@@ -98,7 +106,28 @@ back in.
98
106
  For backoff, the standard `Retry-After` response header (seconds or HTTP-date)
99
107
  is honored when present, with `error.retryAfter` (seconds) in the JSON body
100
108
  as a fallback. Local timeouts (the SDK's abort timer) are treated as
101
- cancellations and are not retried.
109
+ cancellations for reads, updates, deletes, and other non-idempotent calls.
110
+ Generic Creates are the exception: their idempotency key makes timeout retries
111
+ safe, so they reuse the same key on the next attempt.
112
+
113
+ ## Safe Create Retries
114
+
115
+ Every generic resource `.create()` call automatically sends a cryptographically
116
+ random `Idempotency-Key`. The SDK generates it once before retries begin and
117
+ uses the same key for every attempt, including `.withResponse.create()`.
118
+
119
+ For a workflow that can resume after the current process exits, supply and
120
+ persist your own key:
121
+
122
+ ```ts
123
+ await nxus.bills.create(request, {
124
+ idempotencyKey: `billing-import-${importJobId}`,
125
+ });
126
+ ```
127
+
128
+ The key is sent only as the `Idempotency-Key` HTTP header, never in the JSON
129
+ body. QuickBooks recovery identifiers and recovery status remain server-owned;
130
+ on a timeout, retry the same logical Create key and follow `x-should-retry`.
102
131
 
103
132
  Configure globally or per-request:
104
133
 
@@ -109,12 +138,16 @@ const nxus = new NxusClient({
109
138
  });
110
139
 
111
140
  // Disable retries for one call
112
- const created = await nxus.invoices.create({
113
- customerRefListId: "...",
114
- invoiceLineAdds: [{ itemRefListId: "...", amount: 100 }],
115
- connectionId: "...",
116
- maxRetries: 0,
117
- });
141
+ const created = await nxus.invoices.create(
142
+ {
143
+ customerRefListId: "...",
144
+ invoiceLineAdds: [{ itemRefListId: "...", amount: 100 }],
145
+ },
146
+ {
147
+ connectionId: "...",
148
+ maxRetries: 0,
149
+ },
150
+ );
118
151
  ```
119
152
 
120
153
  ## Verbose Logging
@@ -126,7 +159,7 @@ and error. Sensitive headers (`Authorization`, `Cookie`, `Set-Cookie`,
126
159
  ```ts
127
160
  const nxus = new NxusClient({
128
161
  apiKey: "sk_live_...",
129
- verbose: true, // logs to console
162
+ verbose: true, // logs to console
130
163
  });
131
164
  ```
132
165
 
@@ -138,8 +171,8 @@ import type { NxusLogger } from "nxus-qbd";
138
171
 
139
172
  const logger: NxusLogger = {
140
173
  debug: (m, c) => myLogger.debug({ event: m, ...c }),
141
- info: (m, c) => myLogger.info({ event: m, ...c }),
142
- warn: (m, c) => myLogger.warn({ event: m, ...c }),
174
+ info: (m, c) => myLogger.info({ event: m, ...c }),
175
+ warn: (m, c) => myLogger.warn({ event: m, ...c }),
143
176
  error: (m, c) => myLogger.error({ event: m, ...c }),
144
177
  };
145
178
 
@@ -181,29 +214,50 @@ const nxus = new NxusClient({
181
214
 
182
215
  `fetchOptions` may also be supplied per request to override the client default.
183
216
 
184
- ## Raw HTTP Access
217
+ ## Response Metadata
185
218
 
186
- When you need direct access to the underlying `Response` — headers, streaming
187
- bodies, custom status handling — use `transport.raw()`. Authentication, default
188
- headers, the timeout, and retries are still applied; only JSON parsing and the
189
- typed error mapping are bypassed.
219
+ Every resource method has a `withResponse` twin that returns the parsed model
220
+ _and_ the response metadata that came with it:
190
221
 
191
222
  ```ts
192
- import { NxusClient } from "nxus-qbd";
223
+ const check = await nxus.checks.create({ payeeId });
224
+ // -> Check
193
225
 
194
- const nxus = new NxusClient({ apiKey: "sk_live_..." });
226
+ const wrapped = await nxus.checks.withResponse.create({ payeeId });
227
+ // -> NxusResponse<Check>
228
+
229
+ wrapped.data; // the same Check
230
+ wrapped.statusCode; // 200
231
+ wrapped.requestId; // 'req_abc123' — quote this in support requests
232
+ wrapped.headers; // frozen, lower-cased names
233
+ ```
234
+
235
+ Both forms are the same call. The plain method is a wrapper that discards the
236
+ metadata, so parsing, retries and error translation are identical — only the
237
+ return value differs. Errors throw `NxusApiError` in both.
195
238
 
196
- const res = await (nxus as unknown as { transport: { raw: (path: string, init?: RequestInit) => Promise<Response> } })
197
- .transport.raw("/api/v1/vendors", { method: "GET" });
239
+ `NxusResponse` is frozen, as is its `headers` object.
198
240
 
199
- console.log(res.status, res.headers.get("x-request-id"));
200
- const stream = res.body; // ReadableStream for large downloads
241
+ The undecoded body is not retained unless you ask for it, since keeping it for
242
+ every call would hold a second full copy of every payload alive:
243
+
244
+ ```ts
245
+ const wrapped = await nxus.vendors.withResponse.retrieve(id, {
246
+ includeRawBody: true,
247
+ });
248
+ wrapped.rawBody; // the exact text the server sent
201
249
  ```
202
250
 
203
- Non-2xx responses are returned, not thrown — the caller is responsible for
204
- checking `response.ok`. Use this only for cases the typed resource methods
205
- can't model (binary downloads, response-header inspection, custom error
206
- semantics).
251
+ The SDK never hands back a `fetch` `Response`. A `Response` body can only be
252
+ read once, so exposing one would mean handing consumers an object that is
253
+ already consumed — and would put the runtime's stream semantics into this
254
+ SDK's contract. Everything useful is copied out while the response is still
255
+ readable, so a `NxusResponse` is safe to keep, log, or pass around.
256
+
257
+ `withResponse.list` returns the **first page** only and does not auto-paginate:
258
+ later pages are separate requests with their own status and headers, which one
259
+ wrapper could not honestly describe. Use `wrapped.data.hasMore` and
260
+ `wrapped.data.cursor` to continue, or the plain `list` for the async iterator.
207
261
 
208
262
  ## Quick Start
209
263
 
@@ -213,7 +267,10 @@ import { NxusClient } from "nxus-qbd";
213
267
  const nxus = new NxusClient({ apiKey: "sk_live_..." });
214
268
 
215
269
  // List vendors
216
- const page = await nxus.vendors.list({ limit: 50, connectionId: "your-connection-id" });
270
+ const page = await nxus.vendors.list(
271
+ { limit: 50 },
272
+ { connectionId: "your-connection-id" },
273
+ );
217
274
 
218
275
  for (const vendor of page.data) {
219
276
  console.log(vendor.name);
@@ -224,21 +281,28 @@ const customer = await nxus.customers.retrieve("80000001-1234567890", {
224
281
  connectionId: "your-connection-id",
225
282
  });
226
283
 
227
- // Create an invoice (flat params)
228
- const invoice = await nxus.invoices.create({
229
- customerRefListId: "80000001-1234567890",
230
- invoiceLineAdds: [
231
- { itemRefListId: "80000002-1234567890", amount: 150.0 },
232
- ],
233
- connectionId: "your-connection-id",
234
- });
235
-
236
- // Update a vendor (ID first, flat fields)
237
- const updated = await nxus.vendors.update("80000001-1234567890", {
238
- name: "Acme (Updated)",
239
- revisionNumber: vendor.revisionNumber,
240
- connectionId: "your-connection-id",
241
- });
284
+ // Create an invoice (payload first, transport options second)
285
+ const invoice = await nxus.invoices.create(
286
+ {
287
+ customerRefListId: "80000001-1234567890",
288
+ invoiceLineAdds: [{ itemRefListId: "80000002-1234567890", amount: 150.0 }],
289
+ },
290
+ {
291
+ connectionId: "your-connection-id",
292
+ },
293
+ );
294
+
295
+ // Update a vendor (ID first, payload second, transport options third)
296
+ const updated = await nxus.vendors.update(
297
+ "80000001-1234567890",
298
+ {
299
+ name: "Acme (Updated)",
300
+ revisionNumber: vendor.revisionNumber,
301
+ },
302
+ {
303
+ connectionId: "your-connection-id",
304
+ },
305
+ );
242
306
 
243
307
  // Delete
244
308
  await nxus.vendors.delete("80000001-1234567890", {
@@ -252,14 +316,113 @@ Every request requires a `connectionId` to identify which QuickBooks Desktop com
252
316
 
253
317
  ```ts
254
318
  // Per-request
255
- const page = await nxus.vendors.list({ limit: 10, connectionId: "your-connection-id" });
256
- const vendor = await nxus.vendors.retrieve("id", { connectionId: "your-connection-id" });
319
+ const page = await nxus.vendors.list(
320
+ { limit: 10 },
321
+ { connectionId: "your-connection-id" },
322
+ );
323
+ const vendor = await nxus.vendors.retrieve("id", {
324
+ connectionId: "your-connection-id",
325
+ });
257
326
 
258
327
  // Global default
259
328
  const nxus = new NxusClient({
260
329
  apiKey: "sk_live_...",
261
- headers: { "X-Connection-Id": "your-connection-id" },
330
+ connectionId: "your-connection-id",
331
+ });
332
+ ```
333
+
334
+ ## Request Options
335
+
336
+ Resource methods that accept a request body or query now prefer a split call shape:
337
+
338
+ ```ts
339
+ await nxus.vendors.create(
340
+ { name: "Acme" },
341
+ { connectionId: "your-connection-id", timeout: 30_000 },
342
+ );
343
+
344
+ await nxus.vendors.list(
345
+ { limit: 50, timeoutSeconds: 45 },
346
+ { connectionId: "your-connection-id" },
347
+ );
348
+
349
+ await nxus.reports.retrieveAging(
350
+ { reportType: "summary" },
351
+ { connectionId: "your-connection-id" },
352
+ );
353
+ ```
354
+
355
+ This keeps transport options out of serialized request bodies and query strings.
356
+
357
+ `authSessions.create()` is the main special case because `connectionId` is a real
358
+ payload field on that endpoint. When you need both the auth-session payload
359
+ connection and a transport-level connection header, pass them separately:
360
+
361
+ ```ts
362
+ await nxus.authSessions.create(
363
+ {
364
+ connectionId: "payload-connection-id",
365
+ redirectUrl: "https://example.com/after-qwc",
366
+ },
367
+ {
368
+ connectionId: "transport-connection-id",
369
+ },
370
+ );
371
+ ```
372
+
373
+ ## Filtering By Active Status
374
+
375
+ QuickBooks returns only active records unless a list request says otherwise.
376
+ `activeStatus` is typed, so the value comes from `QbdActiveStatus` rather than
377
+ a hand-written string:
378
+
379
+ ```ts
380
+ import { NxusClient, QbdActiveStatus } from "nxus-qbd";
381
+
382
+ // Active and inactive records
383
+ const all = await nxus.vendors.list({
384
+ limit: 50,
385
+ activeStatus: QbdActiveStatus.ALL,
386
+ });
387
+
388
+ // Only the records QuickBooks has marked inactive
389
+ const inactive = await nxus.vendors.list({
390
+ limit: 50,
391
+ activeStatus: QbdActiveStatus.INACTIVE_ONLY,
262
392
  });
393
+
394
+ // Omit it entirely for QuickBooks' ActiveOnly default
395
+ const active = await nxus.vendors.list({ limit: 50 });
396
+ ```
397
+
398
+ The wire values are `ActiveOnly`, `InactiveOnly` and `All`, and QuickBooks
399
+ matches them exactly. A near miss such as `"all"` is not rejected as a bad
400
+ request — it travels all the way into qbXML and comes back as QBD error 3110,
401
+ `The enumerated value "all" in the field "ActiveStatus" is unknown or invalid`.
402
+ That is what the enum is for.
403
+
404
+ The enum and its wire string are interchangeable, so both of these compile and
405
+ send the same request, while a typo does not compile at all:
406
+
407
+ ```ts
408
+ await nxus.vendors.list({ activeStatus: QbdActiveStatus.ALL });
409
+ await nxus.vendors.list({ activeStatus: "All" });
410
+
411
+ // @ts-expect-error — "all" is not one of the three literals
412
+ await nxus.vendors.list({ activeStatus: "all" });
413
+ ```
414
+
415
+ A value the compiler only knows as `string` — an environment variable, a CLI
416
+ flag, a database column — cannot be checked that way. `toActiveStatus` closes
417
+ that gap by validating locally instead of letting QuickBooks fail the request:
418
+
419
+ ```ts
420
+ import { toActiveStatus } from "nxus-qbd";
421
+
422
+ const activeStatus = toActiveStatus(process.env.NXUS_ACTIVE_STATUS ?? "All");
423
+ await nxus.vendors.list({ limit: 50, activeStatus });
424
+
425
+ // `isActiveStatus(value)` narrows without throwing.
263
426
  ```
264
427
 
265
428
  ## Auto-Pagination
@@ -268,7 +431,10 @@ List methods return an `AutoPaginationPromise` that supports both manual page na
268
431
 
269
432
  ```ts
270
433
  // Auto-paginate through all records
271
- for await (const vendor of nxus.vendors.list({ limit: 100, timeoutSeconds: 45 })) {
434
+ for await (const vendor of nxus.vendors.list({
435
+ limit: 100,
436
+ timeoutSeconds: 45,
437
+ })) {
272
438
  console.log(vendor.name);
273
439
  }
274
440
 
@@ -289,17 +455,16 @@ while (page.hasNextPage()) {
289
455
 
290
456
  Runnable examples live in [`examples/`](examples/):
291
457
 
292
- | Example | Description |
293
- |---|---|
294
- | [`basic-crud.ts`](examples/basic-crud.ts) | Create, retrieve, update, list, and delete a vendor |
295
- | [`authSetup.ts`](examples/authSetup.ts) | Create a connection, generate a hosted QWC auth flow URL, and check auth status |
296
- | [`auto-pagination.ts`](examples/auto-pagination.ts) | Auto-iteration across pages plus manual page navigation |
297
- | [`connection-scoped.ts`](examples/connection-scoped.ts) | Multi-company isolation with `connectionId` |
298
- | [`error-handling.ts`](examples/error-handling.ts) | Error categorization and typed SDK errors |
299
- | [`pagination-walkthrough.ts`](examples/pagination-walkthrough.ts) | Cursor handling walkthrough |
300
- | [`reports.ts`](examples/reports.ts) | Aging, general detail, and general summary reports |
301
- | [`timeout-tuning.ts`](examples/timeout-tuning.ts) | Default timeout behavior, client-wide overrides, and per-request timeout tuning |
302
-
458
+ | Example | Description |
459
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------- |
460
+ | [`basic-crud.ts`](examples/basic-crud.ts) | Create, retrieve, update, list, and delete a vendor |
461
+ | [`authSetup.ts`](examples/authSetup.ts) | Create a connection, generate a hosted QWC auth flow URL, and check auth status |
462
+ | [`auto-pagination.ts`](examples/auto-pagination.ts) | Auto-iteration across pages plus manual page navigation |
463
+ | [`connection-scoped.ts`](examples/connection-scoped.ts) | Multi-company isolation with `connectionId` |
464
+ | [`error-handling.ts`](examples/error-handling.ts) | Error categorization and typed SDK errors |
465
+ | [`pagination-walkthrough.ts`](examples/pagination-walkthrough.ts) | Cursor handling walkthrough |
466
+ | [`reports.ts`](examples/reports.ts) | Aging, general detail, and general summary reports |
467
+ | [`timeout-tuning.ts`](examples/timeout-tuning.ts) | Default timeout behavior, client-wide overrides, and per-request timeout tuning |
303
468
 
304
469
  ## Error Handling
305
470
 
@@ -312,40 +477,54 @@ try {
312
477
  await nxus.vendors.retrieve("non-existent-id");
313
478
  } catch (err) {
314
479
  if (err instanceof NxusApiError) {
315
- console.log(err.status); // 404
316
- console.log(err.userMessage); // User-safe message
317
- console.log(err.isNotFound); // true
318
- console.log(err.isAuthError); // false
319
- console.log(err.isRateLimited); // false
480
+ console.log(err.status); // 404
481
+ console.log(err.userMessage); // User-safe message
482
+ console.log(err.retryAfter); // Requested retry delay in seconds, if present
483
+ console.log(err.isNotFound); // true
484
+ console.log(err.isAuthError); // false
485
+ console.log(err.isRateLimited); // false
486
+ console.log(err.isRestrictionError); // lifecycle or billing restriction
487
+ console.log(err.isArchivedConnection); // lifecycleState === "archived"
488
+ console.log(err.isConnectorOffline); // QuickBooks Web Connector is not polling
320
489
  }
321
490
  }
322
491
  ```
323
492
 
493
+ Restriction responses also expose `lifecycleState`, `restrictionReason`,
494
+ `restrictionCode`, `requiresPayment`, and `checkoutUrl`. `throwIfError(value)`
495
+ converts an arbitrary generated-client error value into `NxusApiError`.
496
+
497
+ `isConnectorOffline` is worth handling on its own: it means the QuickBooks Web
498
+ Connector is not polling, so the API answered 503 without queuing anything and
499
+ retrying cannot succeed until someone starts the connector. Read `code` to tell
500
+ `QWC_NEVER_CONNECTED` (the `.qwc` file was never installed) from
501
+ `QWC_NOT_CONNECTED` (it authenticated once and has since stopped) — the two want
502
+ different operator instructions.
503
+
324
504
  ## Resources
325
505
 
326
506
  All QuickBooks Desktop resources are available as namespaced properties:
327
507
 
328
- | Category | Resources |
329
- |---|---|
508
+ | Category | Resources |
509
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
330
510
  | **Transactions** | `invoices`, `bills`, `checks`, `deposits`, `estimates`, `creditMemos`, `purchaseOrders`, `salesReceipts`, `journalEntries`, `receivePayments`, `vendorCredits`, `creditCardCharges`, `creditCardBills`, `creditCardCredits`, `charges`, `buildAssemblies`, `arRefundCreditCards`, `salesTaxPaymentChecks`, `itemReceipts`, `CheckBillPayments`, `timeTrackings`, `transactions` |
331
- | **Lists** | `accounts`, `customers`, `vendors`, `employees`, `otherNames`, `currencies`, `terms`, `dateDrivenTerms`, `paymentMethods`, `shipMethods`, `salesTaxCodes`, `priceLevels`, `qbdClasses`, `customerTypes`, `vendorTypes`, `billingRates`, `inventorySites`, `barCodes`, `accountTaxLineInfos`, `unitOfMeasureSets`, `specialItems` |
332
- | **Read-only** | `billToPay` |
333
- | **Items** | `items`, `inventoryItems`, `itemDiscounts`, `itemFixedAssets`, `itemGroups`, `itemInventoryAssemblies`, `itemNonInventory`, `itemOtherCharges`, `itemPayments`, `itemSalesTax`, `itemSalesTaxGroups`, `serviceItems`, `itemSubtotals` |
334
- | **Payroll** | `payrollItemNonWages`, `payrollItemWages`, `workersCompCodes` |
335
- | **Reports** | `reports.retrieveAging()`, `reports.retrieveGeneralDetail()`, `reports.retrieveGeneralSummary()`, `reports.retrieveBudgetSummary()`, `reports.retrieveJob()`, `reports.retrieveTime()`, `reports.retrieveCustomDetail()`, `reports.retrieveCustomSummary()`, `reports.retrievePayrollDetail()` |
336
- | **Core** | `authSessions`, `connections` |
337
-
511
+ | **Lists** | `accounts`, `customers`, `vendors`, `employees`, `otherNames`, `currencies`, `terms`, `dateDrivenTerms`, `paymentMethods`, `shipMethods`, `salesTaxCodes`, `priceLevels`, `qbdClasses`, `customerTypes`, `vendorTypes`, `billingRates`, `inventorySites`, `barCodes`, `accountTaxLineInfos`, `unitOfMeasureSets`, `specialItems` |
512
+ | **Read-only** | `billToPay` |
513
+ | **Items** | `items`, `inventoryItems`, `itemDiscounts`, `itemFixedAssets`, `itemGroups`, `itemInventoryAssemblies`, `itemNonInventory`, `itemOtherCharges`, `itemPayments`, `itemSalesTax`, `itemSalesTaxGroups`, `serviceItems`, `itemSubtotals` |
514
+ | **Payroll** | `payrollItemNonWages`, `payrollItemWages`, `workersCompCodes` |
515
+ | **Reports** | `reports.retrieveAging()`, `reports.retrieveGeneralDetail()`, `reports.retrieveGeneralSummary()`, `reports.retrieveBudgetSummary()`, `reports.retrieveJob()`, `reports.retrieveTime()`, `reports.retrieveCustomDetail()`, `reports.retrieveCustomSummary()`, `reports.retrievePayrollDetail()` |
516
+ | **Core** | `authSessions`, `connections` |
338
517
 
339
518
  ## Custom fields and data extensions
340
519
 
341
520
  QuickBooks Desktop uses the same underlying mechanism for both UI-visible custom fields and application-only integration data:
342
521
 
343
- | QuickBooks concept | SDK/API name | Purpose |
344
- |---|---|---|
345
- | Data extension definition | `DataExtDef` / custom field definition | Describes a field's owner, name, data type, and supported object types. |
346
- | Data extension value | `DataExt` / custom field value | Stores the field's value on one specific QuickBooks list object, transaction, or transaction line. |
522
+ | QuickBooks concept | SDK/API name | Purpose |
523
+ | ------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------- |
524
+ | Data extension definition | `DataExtDefinition` / custom field definition | Describes a field's owner, name, data type, and supported object types. |
525
+ | Data extension value | `DataExt` / custom field value | Stores the field's value on one specific QuickBooks list object, transaction, or transaction line. |
347
526
 
348
- A definition must exist before a value can be written. Definitions are identified by `ownerId + name`; values add the specific QuickBooks target to that composite identity. QuickBooks may omit `DataExtID` for private definitions, so SDK consumers must allow `DataExtDef.id` to be `null`.
527
+ A definition must exist before a value can be written. Definitions are identified by `ownerId + name`; values add the specific QuickBooks target to that composite identity. QuickBooks may omit `DataExtID` for private definitions, so SDK consumers must allow `DataExtDefinition.id` to be `null`.
349
528
 
350
529
  The `ownerId` determines how a definition is used:
351
530
 
@@ -356,14 +535,13 @@ The `assignToObjects` property is therefore optional in the SDK request type, bu
356
535
 
357
536
  The normal workflow is:
358
537
 
359
- 1. Create the `DataExtDef`.
538
+ 1. Create the `DataExtDefinition`.
360
539
  2. Create a `DataExt` value using the same `ownerId` and field name, plus a target such as a Customer `ListID`, an Invoice `TxnID`, or a transaction-line `TxnLineID`.
361
540
  3. Update or delete the value using that same composite identity.
362
541
  4. Delete a private definition only after its values are no longer needed. Public definitions must be managed in the QuickBooks UI because QuickBooks does not support deleting them through `DataExtDefDel`.
363
542
 
364
543
  Public fields are typically used for information users should see or edit in QuickBooks. Private extensions are commonly used for external-system identifiers, synchronization or verification markers, workflow state, migration metadata, and other integration data that should not appear in the QuickBooks UI.
365
544
 
366
-
367
545
  ## License
368
546
 
369
547
  MIT