@go-labs-sg/bb 2.41.0 → 2.43.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.
package/README.md CHANGED
@@ -22,6 +22,39 @@ The shared API rechecks existing records at submission. Canonical matches reuse
22
22
 
23
23
  `bb company use` and `bb company create` are state-changing, potentially external-writing commands. In non-interactive mode their existing permission gates require `--allow-state-change --allow-external-write`. Deploy the backend before publishing this CLI change. See [company discovery details](../api/docs/company-discovery.md) for limits and retry behaviour.
24
24
 
25
+ ## Record a payment made outside Budget Builder
26
+
27
+ Admins can record an already-made payment on an APPROVED bill or claim without transferring money or emailing the supplier/claimant:
28
+
29
+ ```bash
30
+ bb bill payment accounts
31
+ bb bill payment record-external <billId> \
32
+ --paymentReference 2343190532 \
33
+ --paymentDate 2026-09-01 \
34
+ --paymentAccount <quickbooks-account-id> \
35
+ --paymentProof receipt.pdf
36
+ ```
37
+
38
+ Choose the bank or card account actually used (including `Events Requisitions`); no account or date is defaulted. Omit `--paymentProof` if a payment-proof PDF is already attached. In non-interactive use, add `--allow-state-change --allow-external-write --allow-financial-write`; no `--allow-email` is needed. The UI offers the same **Record external payment** action next to ordinary **Mark paid**.
39
+
40
+ BB marks the bill PAID immediately and queues durable QuickBooks reconciliation. A settled zero-balance QBO bill reuses its existing BillPayment IDs. Otherwise reconciliation creates a payment with the specified date/account and a stable provider request ID. Partially settled or inconsistent QBO bills require manual reconciliation; BB never guesses. Inspect failed/pending work in Integration Queue and **do not pay the bill again**. Exact retries with the same reference/date/account return the recorded settlement; changed details conflict. Ordinary Mark paid keeps its existing payment-advice workflow.
41
+
42
+ `bb update-bill --payload '{"id":"<billId>","comment":"Already paid; do not pay again"}'` now accepts a partial payload. Omitted fields are preserved; comment-only updates do not change financial data or sync QBO, and are allowed on approved/paid bills for the creator or an admin. Financial edits retain their draft/rejected restrictions.
43
+
44
+ Deployment prerequisite: apply the Budget Builder Prisma schema additions (`Bill.externalPayment` JSON and `EXTERNAL_PAYMENT` operation enum) before deploying the API/web/workers; deploy the backend before publishing the CLI. This feature does not modify existing paid bills or repair historical QBO entries automatically.
45
+
46
+ ## Payload help and uncertain writes
47
+
48
+ Run `bb <command> --help` (for example, `bb create-item --help`) to see required and optional `--payload` fields and an example JSON object. Item creation and updates accept a finite numeric `cost` and convert it to the API's decimal-string input. Validation errors identify the affected field; unsupported QuickBooks name characters are listed explicitly.
49
+
50
+ If `create-budget` reports an uncertain outcome (including Prisma P2028 or a network interruption), **do not retry immediately**. Run `bb list-budgets --projectId <project-id>` and check for the budget name first; the write may have committed even though the CLI did not receive a successful response. This check is not an idempotency guarantee when another budget has the same name.
51
+
52
+ A failed `create-supplier` request may likewise have committed. Inspect `bb list-suppliers --name <name>` and matching supplier details before retrying; names alone do not identify one attempt. If supplier creation succeeded but its separate approval request failed or returned no approval IDs, inspect that supplier's approvals by ID and retry only the approval step if needed. Do not create the supplier again. The CLI confirms the combined supplier-and-approval workflow before the first write.
53
+
54
+ `create-budget-approval` and `create-estimate` accept `--companyPayload`, `--contactPayload`, and `--eventPayload` as JSON objects. The CLI rejects non-object JSON; the API validates required fields.
55
+
56
+ `create-project` requires an existing Asana Deals lead task. In non-interactive runs pass `--asanaTaskId`; interactive runs can select a match with `--asanaSearch`. The Slack channel is resolved from the task unless all Slack channel flags are provided. For a new direct client, create the lead task in the website form first.
57
+
25
58
  ## Shared catalogue editing
26
59
 
