Docs

Billing and expenses

API reference for invoices and their lines, recurring invoices, quotes, products, taxes and expenses.

These endpoints need the Sales area of the key's role, apart from expenses, which need Financial. See Keys and permissions.

Invoices

EndpointDoes
GET invoices/read.phpLists invoices, or gets one
ParameterDoes
invoice_idJust this invoice
client_idJust this client's invoices
limit, offsetPaging

Every invoice is listed, whatever its status. invoice_amount is its total. ITFlow works out the rest of the sums and adds them to each invoice:

FieldNotes
invoice_subtotalThe total before tax
invoice_taxThe tax
invoice_taxesThe tax by each part of it, as on the invoice: a name and an amount
invoice_tax_registrationsThe tax registration lines printed on the invoice
{
  "success": "True",
  "count": 1,
  "data": [
    {
      "invoice_id": "475",
      "invoice_prefix": "INV-",
      "invoice_number": "475",
      "invoice_scope": "Wireless upgrade - two access points for the treatment rooms",
      "invoice_status": "Draft",
      "invoice_date": "2026-10-21",
      "invoice_due": "2026-11-05",
      "invoice_amount": "824.30",
      "invoice_currency_code": "USD",
      "invoice_client_id": "1",
      "invoice_subtotal": 790,
      "invoice_tax": 34.3,
      "invoice_taxes": [ { "name": "PA Sales Tax 6%", "amount": 29.4 }, { "name": "Allegheny County 1%", "amount": 4.9 } ],
      "invoice_tax_registrations": [ "Allegheny County Sales Tax No. 75520193" ]
    }
  ]
}

Fields: invoice_id, invoice_prefix, invoice_number, invoice_scope, invoice_status, invoice_date, invoice_due, invoice_discount_amount, invoice_credit_amount, invoice_amount, invoice_currency_code, invoice_note, invoice_url_key, invoice_category_id, invoice_recurring_invoice_id, invoice_quote_id, invoice_client_id, invoice_created_at, invoice_updated_at, invoice_archived_at, and the sums above.

Invoices are read only. Payments can't be read through the API.

Invoice lines

EndpointDoes
GET invoice_items/read.phpAn invoice's lines, or one line
POST invoice_items/create.phpAdds a line to an invoice

Read

ParameterDoes
invoice_idThis invoice's lines, in their order. You need this or item_id.
item_idJust this line
client_idOnly if the invoice is this client's
limit, offsetPaging

Each line comes with its tax rate's tax_name and tax_percent.

{
  "success": "True",
  "count": 1,
  "data": [
    { "item_id": "1956", "item_name": "Ubiquiti U6-Pro Access Point", "item_description": "Wi-Fi 6 access point, ceiling mounted", "item_quantity": "2.00", "item_price": "245.00", "item_subtotal": "490.00", "item_tax": "34.30", "item_total": "524.30", "item_order": "1", "item_tax_id": "2", "item_product_id": "96", "item_invoice_id": "475", "tax_name": "Allegheny County Sales Tax", "tax_percent": "7.0000" }
  ]
}

Fields: item_id, item_name, item_description, item_quantity, item_price, item_subtotal, item_tax, item_total, item_order, item_tax_id, item_product_id, item_invoice_id, item_created_at, item_updated_at, item_archived_at, tax_name, tax_percent.

Create

FieldNotes
invoice_idRequired. The invoice can't be paid already.
nameRequired, up to 200 characters
qtyRequired, more than 0
priceThe price of one
description
tax_idA tax rate's tax_id, 0 for no tax, or default for the rate the client - or the product - usually has
product_idThe product it is. One whose stock is tracked has the quantity taken from stock, and the line is turned down if there isn't enough.
item_orderWhere it goes among the lines
client_idThe invoice's client. Needed when the key's agent can see only some clients.

The invoice's totals are worked out again afterwards.

curl -X POST https://itflow.example.com/api/v1/invoice_items/create.php \
  -H "Content-Type: application/json" \
  -d '{"api_key": "YOUR_API_KEY", "invoice_id": 475, "name": "Patch cables", "description": "Cat6, 3 ft", "qty": 4, "price": 6.50, "tax_id": "default"}'

Recurring invoices

EndpointDoes
GET recurring_invoices/read.phpLists recurring invoices, or gets one with its lines
POST recurring_invoices/create.phpMakes one, and its first invoice now if you ask

Read

ParameterDoes
recurring_invoice_idJust this one, with its lines as items
client_idJust this client's
limit, offsetPaging

Create

FieldNotes
client_idRequired
itemsRequired: its lines, 1 to 100. Each is a product_id - its name, description and price unless you send them - or a name and price; with qty (1 if left out), description, and tax_id: a tax's id, or default for the client's usual rate.
frequencymonth (the default), quarter or year
start_dateIts first run, as 2026-11-05. Today if you leave it out.
scopeWhat it's for, shown on each invoice
note, category_id, discountThe note each invoice carries, an income category, and an amount off each one
auto_send1, the default: each invoice it makes is emailed by itself. 0 leaves them as drafts.
invoice_now1 makes the first invoice now, in place of the run on start_date - the next is a period later
invoice_sendWith invoice_now, 1 (the default) emails it to the client's primary and billing contacts and marks it Sent, so it can be paid from its link. 0 leaves it a draft.

It's made in the client's currency, as a recurring invoice in ITFlow is. A client, date, product or line that won't do is refused with 400 and why in message.

