The Avaza API now supports one of the most requested automation capabilities: adding uninvoiced billable timesheets, expenses and fixed amounts to invoices programmatically. Everything you can do through the Add Time, Add Expenses and Add Fixed Amount dialogs when building an invoice in Avaza can now be driven through the API — plus a few workflows designed specifically for automation, like previewing a billing run before committing it and generating a customer’s entire invoice in a single call.
This guide walks through the new endpoints and the most common workflows. Full request and response documentation for every endpoint is available in the API reference at https://api.avaza.com.
Before You Start
You’ll need a Personal Access Token or OAuth connection with the relevant scopes: reading and writing financial data, plus reading timesheets and expenses if you use the discovery endpoints.
A few ground rules apply throughout, matching how invoicing works in the Avaza web app:
- Only records that are billable, approved and not yet invoiced can be added to an invoice. Timesheet entries with a running timer are excluded until the timer stops.
- All records on an invoice must belong to the same customer as the invoice.
- Once a record is linked to an invoice line, it can’t be invoiced again — removing the line releases it.
- Amounts are calculated by Avaza exactly as the web app calculates them: timesheet durations use your account’s rounding settings and billing rates, expenses include category markup and currency conversion, and fixed amounts bill at their set amount.
Step 1 — Find What’s Ready to Bill
GET /api/Invoice/UninvoicedSummary answers “what’s ready to bill?” in one call. Pass a CompanyID (or ProjectID) and it returns the uninvoiced billable hours, the indicative value of that time, the total uninvoiced expense value, and the total of uninvoiced fixed amounts.
GET /api/Invoice/UninvoicedSummary?CompanyID=455
Time and fixed amount values are expressed in the customer’s currency; expense values are in your account’s base currency until they’re added to an invoice (see “How Expense Currency Works” below).
To see the individual records behind those totals, the existing list endpoints now support filtering to a customer’s uninvoiced items:
GET /api/Timesheet?CustomerID=455&isInvoiced=false&isBillable=true
GET /api/Expense?isInvoiced=false&isChargeable=true
GET /api/FixedAmount?CustomerID=455&isInvoiced=false
The IDs these return are what you use in the next step.
Step 2 — Create an Invoice with Linked Items
Line items on POST /api/Invoice now accept three optional arrays: TimesheetEntryIDs, ExpenseIDs and FixedAmountIDs. Any record IDs you place on a line are linked to that line and marked as invoiced.
Grouping is beautifully simple: the IDs you put on a line determine the grouping. One timesheet ID on a line gives it its own line; ten IDs on one line produces a single consolidated line. You decide the presentation by how you partition the IDs.
POST /api/Invoice
{
“CompanyIDFK”: 455,
“DateIssued”: “2026-09-01”,
“LineItems”: [
{ “TimesheetEntryIDs”: [88213, 88214, 88215] },
{ “ExpenseIDs”: [5512] },
{ “FixedAmountIDs”: [3310] }
]
}
Notice that Quantity, UnitPrice and Description are omitted — Avaza derives them from the linked records: summed hours and the applicable billing rate for time, the markup-inclusive billable amount for expenses, the set amount for fixed amounts, with descriptions composed the same way the web dialogs compose them.
Want control over the numbers? Supply your own Quantity, UnitPrice or Description on a linked line and your values are used instead, while the records still get linked. The underlying timesheet, expense or fixed amount records are never modified by an override.
A few rules per line: don’t mix record types on one line (time, expenses and fixed amounts each get their own lines), grouped timesheets must belong to one project, and each fixed amount gets its own line.
Adding Items to an Existing Invoice
POST /api/Invoice/AddLineItems appends lines to an invoice you’ve already created — with the same link arrays — and never touches the lines already on it. Totals, tax and the balance are recalculated automatically. This is the recommended way to add to an invoice from automation, since you only send what’s new.
POST /api/Invoice/AddLineItems
{
“TransactionID”: 88231,
“LineItems”: [
{ “TimesheetEntryIDs”: [88216, 88217] }
]
}
(The existing PUT /api/Invoice endpoint continues to work as full line replacement — lines you omit from a PUT are removed, and any linked records on removed lines are automatically released back to uninvoiced.)
POST /api/Invoice/RemoveLineItems deletes named lines from an invoice and releases their linked records, making them available to invoice again. An invoice always keeps at least one line.
Preview Before You Commit
POST /api/Invoice/PreviewUninvoicedItems is a dry run for filter-based billing: give it a customer and optional filters, and it returns exactly the line items that would be generated — amounts, descriptions, and the source records each line would cover — without writing anything. Nothing is invoiced, no records are touched. It’s ideal for a review step in an approval workflow, or for showing a human what an automated run is about to do.
One-Call Automated Billing
POST /api/Invoice/AddUninvoicedItems selects, groups, appends and links in a single call — the closest equivalent to walking through the web dialogs, designed for end-of-month automation:
POST /api/Invoice/AddUninvoicedItems
{
“TransactionID”: 88231,
“TimeEntries”: {
“DateTo”: “2026-08-31”,
“Grouping”: “GroupByProjectTask”
},
“Expenses”: {
“Grouping”: “NoGrouping”
},
“FixedAmounts”: { }
}
Each section supports the same filters and grouping modes as the web dialogs (projects, people, tasks, categories, date ranges; time groups by project, category, person, section or task; expenses by category). Everything currently eligible that matches is added. Timesheet entries with running timers are skipped and reported back so you know what was left behind.
Running the same call again is safe: records already invoiced aren’t eligible any more, so a repeat run simply reports zero items added — no duplicates, ever. That makes retry loops in automation worry-free.
Reading the Links Back
Invoice line items now show which records they were generated from. GET /api/Invoice/{id} always includes each line’s TimesheetEntryIDs, ExpenseIDs and FixedAmountIDs; the invoice list endpoint includes them when you pass IncludeSourceLinks=true. On the record side, GET /api/FixedAmount now returns the linked invoice line reference, and includeInvoiceDetails=true adds the invoice it belongs to — so reconciliation in either direction is a single call.
How Expense Currency Works
Expenses can be tracked in any currency. When an expense in a different currency is added to an invoice, Avaza converts it to the customer’s currency at that moment, using the same exchange rate source as the web app, and stores the applied rate on the expense. Until an expense is added to an invoice, list endpoints show it in its tracked currency — the definitive converted amount is determined at invoicing time.
Validation and Error Handling
Requests are all-or-nothing. If any record you reference is ineligible — belongs to a different customer, is unapproved, not billable, has a running timer, or is already invoiced — the entire request is rejected and nothing is changed. The error response lists every problem record with its ID and the reason, so one correction fixes everything:
{
“Errors”: [
{ “ItemType”: “Timesheet”, “ItemID”: 88299, “Reason”: “AlreadyInvoiced” },
{ “ItemType”: “Expense”, “ItemID”: 5600, “Reason”: “DifferentCustomer” }
]
}
If two processes try to invoice the same records at the same moment (for example, your automation and a teammate in the web app), exactly one succeeds — the other receives a conflict response and can simply re-check what’s still uninvoiced. Double-invoicing is impossible.
Webhooks
Pass SendWebhooks: true on any of these calls and, alongside the usual invoice_created / invoice_updated events, Avaza fires timesheet_updated and expense_updated events for every record that gets linked or released — so downstream systems tracking billing status stay in sync automatically.
Using These Features with AI Assistants
If you’ve connected an AI assistant to Avaza through our MCP server, it now has these capabilities too: summarising what’s ready to bill, previewing a billing run, creating invoices from uninvoiced work, and appending or removing linked lines. You can simply ask your assistant something like “invoice all of Acme’s unbilled time and expenses for August, grouped by task” and review the preview it shows you before it proceeds.
Works Alongside Everything Else
Invoices built through the API are indistinguishable from invoices built in the web app — you can open them, edit them, and add more items to them in either place. Deleting a linked line, whether via API or in the browser, always releases its records back to uninvoiced. Recurring invoice profiles and retainers continue to work exactly as before.
If you have questions or run into anything unexpected, reach out to us at support@avaza.com — we’d love to hear what you build with this.