# Transactions and list entities

Vendors, items, accounts and the other list entities, and fourteen transactions from Invoice to Transfer, with delete, void and the amounts each keeps.

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](#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:

```bash
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](#amounts)), then voids the invoice and deletes the payment:

```bash
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](https://www.rystic.ai/docs/simulators/quickbooks.md#idempotency)). [Error format](https://www.rystic.ai/docs/simulators/quickbooks.md#error-format) covers refusals, and [Auth](https://www.rystic.ai/docs/simulators/quickbooks.md#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 `LinkedTxn` names. That invoice loses the line's `Amount` from its `Balance`, lists the payment in its own `LinkedTxn` and raises its `SyncToken`.
- Its customer's `Balance` drops by its `TotalAmt`.
- Deleting or voiding the payment reverses both, and raises the invoice's `SyncToken` again.

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.

```bash
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](https://www.rystic.ai/docs/simulators/quickbooks.md#idempotency)).

---

Source: https://www.rystic.ai/docs/simulators/quickbooks/features/transactions · Markdown: https://www.rystic.ai/docs/simulators/quickbooks/features/transactions.md
