Create and pay QuickBooks test documents

Staging verified: This workflow passed on November 3, 2026 with a Console-created synthetic company and ordinary runtime credentials. Production qualification is pending. Supported operations are described below.

Use a synthetic company with QuickBooks selected and a Developer or higher plan with native API access. Generation credits and native API access are separate; adding generation credits does not enable native routes. See Connect your software for current access requirements.

Create the company in the Console, then create a Read and modify company key in Settings → Company → Company API keys. Keep it on your server. You can also use a staging organization key with the same access for the organization that owns the company. Use the matching origin and slug from that company's Connect panel:

export FICTIX_API_ORIGIN="https://api-staging.fictix.ai"
export FICTIX_PROJECT_SLUG="<your staging company slug>"
export FICTIX_PROJECT_API_KEY="<your company key>"
QBO_BASE="$FICTIX_API_ORIGIN/api/v1/orgs/$FICTIX_PROJECT_SLUG/native/qbo/v3/company/test"

These requests change only the synthetic company's records. They do not send money through a real QuickBooks or bank connection.

Read the IDs your application will use

Query customers, vendors, items and ledger accounts. Replace Account in this request with Customer, Vendor or Item for the other lists:

curl --fail-with-body -sS --get "$QBO_BASE/query" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY" \
  --data-urlencode 'query=SELECT * FROM Account STARTPOSITION 1 MAXRESULTS 1000'

Read the records inside QueryResponse.Account, QueryResponse.Customer, QueryResponse.Vendor and QueryResponse.Item. Use their returned Id values in native references. In particular, AccountRef.value refers to a native Account.Id; do not substitute a different ID from an export or canonical data response.

Choose an active service item with an income-account mapping, an expense account, and the bank-linked cash account for this company. Invoice creation resolves the item's income account. Payment posting requires exactly one active bank account linked to the selected cash ledger account, using the document's currency. An ambiguous or missing mapping returns a validation error before posting.

The query reference describes supported filters and paging. Queries and single-record GETs also support Invoice, Bill, Payment, BillPayment and JournalEntry.

Create an invoice

Save this as invoice.json, replacing the customer and item IDs with values you just read. Use your transaction date in YYYY-MM-DD format.

{
  "CustomerRef": {"value": "<customer Id>"},
  "TxnDate": "2026-11-03",
  "Line": [{
    "Amount": 0.01,
    "DetailType": "SalesItemLineDetail",
    "SalesItemLineDetail": {
      "ItemRef": {"value": "<service item Id>"},
      "Qty": 1,
      "UnitPrice": 0.01
    }
  }]
}
curl --fail-with-body -sS "$QBO_BASE/invoice" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qbo-invoice-demo-1" \
  --data-binary @invoice.json

A successful response contains Invoice.Id, TotalAmt: 0.01 and Balance: 0.01. Creation posts the receivable and revenue. It does not record a cash receipt. Save Invoice.Id for the payment.

Use a distinct idempotency key for each operation. Persist the key and exact payload before sending. If the response is lost, retry with that same key and body; changing the payload under the same key returns 409. Use a new key for a genuinely new invoice.

Apply the customer's payment

Save this as payment.json. Use the same customer, the cash account's native ID, and the returned invoice ID:

{
  "CustomerRef": {"value": "<customer Id>"},
  "TxnDate": "2026-11-03",
  "TotalAmt": 0.01,
  "DepositToAccountRef": {"value": "<cash Account Id>"},
  "Line": [{
    "Amount": 0.01,
    "LinkedTxn": [{"TxnId": "<Invoice.Id>", "TxnType": "Invoice"}]
  }]
}
curl --fail-with-body -sS "$QBO_BASE/payment" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qbo-payment-demo-1" \
  --data-binary @payment.json

The response contains Payment.Id. Read the invoice again at GET /invoice/{Invoice.Id}: its balance should now be zero. The payment creates the linked bank transaction and balanced cash/receivable posting.

Create a vendor bill

Save this as bill.json using the vendor and expense account IDs:

{
  "VendorRef": {"value": "<vendor Id>"},
  "TxnDate": "2026-11-03",
  "Line": [{
    "Amount": 0.01,
    "DetailType": "AccountBasedExpenseLineDetail",
    "AccountBasedExpenseLineDetail": {
      "AccountRef": {"value": "<expense Account Id>"}
    }
  }]
}
curl --fail-with-body -sS "$QBO_BASE/bill" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qbo-bill-demo-1" \
  --data-binary @bill.json

A successful response contains Bill.Id and an outstanding balance of 0.01. The posting increases expense and accounts payable; cash is unchanged.

Pay the bill

Save this as billpayment.json. This workflow supports PayType: "Check":

{
  "VendorRef": {"value": "<vendor Id>"},
  "TxnDate": "2026-11-03",
  "TotalAmt": 0.01,
  "PayType": "Check",
  "CheckPayment": {"BankAccountRef": {"value": "<cash Account Id>"}},
  "Line": [{
    "Amount": 0.01,
    "LinkedTxn": [{"TxnId": "<Bill.Id>", "TxnType": "Bill"}]
  }]
}
curl --fail-with-body -sS "$QBO_BASE/billpayment" \
  -H "X-API-Key: $FICTIX_PROJECT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qbo-billpayment-demo-1" \
  --data-binary @billpayment.json

Read GET /bill/{Bill.Id} to confirm a zero balance. The payment creates the linked bank withdrawal and balanced payable/cash posting. Retrying an operation with its original key and payload must not create another payment.

Check the resulting books

Query JournalEntry. Each line contains a numeric Amount, DetailType: "JournalEntryLineDetail", and a JournalEntryLineDetail object with PostingType: "Debit" or "Credit" and a resolvable AccountRef. Each journal's debit and credit amounts must balance. Existing document IDs must remain stable as your application writes new records.

The four operations above create four balanced journals. After both exact payments, the new invoice and bill have zero outstanding balance, and their opposite cash movements cancel. You can also read canonical entities or download a CSV export to reconcile the company's receivables, payables and bank balances with its ledger.

Supported slice

This guide covers new single-currency, non-tax service invoices, expense bills, and exact payments linked to one existing document. The party, currency, amount, active accounts and mappings must agree. Unsupported invoice or bill corrections return 409; creating a payment does not authorize editing a posted document. Inventory, tax and currency-conversion workflows are outside this example. Direct JournalEntry writes are rejected; journal reads expose the actual posted accounting consequences.

Validation errors return a QBO Fault or a Fictix error body. Check the HTTP status and body before treating an operation as accepted. The broader provider workflow reference and Intuit's accounting documentation describe the wire conventions; supported Fictix operations remain bounded by this guide.