Simulators
Transactions and list entities
The list entities (Vendor, Employee, Item, Account, Class, Department, Term and PaymentMethod) and the fourteen transactions, from Invoice to Transfer, share one envelope and one write pattern (Ids and writes). The scenarios seed no list entity or transaction, so create what a transaction references first.
Reference other records
The simulator checks the records a body references, such as a line’s ItemRef, and returns 400 610 naming an unknown one. This block creates an income account, an item that sells into it and an invoice for three of the item:
R=4620816365320737870
curl -s "$RYSTIC_URL/v3/company/$R/account" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Name":"Sales","AccountType":"Income"}' | jq -c '.Account | {Id, Name, SyncToken}'
# -> {"Id":"1","Name":"Sales","SyncToken":"0"}
curl -s "$RYSTIC_URL/v3/company/$R/item" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Name":"Sourdough loaf","Type":"NonInventory","IncomeAccountRef":{"value":"1"},"UnitPrice":8}' | jq -c '.Item | {Id, Name, UnitPrice}'
# -> {"Id":"1","Name":"Sourdough loaf","UnitPrice":8}
curl -s "$RYSTIC_URL/v3/company/$R/invoice" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"CustomerRef":{"value":"1"},"Line":[{"Amount":24,"DetailType":"SalesItemLineDetail","SalesItemLineDetail":{"ItemRef":{"value":"1"},"Qty":3,"UnitPrice":8}}]}' | jq -c '.Invoice | {Id, TotalAmt, Balance, SyncToken}'
# -> {"Id":"1","TotalAmt":24,"Balance":24,"SyncToken":"0"}
An item’s IncomeAccountRef must name an account that exists, and an invoice’s lines must name items that exist.
Differs from QuickBooks: an item with no IncomeAccountRef is accepted, where QuickBooks requires one on Service, Inventory, Assembly, Other Charge and Product items (unconfirmed).
Delete or void a transaction
To delete a transaction, send POST …/<entity>?operation=delete with its Id and SyncToken. The response has "status":"Deleted", and a later read of that Id returns 400 610. Invoice, Payment, SalesReceipt and BillPayment can also be voided:
| Transaction | Void request |
|---|---|
| Invoice | POST …/invoice?operation=void |
| Payment, SalesReceipt and BillPayment | POST …/<entity>?include=void&operation=update |
This block records a payment against the invoice, which settles its Balance and raises its SyncToken (Amounts), then voids the invoice and deletes the payment:
curl -s "$RYSTIC_URL/v3/company/$R/payment" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"CustomerRef":{"value":"1"},"TotalAmt":30,"Line":[{"Amount":24,"LinkedTxn":[{"TxnId":"1","TxnType":"Invoice"}]}]}' | jq -c '.Payment | {Id, TotalAmt, UnappliedAmt}'
# -> {"Id":"1","TotalAmt":30,"UnappliedAmt":6}
curl -s "$RYSTIC_URL/v3/company/$R/invoice/1" -H 'Authorization: Bearer placeholder' | jq -c '.Invoice | {Id, Balance, SyncToken}'
# -> {"Id":"1","Balance":0,"SyncToken":"1"}
curl -s "$RYSTIC_URL/v3/company/$R/invoice?operation=void" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Id":"1","SyncToken":"1"}' | jq -c '.Invoice | {Id, TotalAmt, PrivateNote, SyncToken}'
# -> {"Id":"1","TotalAmt":0,"PrivateNote":"Voided","SyncToken":"2"}
curl -s "$RYSTIC_URL/v3/company/$R/payment?operation=delete" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Id":"1","SyncToken":"0"}' | jq -c '.Payment'
# -> {"Id":"1","domain":"QBO","status":"Deleted"}
A void sets the transaction’s amounts to 0 and empties a Payment’s or BillPayment’s lines. It writes Voided in PrivateNote, before any note already there.
Ids and writes
Creating a record sets SyncToken to "0". A write that names an Id and the current SyncToken updates the record and raises its SyncToken; a stale one is refused (Idempotency). Error format covers refusals, and Auth a request with no token.
Amounts
| Transaction | TotalAmt |
|---|---|
| Payment | the TotalAmt you send, or 0; UnappliedAmt is what its lines leave unapplied |
| Estimate and BillPayment | the TotalAmt you send, or the sum of its lines |
| JournalEntry | the sum of its debit lines, which must equal its credit lines |
| Transfer | none: it has one Amount |
| every other transaction | the sum of its lines, whatever you send; an Invoice whose lines hold no detail line keeps the TotalAmt you send, else the one it had, or 0 |
A payment moves the balances it touches:
- Each line pays the first invoice its
LinkedTxnnames. That invoice loses the line’sAmountfrom itsBalance, lists the payment in its ownLinkedTxnand raises itsSyncToken. - Its customer’s
Balancedrops by itsTotalAmt. - Deleting or voiding the payment reverses both, and raises the invoice’s
SyncTokenagain.
An invoice adds its Balance to its customer’s, and deleting or voiding it takes off what it was billed. A payment that paid it stays, now unapplied: its lines that paid the invoice are dropped, their amount moves to UnappliedAmt, and its SyncToken rises.
This block bills customer 1 for 40, pays 25 of it, deletes the payment, pays 30 with 25 applied and then voids the invoice, reading the balances after each step. The customer ends 30 lower than it started: the voided invoice bills nothing, and the second payment stays as unapplied credit.
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":239}
curl -s "$RYSTIC_URL/v3/company/$R/invoice" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"CustomerRef":{"value":"1"},"Line":[{"Amount":40,"DetailType":"SalesItemLineDetail","SalesItemLineDetail":{"ItemRef":{"value":"1"},"Qty":5,"UnitPrice":8}}]}' | jq -c '.Invoice | {Id, Balance}'
# -> {"Id":"2","Balance":40}
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":279}
curl -s "$RYSTIC_URL/v3/company/$R/payment" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"CustomerRef":{"value":"1"},"TotalAmt":25,"Line":[{"Amount":25,"LinkedTxn":[{"TxnId":"2","TxnType":"Invoice"}]}]}' | jq -c '.Payment | {Id, TotalAmt, UnappliedAmt}'
# -> {"Id":"2","TotalAmt":25,"UnappliedAmt":0}
curl -s "$RYSTIC_URL/v3/company/$R/invoice/2" -H 'Authorization: Bearer placeholder' | jq -c '.Invoice | {Id, Balance, SyncToken, LinkedTxn}'
# -> {"Id":"2","Balance":15,"SyncToken":"1","LinkedTxn":[{"TxnId":"2","TxnType":"Payment"}]}
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":254}
curl -s "$RYSTIC_URL/v3/company/$R/payment?operation=delete" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Id":"2","SyncToken":"0"}' | jq -c '.Payment.status'
# -> "Deleted"
curl -s "$RYSTIC_URL/v3/company/$R/invoice/2" -H 'Authorization: Bearer placeholder' | jq -c '.Invoice | {Id, Balance, SyncToken, LinkedTxn}'
# -> {"Id":"2","Balance":40,"SyncToken":"2","LinkedTxn":[]}
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":279}
curl -s "$RYSTIC_URL/v3/company/$R/payment" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"CustomerRef":{"value":"1"},"TotalAmt":30,"Line":[{"Amount":25,"LinkedTxn":[{"TxnId":"2","TxnType":"Invoice"}]}]}' | jq -c '.Payment | {Id, UnappliedAmt}'
# -> {"Id":"3","UnappliedAmt":5}
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":249}
curl -s "$RYSTIC_URL/v3/company/$R/invoice?operation=void" -H 'Authorization: Bearer placeholder' -H 'Content-Type: application/json' -d '{"Id":"2","SyncToken":"3"}' | jq -c '.Invoice | {Id, TotalAmt, Balance}'
# -> {"Id":"2","TotalAmt":0,"Balance":0}
curl -s "$RYSTIC_URL/v3/company/$R/payment/3" -H 'Authorization: Bearer placeholder' | jq -c '.Payment | {Id, UnappliedAmt, SyncToken, Line}'
# -> {"Id":"3","UnappliedAmt":30,"SyncToken":"1","Line":[]}
curl -s "$RYSTIC_URL/v3/company/$R/customer/1" -H 'Authorization: Bearer placeholder' | jq -c '.Customer | {Id, Balance}'
# -> {"Id":"1","Balance":209}
Request ids
Replay support for requestid varies by entity (Idempotency).