27
60
  All active authenticated users can edit suppliers, inventory items and item categories. Normal-user supplier updates submit a revision for approval in the shared API; item/category edits apply immediately. Lead/Admin supplier edits bypass human review. `bb supplier update` returns the server-owned approval/synchronization result without issuing another approval request. New supplier usage stays on hold during review and linked QuickBooks synchronization; existing usage continues with the last approved details until the edit is approved. Creator identity and delete/archive permissions are unchanged.
@@ -790,6 +790,18 @@
790
790
  {
791
791
  "name": "--allow-financial-write",
792
792
  "description": "Allow financial-record changes in non-interactive use."
793
+ },
794
+ {
795
+ "name": "--companyPayload <json>",
796
+ "description": "Company update JSON object with id, name, and website fields."
797
+ },
798
+ {
799
+ "name": "--contactPayload <json>",
800
+ "description": "Contact update JSON object with companyId, title, firstName, lastName, email, and mobile fields."
801
+ },
802
+ {
803
+ "name": "--eventPayload <json>",
804
+ "description": "Event timing JSON object with date, startTime, and endTime fields."
793
805
  }
794
806
  ],
795
807
  "argumentMode": "legacy-passthrough",
@@ -840,6 +852,18 @@
840
852
  {
841
853
  "name": "--allow-financial-write",
842
854
  "description": "Allow financial-record changes in non-interactive use."
855
+ },
856
+ {
857
+ "name": "--companyPayload <json>",
858
+ "description": "Company update JSON object with id, name, and website fields."
859
+ },
860
+ {
861
+ "name": "--contactPayload <json>",
862
+ "description": "Contact update JSON object with companyId, title, firstName, lastName, email, and mobile fields."
863
+ },
864
+ {
865
+ "name": "--eventPayload <json>",
866
+ "description": "Event timing JSON object with date, startTime, and endTime fields."
843
867
  }
844
868
  ],
845
869
  "argumentMode": "legacy-passthrough",