curl -X POST https://itflow.example.com/api/v1/recurring_invoices/create.php \
  -H "Content-Type: application/json" \
  -d '{"api_key": "YOUR_API_KEY", "client_id": 1, "scope": "Managed services", "items": [{"product_id": 4, "tax_id": "default"}, {"product_id": 5, "qty": 12, "tax_id": "default"}], "invoice_now": 1}'
{
  "success": "True", "count": "1", "data": [ { "insert_id": 19 } ],
  "recurring_invoice_reference": "REC-19", "amount": 450, "next_date": "2026-12-05",
  "invoice": { "invoice_id": 469, "reference": "INV-469", "amount": 450, "currency": "USD", "due": "2026-12-05", "status": "Sent",
               "url": "https://itflow.example.com/guest/guest_view_invoice.php?invoice_id=469&url_key=...", "emailed_to": ["Priya Raghavan (praghavan@ravenwooddental.example)"] }
}

invoice.url is where the client views and pays it - put it behind a Pay button. To have a ticket wait for that invoice to be paid, raise it with ticket_invoice_id - see Tickets.

Quotes

EndpointDoes
GET quotes/read.phpLists quotes, or gets one
ParameterDoes
quote_idJust this quote
client_idJust this client's quotes
limit, offsetPaging

Like invoices, each quote comes with quote_subtotal, quote_tax, quote_taxes and quote_tax_registrations. On a quote with monthly lines, those are for the one-time part, and quote_monthly_amount is the monthly total.

{
  "success": "True",
  "count": 1,
  "data": [
    { "quote_id": "2", "quote_prefix": "QUO-", "quote_number": "2", "quote_scope": "Uninterruptible power supply for the comms rack", "quote_status": "Accepted", "quote_amount": "1312.95", "quote_monthly_amount": "0.00", "quote_subtotal": 1265, "quote_tax": 47.95, "quote_taxes": [ { "name": "PA Sales Tax 6%", "amount": 41.1 }, { "name": "Allegheny County 1%", "amount": 6.85 } ] }
  ]
}

Fields: quote_id, quote_prefix, quote_number, quote_scope, quote_status, quote_discount_amount, quote_date, quote_expire, quote_amount, quote_monthly_amount, quote_currency_code, quote_note, quote_url_key, quote_category_id, quote_client_id, quote_created_at, quote_updated_at, quote_archived_at, and the sums above.

Products

EndpointDoes
GET products/read.phpLists your products and services, or gets one
ParameterDoes
product_idJust this product
limit, offsetPaging

Products aren't a client's, so client_id doesn't apply. The list includes archived products.

{
  "success": "True",
  "count": 1,
  "data": [
    { "product_id": "1", "product_name": "Managed Workstation", "product_type": "service", "product_code": "MS-WKS", "product_price": "65.00", "product_currency_code": "USD", "product_frequency": "month", "product_track_stock": "0", "product_tax_id": "0", "product_category_id": "15" }
  ]
}

Fields: product_id, product_name, product_type, product_description, product_notes, product_code, product_vendor_part, product_location, product_price, product_cost, product_currency_code, product_frequency, product_seat_source, product_track_stock, product_reorder_level, product_reorder_qty, product_asset_type, product_make, product_model, product_warranty_months, product_tax_id, product_category_id, product_vendor_id, product_created_at, product_updated_at, product_archived_at.

Taxes

EndpointDoes
GET taxes/read.phpLists your tax rates, or gets one
ParameterDoes
tax_idJust this rate, archived or not
archived1 to include archived rates
limit, offsetPaging
{
  "success": "True",
  "count": 1,
  "data": [
    {
      "tax_id": 2,
      "tax_name": "Allegheny County Sales Tax",
      "tax_percent": 7,
      "tax_description": "Pennsylvania 6% plus the Allegheny County local 1%",
      "tax_registration_number": "75520193",
      "tax_archived_at": null,
      "tax_replaced_by": 0,
      "tax_default": false,
      "tax_components": [
        { "name": "PA Sales Tax", "percent": 6, "compound": false, "registration_number": "75520193" },
        { "name": "Allegheny County", "percent": 1, "compound": false, "registration_number": "75520193" }
      ]
    }
  ]
}

tax_percent is the whole rate, and tax_components its parts. A part that's compound is charged on top of the parts before it. tax_default is true for the rate new lines get, and tax_replaced_by is the rate that replaced a changed one. See Taxes.

Expenses

EndpointDoes
GET expenses/read.phpLists expenses, or gets one
ParameterDoes
expense_idJust this expense
client_idJust this client's expenses. 0 for those that aren't a client's.
limit, offsetPaging
{
  "success": "True",
  "count": 1,
  "data": [
    { "expense_id": "13", "expense_description": "Hardware supplied to Ravenwood Dental Group", "expense_amount": "1762.00", "expense_date": "2026-10-14", "expense_vendor_id": "1", "expense_category_id": "76", "expense_client_id": "1", "expense_billable": "1", "expense_invoice_id": null }
  ]
}

Fields: expense_id, expense_description, expense_amount, expense_tax_id, expense_tax_amount, expense_currency_code, expense_date, expense_reference, expense_payment_method, expense_receipt, expense_vendor_id, expense_client_id, expense_category_id, expense_account_id, expense_refund_of_id, expense_recurring_expense_id, expense_billable, expense_markup, expense_invoice_id, expense_invoice_item_id, expense_import_key, expense_paid_by, expense_reimbursement_id, expense_reconciliation_id, expense_created_by, expense_created_at, expense_updated_at, expense_archived_at.

↑↓ to pickEnter to open