- Calculate on write: send
auto_calculate_tax: "required"on create, replace, or patch. DualEntry calculates tax for every line and replaces any line tax you supplied before saving. - Calculate, then create: call
POST /public/v2/taxes/calculate/, map the result onto each line’staxobject, then create the record. Use this path for native VAT or GST (where you must select a rate), or when you need to preview tax before writing.
auto_calculate_tax keep caller-supplied line tax and must either send that tax themselves or use the calculate-then-create flow below.
Prerequisites
Before you calculate tax or create a taxable record, confirm the following:- V2 API (
/public/v2/...) X-API-KEYheader with your organization’s API key (authenticating your requests)- The company is set up for the correct tax regime (GST, VAT, or US sales tax)
- The customer (or vendor) has
is_taxableset totruewhen tax should apply
Let DualEntry calculate tax on write
Setauto_calculate_tax to "required" on the write payload. DualEntry calculates tax for every line and replaces any supplied line tax before saving. If calculation cannot complete, the request returns 422.
Supported on: create (POST), replace (PUT), and patch (PATCH) for invoices, bills, cash sales, customer credits, direct expenses, purchase orders, sales orders, and vendor credits.
Supported tax engines: native US sales tax (the DualEntry tax engine), and Avalara Sales Tax, VAT, and GST. Native VAT and GST return
422 because this field does not select a rate. Use calculate, then create for those.
Example: create an invoice with auto-calculated tax
tax object you send on a line.
Address resolution
DualEntry picks tax addresses from the payload first, then from saved records, in this order:When auto-calculate returns 422
These are the common causes of a422 when auto_calculate_tax is "required", and how to fix each one:
Calculate, then create (manual path)
Use this path when you need to preview tax before writing, or when native VAT/GST requires selecting a rate fromavailable_rates.
Step 1: Resolve IDs
Look up the company, customer or vendor, and item IDs the calculate call needs:Step 2: Calculate tax
Send the resolved IDs and item lines to the calculate endpoint:company_idcustomer_id(money-in, e.g. invoices) orvendor_id(money-out, e.g. bills), not both
items: each withitem_id,quantity, andunit_price(item_idmay benullfor a vendor expense line)transaction_buyer_address: the destination address, required for US sales taxtransaction_dateandcurrency_code: required for US sales taxsupply_date: filters VAT/GST rates by their validity window
type is one of:
For GST and VAT, the first calculate call often returns
available_rates. Pick a rate, send it on the line as selected_gst_tax_rate_id or selected_vat_rate_id, then calculate again with that rate selected.
Step 3: Map the result onto each invoice line
Copy each field from the calculator response onto the matching field in the invoice line’stax object:
Also carry the line amount over: calculator
unit_price → invoice line rate.
Step 4: Create the invoice
Send the mapped tax fields on each line when you create the invoice. Omitauto_calculate_tax so DualEntry keeps the tax you mapped:
shipping_address on the invoice for fulfillment; it does not replace the calculate step when auto_calculate_tax is omitted.
Canada GST example (two calculate calls)
GST and VAT regimes need a second calculate call once a rate is selected. Native VAT/GST cannot useauto_calculate_tax: "required". Use this flow instead.
Call A: list available rates
Calculate without a selected rate first to see what DualEntry offers for this address:
type: "GST" with data.place_of_supply ("ON") and data.available_rates listing candidate rate IDs. Pick one (for example, the Ontario HST rate) from available_rates or from GET /public/v2/gst-tax-rates/.
Call B: calculate again with the selected rate
Add the chosen rate ID to the line and calculate again to get the final tax amounts:
tax_code, tax_rate, tax_amount, and selected_gst_tax_rate_id set. Map those onto the invoice as in Step 3, then create the invoice using the values from call B.
US sales tax
Withauto_calculate_tax: "required": send a complete buyer address on the invoice (or rely on the customer saved address), and DualEntry calculates and writes line tax on create, replace, or patch.
With calculate-then-create:
- Send
transaction_buyer_address(includeregionandpostal_code),transaction_date, andcurrency_codeon calculate. - The response
typeisSALES_TAX. - Copy
tax_code,tax_rate, andtax_amountonto the line’staxobject. - Create the invoice (omit
auto_calculate_tax).
type: "NONE" with a reason. Fix the address and calculate again before creating the invoice. With auto_calculate_tax: "required", a missing address returns 422 instead.
VAT
- The first calculate call returns
available_rates. - Send
selected_vat_rate_idon the line and calculate again. - Set the invoice line’s
tax.vat_rate_idfrom the sameselected_vat_rate_id. - Create the invoice.
auto_calculate_tax: "required". Avalara VAT can.
If calculate returns an error
The calculate endpoint returns errors for a few common mistakes:
Fix the request and calculate again. A
NONE result is not itself an error: it means DualEntry could not determine tax for this request, and the reason field says why.
For errors when auto_calculate_tax is "required", see When auto-calculate returns 422.
Checklist before go-live
Calculate on write- Set
auto_calculate_taxto"required"on create, replace, or patch - Provide a usable buyer or ship address, or a saved address on the customer, vendor, or company
- Confirm the response shows
items[].taxwith the expected code, rate, and amount - For native VAT/GST, use calculate-then-create instead of this path
- Call calculate before creating the invoice or bill
- Pass the buyer/shipping address on calculate as
transaction_buyer_address - For GST/VAT, select a rate from
available_ratesand calculate a second time - Copy every mapped tax field onto each line’s
taxobject - Omit
auto_calculate_taxso DualEntry keeps the tax you mapped - Confirm the invoice response shows
items[].taxwith the expected code, rate, and amount