@@ -2237,7 +2261,7 @@
2237
2261
  {
2238
2262
  "path": ["bill", "update"],
2239
2263
  "legacyAliases": ["update-bill", "update_bill"],
2240
- "summary": "Update a bill or claim; payload must include id. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.",
2264
+ "summary": "Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.",
2241
2265
  "globalOptions": [
2242
2266
  {
2243
2267
  "name": "--help",
@@ -2437,6 +2461,112 @@
2437
2461
  "effects": ["state-change", "email", "financial-write"],
2438
2462
  "legacyTarget": "update-bill-status"
2439
2463
  },
2464
+ {
2465
+ "path": ["bill", "payment", "record-external"],
2466
+ "legacyAliases": [
2467
+ "record-external-bill-payment",
2468
+ "record_external_bill_payment"
2469
+ ],
2470
+ "summary": "Record an already-made payment on an APPROVED bill or claim, with no email and no money transfer. Requires <billId> --paymentReference --paymentDate YYYY-MM-DD --paymentAccount <QBO account ID> [--paymentProof receipt.pdf]. Reuses settled QBO payment links or queues one dated payment from the selected account. Exact retries are safe; do not pay again while reconciliation is pending.",
2471
+ "globalOptions": [
2472
+ {
2473
+ "name": "--help",
2474
+ "description": "Show help for this command."
2475
+ },
2476
+ {
2477
+ "name": "--quiet",
2478
+ "description": "Suppress non-error diagnostics."
2479
+ },
2480
+ {
2481
+ "name": "--debug",
2482
+ "description": "Emit sanitized diagnostic traces."
2483
+ },
2484
+ {
2485
+ "name": "--api-url",
2486
+ "description": "Override the Budget Builder API base URL."
2487
+ },
2488
+ {
2489
+ "name": "--no-browser",
2490
+ "description": "Print the authorization URL without opening a browser."
2491
+ },
2492
+ {
2493
+ "name": "--allow-state-change",
2494
+ "description": "Allow a Budget Builder state change in non-interactive use."
2495
+ },
2496
+ {
2497
+ "name": "--allow-email",
2498
+ "description": "Allow sending email in non-interactive use."
2499
+ },
2500
+ {
2501
+ "name": "--allow-external-write",
2502
+ "description": "Allow writes to external systems in non-interactive use."
2503
+ },
2504
+ {
2505
+ "name": "--allow-delete",
2506
+ "description": "Allow deleting data in non-interactive use."
2507
+ },
2508
+ {
2509
+ "name": "--allow-financial-write",
2510
+ "description": "Allow financial-record changes in non-interactive use."
2511
+ }
2512
+ ],
2513
+ "argumentMode": "legacy-passthrough",
2514
+ "effects": ["state-change", "external-write", "financial-write"],
2515
+ "legacyTarget": "record-external-bill-payment"
2516
+ },
2517
+ {
2518
+ "path": ["bill", "payment", "accounts"],
2519
+ "legacyAliases": [
2520
+ "list-external-payment-accounts",
2521
+ "list_external_payment_accounts"
2522
+ ],
2523
+ "summary": "List active QuickBooks bank and credit-card account IDs for recording external payments (admin only).",
2524
+ "globalOptions": [
2525
+ {
2526
+ "name": "--help",
2527
+ "description": "Show help for this command."
2528
+ },
2529
+ {
2530
+ "name": "--quiet",
2531
+ "description": "Suppress non-error diagnostics."
2532
+ },
2533
+ {
2534
+ "name": "--debug",
2535
+ "description": "Emit sanitized diagnostic traces."
2536
+ },
2537
+ {
2538
+ "name": "--api-url",
2539
+ "description": "Override the Budget Builder API base URL."
2540
+ },
2541
+ {
2542
+ "name": "--no-browser",
2543
+ "description": "Print the authorization URL without opening a browser."
2544
+ },
2545
+ {
2546
+ "name": "--allow-state-change",
2547
+ "description": "Allow a Budget Builder state change in non-interactive use."
2548
+ },
2549
+ {
2550
+ "name": "--allow-email",
2551
+ "description": "Allow sending email in non-interactive use."
2552
+ },
2553
+ {
2554
+ "name": "--allow-external-write",
2555
+ "description": "Allow writes to external systems in non-interactive use."
2556
+ },
2557
+ {
2558
+ "name": "--allow-delete",
2559
+ "description": "Allow deleting data in non-interactive use."
2560
+ },
2561
+ {
2562
+ "name": "--allow-financial-write",
2563
+ "description": "Allow financial-record changes in non-interactive use."
2564
+ }
2565
+ ],
2566
+ "argumentMode": "legacy-passthrough",
2567
+ "effects": [],
2568
+ "legacyTarget": "list-external-payment-accounts"
2569
+ },
2440
2570
  {
2441
2571
  "path": ["bill", "payment", "patch"],
2442
2572
  "legacyAliases": ["patch-bill-payment", "patch_bill_payment"],
@@ -5504,7 +5634,7 @@
5504
5634
  {
5505
5635
  "path": ["project", "create"],
5506
5636
  "legacyAliases": ["create-project", "create_project"],
5507
- "summary": "Create Project.",
5637
+ "summary": "Create a project linked to an existing Asana Deals lead task. Supply --asanaTaskId in non-interactive use; interactive use searches for and selects a lead task (optionally --asanaSearch). The Slack channel is resolved from the selected Asana task unless all three Slack channel flags are supplied. For a new direct client, create the lead task using the website form first.",
5508
5638
  "globalOptions": [
5509
5639
  {
5510
5640
  "name": "--help",
@@ -161,6 +161,11 @@ Legacy aliases: `send-estimate-to-contact-person`, `send_estimate_to_contact_per
161
161
 
162
162
  Effects: state-change, email.
163
163
 
164
+ Payload fields (--payload JSON)
165
+ Required: estimateId: string; budgetId: string; to: email; cc: email[]; replyTo: email; subject: string; content: HTML string; signature: HTML string
166
+ Optional: estimateDocNumber: string
167
+ Example: bb send-estimate-to-contact-person --payload '{"estimateId":"<estimate-id>","budgetId":"<budget-id>","to":"client@example.com","cc":[],"replyTo":"team@example.com","subject":"Estimate","content":"<p>Attached estimate</p>","signature":"<p>Team</p>"}'
168
+
164
169
  ## `bb budget create`
165
170
 
166
171
  Create Budget.
@@ -169,6 +174,11 @@ Legacy aliases: `create-budget`, `create_budget`.
169
174
 
170
175
  Effects: state-change.
171
176
 
177
+ Payload fields (--payload JSON)
178
+ Required: name: string; budget: decimal string; paymentTerm: string; categoryId: string; projectId: string
179
+ Optional: sourceBudgetId: string; unavailableItemReviewAcknowledged: boolean (only after review); pipedriveDealId: string
180
+ Example: bb create-budget --payload '{"name":"Event budget","budget":"1500","paymentTerm":"Net 30","categoryId":"<category-id>","projectId":"<project-id>"}'
181
+
172
182
  ## `bb budget update`
173
183
 
174
184
  Update Budget.
@@ -177,6 +187,11 @@ Legacy aliases: `update-budget`, `update_budget`.
177
187
 
178
188
  Effects: state-change.
179
189
 
190
+ Payload fields (--payload JSON)
191
+ Required: id: string; name: string; budget: decimal string; paymentTerm: string; categoryId: string; projectId: string
192
+ Optional: sourceBudgetId: string; pipedriveDealId: string
193
+ Example: bb update-budget --payload '{"id":"<budget-id>","name":"Event budget","budget":"1500","paymentTerm":"Net 30","categoryId":"<category-id>","projectId":"<project-id>"}'
194
+
180
195
  ## `bb budget delete`
181
196
 
182
197
  Delete Budget.
@@ -273,6 +288,11 @@ Legacy aliases: `update-budget-commission`, `update_budget_commission`.
273
288
 
274
289
  Effects: state-change, financial-write.
275
290
 
291
+ Payload fields (--payload JSON)
292
+ Required: budgetId: string; name: string; percentage: decimal string; totalSellingAfterDiscount: number
293
+ Optional: none
294
+ Example: bb update-budget-commission --payload '{"budgetId":"<budget-id>","name":"Sales commission","percentage":"10","totalSellingAfterDiscount":1500}'
295
+
276
296
  ## `bb budget discount update`
277
297
 
278
298
  Update Budget Discount.
@@ -281,6 +301,11 @@ Legacy aliases: `update-budget-discount`, `update_budget_discount`.
281
301
 
282
302
  Effects: state-change, financial-write.
283
303
 
304
+ Payload fields (--payload JSON)
305
+ Required: budgetId: string; name: string; type: percentage|amount; value: decimal string; totalSellingBeforeDiscount: number
306
+ Optional: none
307
+ Example: bb update-budget-discount --payload '{"budgetId":"<budget-id>","name":"Discount","type":"amount","value":"100","totalSellingBeforeDiscount":1500}'
308
+
284
309
  ## `bb budget commission delete`
285
310
 
286
311
  Delete Budget Commission.
@@ -353,6 +378,11 @@ Legacy aliases: `create-bill`, `create_bill`.
353
378
 
354
379
  Effects: state-change, email, external-write, financial-write.
355
380
 
381
+ Payload fields (--payload JSON)
382
+ Required: budgetId: string; projectId: string; supplierId: string; amount: number (ex-GST); budgetItemIds: string[]; isClaimable: boolean; supplier bills: quotationIds: string[] or quotationAllocations: {budgetItemId, quotationId, amount}[] (unless --quotation-exempt)
383
+ Optional: lineAmounts: {budgetItemId, amount}[] (required with quotationAllocations); attachments: {id,name,key,size}[]; invoiceNumber: string; invoiceDate: ISO date; draftOnly: boolean; alreadyPaid: boolean; extractedAmount: number
384
+ Example: bb create-bill --payload '{"budgetId":"<budget-id>","projectId":"<project-id>","supplierId":"<supplier-id>","amount":1800,"budgetItemIds":["<budget-item-id>"],"isClaimable":false,"quotationIds":["<quotation-id>"],"attachments":[]}'
385
+
356
386
  ## `bb bill selection validate`
357
387
 
358
388
  Validate the approved supplier and selected bill line items.
@@ -361,6 +391,11 @@ Legacy aliases: `validate-bill-selection`, `validate_bill_selection`.
361
391
 
362
392
  Effects: none.
363
393
 
394
+ Payload fields (--payload JSON)
395
+ Required: projectId: string; supplierId: string; budgetItemIds: string[]
396
+ Optional: quotationIds: string[] for supplier bills; isClaimable: boolean; amount: number; lineAmounts: {budgetItemId, amount}[]; quotationAllocations: {budgetItemId, quotationId, amount}[] (requires amount and lineAmounts)
397
+ Example: bb validate-bill-selection --payload '{"projectId":"<project-id>","supplierId":"<supplier-id>","budgetItemIds":["<budget-item-id>"],"quotationIds":["<quotation-id>"]}'
398
+
364
399
  ## `bb bill quotation link`
365
400
 
366
401
  Link Bill Quotations.
@@ -369,14 +404,24 @@ Legacy aliases: `link-bill-quotations`, `link_bill_quotations`, `billId`.
369
404
 
370
405
  Effects: state-change, financial-write.
371
406
 
407
+ Payload fields (--payload JSON)
408
+ Required: positional <billId>; quotationIds: string[] or quotationAllocations: {budgetItemId, quotationId, amount}[]
409
+ Optional: none (legacy quotationId is not supported)
410
+ Example: bb link-bill-quotations <billId> --payload '{"quotationIds":["<quotation-id>"]}'
411
+
372
412
  ## `bb bill update`
373
413
 
374
- Update a bill or claim; payload must include id. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.
414
+ Update a bill or claim with a partial payload including id; omitted fields are preserved. Comment-only updates are allowed on approved/paid bills without altering financial data or QuickBooks. All amount fields exclude GST: amount is the portion billed; extractedAmount is the full invoice subtotal; lineAmounts and quotationAllocations also exclude GST. Example: 1800 + 162 GST = 1962 total requires amount=1800 and extractedAmount=1800 for a full bill. The CLI does not strip GST from input. Re-read and verify both amount fields and allocations after correcting a gross/net mistake.
375
415
 
376
416
  Legacy aliases: `update-bill`, `update_bill`.
377
417
 
378
418
  Effects: state-change, external-write, financial-write.
379
419
 
420
+ Payload fields (--payload JSON)
421
+ Required: id: string; budgetId: string; projectId: string; supplierId: string; amount: number (ex-GST); budgetItemIds: string[]; isClaimable: boolean
422
+ Optional: quotationIds: string[]; quotationAllocations: {budgetItemId, quotationId, amount}[]; lineAmounts: {budgetItemId, amount}[]; attachments: {id,name,key,size}[]; invoiceNumber: string; invoiceDate: ISO date
423
+ Example: bb update-bill --payload '{"id":"<bill-id>","budgetId":"<budget-id>","projectId":"<project-id>","supplierId":"<supplier-id>","amount":1800,"budgetItemIds":["<budget-item-id>"],"isClaimable":false,"quotationIds":["<quotation-id>"],"attachments":[]}'
424
+
380
425
  ## `bb bill payment-evidence update`
381
426
 
382
427
  Update Bill Payment Evidence.
@@ -385,6 +430,11 @@ Legacy aliases: `update-bill-payment-evidence`, `update_bill_payment_evidence`.
385
430
 
386
431
  Effects: state-change, financial-write.
387
432
 
433
+ Payload fields (--payload JSON)
434
+ Required: id: string; paymentReference: string; paymentProofAttachments: {id,name (PDF),key,size}[] (at least one)
435
+ Optional: none
436
+ Example: bb update-bill-payment-evidence --payload '{"id":"<bill-id>","paymentReference":"TRANSFER-123","paymentProofAttachments":[{"id":"<attachment-id>","name":"receipt.pdf","key":"<staged-key>","size":1000}]}'
437
+
388
438
  ## `bb bill delete`
389
439
 
390
440
  Delete Bill.
@@ -401,6 +451,22 @@ Legacy aliases: `update-bill-status`, `update_bill_status`.
401
451
 
402
452
  Effects: state-change, email, financial-write.
403
453
 
454
+ ## `bb bill payment record-external`
455
+
456
+ Record an already-made payment on an APPROVED bill or claim, with no email and no money transfer. Requires <billId> --paymentReference --paymentDate YYYY-MM-DD --paymentAccount <QBO account ID> [--paymentProof receipt.pdf]. Reuses settled QBO payment links or queues one dated payment from the selected account. Exact retries are safe; do not pay again while reconciliation is pending.
457
+
458
+ Legacy aliases: `record-external-bill-payment`, `record_external_bill_payment`.
459
+
460
+ Effects: state-change, external-write, financial-write.
461
+
462
+ ## `bb bill payment accounts`
463
+
464
+ List active QuickBooks bank and credit-card account IDs for recording external payments (admin only).
465
+
466
+ Legacy aliases: `list-external-payment-accounts`, `list_external_payment_accounts`.
467
+
468
+ Effects: none.
469
+
404
470
  ## `bb bill payment patch`
405
471
 
406
472
  Patch Bill Payment.
@@ -513,6 +579,11 @@ Legacy aliases: `create-quotation`, `create_quotation`.
513
579
 
514
580
  Effects: state-change.
515
581
 
582
+ Payload fields (--payload JSON)
583
+ Required: projectId: string; budgetId: string; supplierId: string; budgetItemIds: string[]; amountWithoutGst: number; gstAmount: number; attachments: array (uploaded attachment)
584
+ Optional: lineAmounts: {budgetItemId, amount}[] (required for multiple budget items)
585
+ Example: bb create-quotation --payload '{"projectId":"<project-id>","budgetId":"<budget-id>","supplierId":"<supplier-id>","budgetItemIds":["<budget-item-id>"],"amountWithoutGst":1200,"gstAmount":0,"attachments":[{"id":"<attachment-id>","name":"quote.pdf","key":"<staged-key>","size":1000}]}'
586
+
516
587
  ## `bb quotation update`
517
588
 
518
589
  Update a DRAFT or REJECTED quotation using --payload JSON with id and the complete creation payload. Multiple budget items require lineAmounts: [{"budgetItemId":"<first-id>","amount":750},{"budgetItemId":"<second-id>","amount":450}], covering every budgetItemIds entry exactly once and summing to amountWithoutGst. Amounts exclude GST; use gstAmount: 0 for no GST.
@@ -521,6 +592,11 @@ Legacy aliases: `update-quotation`, `update_quotation`.
521
592
 
522
593
  Effects: state-change.
523
594
 
595
+ Payload fields (--payload JSON)
596
+ Required: id: string; projectId: string; budgetId: string; supplierId: string; budgetItemIds: string[]; amountWithoutGst: number; gstAmount: number; attachments: array
597
+ Optional: lineAmounts: {budgetItemId, amount}[] (required for multiple budget items)
598
+ Example: bb update-quotation --payload '{"id":"<quotation-id>","projectId":"<project-id>","budgetId":"<budget-id>","supplierId":"<supplier-id>","budgetItemIds":["<budget-item-id>"],"amountWithoutGst":1200,"gstAmount":0,"attachments":[{"id":"<attachment-id>","name":"quote.pdf","key":"<staged-key>","size":1000}]}'
599
+
524
600
  ## `bb quotation delete`
525
601
 
526
602
  Delete Quotation.
@@ -641,6 +717,11 @@ Legacy aliases: `create-customer-invoice`, `create_customer_invoice`.
641
717
 
642
718
  Effects: state-change, email, external-write, financial-write.
643
719
 
720
+ Payload fields (--payload JSON)
721
+ Required: budgetId: string; splits: [{label: string, percentage: number, dueDate: ISO date}] (exactly one)
722
+ Optional: requestId: UUID string (recommended); invoiceDate: ISO date; details: {billingAddress: string, customerMemo: string}; isCustomPercentage: boolean
723
+ Example: bb create-customer-invoice --payload '{"budgetId":"<budget-id>","splits":[{"label":"Deposit","percentage":50,"dueDate":"2026-10-15"}],"details":{"billingAddress":"1 Example St","customerMemo":"Thanks"}}'
724
+
644
725
  ## `bb customer-invoice discard`
645
726
 
646
727
  Discard Customer Invoice.
@@ -689,6 +770,11 @@ Legacy aliases: `send-customer-invoice-to-contact-person`, `send_customer_invoic
689
770
 
690
771
  Effects: state-change, email.
691
772
 
773
+ Payload fields (--payload JSON)
774
+ Required: invoiceId: string; to: email; cc: email[]; replyTo: email; subject: string; content: HTML string; signature: HTML string
775
+ Optional: none
776
+ Example: bb send-customer-invoice-to-contact-person --payload '{"invoiceId":"<invoice-id>","to":"client@example.com","cc":[],"replyTo":"team@example.com","subject":"Invoice","content":"<p>Attached invoice</p>","signature":"<p>Team</p>"}'
777
+
692
778
  ## `bb customer-invoice pdf download`
693
779
 
694
780
  Download a customer invoice PDF when permitted.
@@ -817,6 +903,11 @@ Legacy aliases: `update-company`, `update_company`.
817
903
 
818
904
  Effects: state-change, external-write.
819
905
 
906
+ Payload fields (--payload JSON)
907
+ Required: id: string; name: string; website: URL string
908
+ Optional: confirmDistinct: boolean
909
+ Example: bb update-company --payload '{"id":"<company-id>","name":"Example Co","website":"https://example.com"}'
910
+
820
911
  ## `bb company delete`
821
912
 
822
913
  Delete Company.
@@ -875,7 +966,7 @@ Effects: state-change, external-write.
875
966
 
876
967
  ## `bb project create`
877
968
 
878
- Create Project.
969
+ Create a project linked to an existing Asana Deals lead task. Supply --asanaTaskId in non-interactive use; interactive use searches for and selects a lead task (optionally --asanaSearch). The Slack channel is resolved from the selected Asana task unless all three Slack channel flags are supplied. For a new direct client, create the lead task using the website form first.
879
970
 
880
971
  Legacy aliases: `create-project`, `create_project`.
881
972
 
@@ -889,6 +980,11 @@ Legacy aliases: `update-project`, `update_project`.
889
980
 
890
981
  Effects: state-change, external-write.
891
982
 
983
+ Payload fields (--payload JSON)
984
+ Required: id: string; name: string; companyId: string; contactPersonId: string; asanaTaskId: string; insideSalesId: string; businessDevelopmentId: string; venue: string; dateRange: {from: ISO date}
985
+ Optional: dateRange.to: ISO date; projectManagerId: string; pax: string; description: string; slackChannelId/slackChannelUrl/slackChannelName: strings (supply all three); requestQboAccountantNotification: boolean; confirmEstimateInvalidation: boolean
986
+ Example: bb update-project --payload '{"id":"<project-id>","name":"Launch","companyId":"<company-id>","contactPersonId":"<contact-id>","asanaTaskId":"<asana-task-id>","insideSalesId":"<user-id>","businessDevelopmentId":"<user-id>","venue":"Hall","dateRange":{"from":"2026-10-01T09:00:00Z"}}'
987
+
892
988
  ## `bb project delete`
893
989
 
894
990
  Delete Project.
@@ -953,6 +1049,11 @@ Legacy aliases: `create-contact-person`, `create_contact_person`.
953
1049
 
954
1050
  Effects: state-change.
955
1051
 
1052
+ Payload fields (--payload JSON)
1053
+ Required: companyId: string; title: MR|MRS|MS|DR; firstName: string; lastName: string|null; email: string; mobile: string
1054
+ Optional: address: {streetAddress1?, city?, state?, postalCode?, country?}
1055
+ Example: bb create-contact-person --payload '{"companyId":"<company-id>","title":"MS","firstName":"Jane","lastName":"Tan","email":"jane@example.com","mobile":"+65 9123 4567"}'
1056
+
956
1057
  ## `bb contact update`
957
1058
 
958
1059
  Update Contact Person.
@@ -961,6 +1062,11 @@ Legacy aliases: `update-contact-person`, `update_contact_person`.
961
1062
 
962
1063
  Effects: state-change.
963
1064
 
1065
+ Payload fields (--payload JSON)
1066
+ Required: id: string; companyId: string; title: MR|MRS|MS|DR; firstName: string; lastName: string|null; email: string; mobile: string
1067
+ Optional: address: object
1068
+ Example: bb update-contact-person --payload '{"id":"<contact-id>","companyId":"<company-id>","title":"MS","firstName":"Jane","lastName":"Tan","email":"jane@example.com","mobile":"+65 9123 4567"}'
1069
+
964
1070
  ## `bb supplier list`
965
1071
 
966
1072
  List suppliers.
@@ -977,6 +1083,11 @@ Legacy aliases: `create-supplier`, `create_supplier`.
977
1083
 
978
1084
  Effects: state-change, email, external-write.
979
1085
 
1086
+ Payload fields (--payload JSON)
1087
+ Required: name: string; primaryContactPerson: string; email: string; phone: string; paymentMethodId: string; paymentTerm: string; roleId: string
1088
+ Optional: gstRegistered: boolean; tags: string[]; website: URL string; address: object; attachments: array; bank and PayNow fields
1089
+ Example: bb create-supplier --payload '{"name":"Example Supplier","primaryContactPerson":"Jane Tan","email":"jane@example.com","phone":"91234567","paymentMethodId":"<method-id>","paymentTerm":"Net 30","roleId":"<role-id>"}'
1090
+
980
1091
  ## `bb supplier update`
981
1092
 
982
1093
  Update Supplier.
@@ -985,6 +1096,11 @@ Legacy aliases: `update-supplier`, `update_supplier`.
985
1096
 
986
1097
  Effects: state-change, email, external-write.
987
1098
 
1099
+ Payload fields (--payload JSON)
1100
+ Required: id: string; name: string; primaryContactPerson: string; email: string; phone: string; paymentMethodId: string; paymentTerm: string; roleId: string
1101
+ Optional: gstRegistered: boolean; tags: string[]; website: URL string; address: object; attachments: array; bank and PayNow fields
1102
+ Example: bb update-supplier --payload '{"id":"<supplier-id>","name":"Example Supplier","primaryContactPerson":"Jane Tan","email":"jane@example.com","phone":"91234567","paymentMethodId":"<method-id>","paymentTerm":"Net 30","roleId":"<role-id>"}'
1103
+
988
1104
  ## `bb supplier delete`
989
1105
 
990
1106
  Delete Suppliers.
@@ -1065,6 +1181,11 @@ Legacy aliases: `create-item`, `create_item`.
1065
1181
 
1066
1182
  Effects: state-change, external-write.
1067
1183
 
1184
+ Payload fields (--payload JSON)
1185
+ Required: name: string (QuickBooks-safe characters); categoryId: string; supplierId: string; cost: decimal string or number
1186
+ Optional: description: string; gstInclusive: boolean; gstOutOfScope: boolean; goLabsProduct: boolean; attachments: array
1187
+ Example: bb create-item --payload '{"name":"Event Crew per hour","categoryId":"<category-id>","supplierId":"<supplier-id>","cost":19}'
1188
+
1068
1189
  ## `bb item update`
1069
1190
 
1070
1191
  Update Item.
@@ -1073,6 +1194,11 @@ Legacy aliases: `update-item`, `update_item`.
1073
1194
 
1074
1195
  Effects: state-change, external-write.
1075
1196
 
1197
+ Payload fields (--payload JSON)
1198
+ Required: id: string; name: string; categoryId: string; supplierId: string; cost: decimal string or number
1199
+ Optional: description: string; gstInclusive: boolean; gstOutOfScope: boolean; goLabsProduct: boolean; attachments: array
1200
+ Example: bb update-item --payload '{"id":"<item-id>","name":"Event Crew per hour","categoryId":"<category-id>","supplierId":"<supplier-id>","cost":"19"}'
1201
+
1076
1202
  ## `bb item archive`
1077
1203
 
1078
1204
  Archive Items.
@@ -1297,6 +1423,11 @@ Legacy aliases: `save-inbound-mapping`, `save_inbound_mapping`.
1297
1423
 
1298
1424
  Effects: state-change.
1299
1425
 
1426
+ Payload fields (--payload JSON)
1427
+ Required: positional <sourceId>; payload: [{canonicalField: enum, typeformFieldId: string, required?: boolean, typeformFieldRef?: string|null}] (1-50 entries)
1428
+ Optional: required defaults false; typeformFieldRef may be omitted
1429
+ Example: bb save-inbound-mapping <sourceId> --payload '[{"canonicalField":"CONTACT_FIRST_NAME","typeformFieldId":"<typeform-field-id>"}]'
1430
+
1300
1431
  ## `bb inbound automation save`
1301
1432
 
1302
1433
  Save Inbound Automation Config.
@@ -1305,6 +1436,11 @@ Legacy aliases: `save-inbound-automation-config`, `save_inbound_automation_confi
1305
1436
 
1306
1437
  Effects: state-change.
1307
1438
 
1439
+ Payload fields (--payload JSON)
1440
+ Required: positional <sourceId>; asanaCustomFields: object; asanaDefaultAssigneeId: string|null; asanaDefaultAssigneeName: string|null; asanaFollowerIds: string[]; asanaProjectId: string; asanaSectionId: string; asanaWonSectionId: string; asanaLostSectionId: string; googleCalendarId: string; googleCalendarTimeZone: string; goshBriefBaseUrl: URL; slackDefaultAssigneeId: string|null; slackInboundChannelId: string; slackInviteUserIds: string[]; slackPitchChannelPrefix: string
1441
+ Optional: asanaDiscussionSectionId, asanaFirstContactSectionId, asanaFirstProposalSentSectionId, asanaProposalWipSectionId: string|null; asanaCustomFields.*: mapped IDs
1442
+ Example: bb save-inbound-automation-config <sourceId> --payload '{"asanaCustomFields":{},"asanaDefaultAssigneeId":null,"asanaDefaultAssigneeName":null,"asanaFollowerIds":[],"asanaProjectId":"<asana-project-id>","asanaSectionId":"<asana-section-id>","asanaWonSectionId":"<asana-won-id>","asanaLostSectionId":"<asana-lost-id>","googleCalendarId":"team@example.com","googleCalendarTimeZone":"Asia/Singapore","goshBriefBaseUrl":"https://example.com/brief","slackDefaultAssigneeId":null,"slackInboundChannelId":"<slack-channel-id>","slackInviteUserIds":[],"slackPitchChannelPrefix":"pitch"}'
1443
+
1308
1444
  ## `bb inbound processing update`
1309
1445
 
1310
1446
  Update Inbound Processing.