Bill a month of logged work
list_unbilled groups billable, uninvoiced time and expenses by client and currency. Passing those ids to create_invoice prices and links the source work atomically, so the draft total is the sum of the exact logged amounts, not a re-typed estimate.
Written and reviewed by the Billr team. Published , last reviewed .
- Who this is for
- Anyone closing a month from agent-logged work, where the value of the run is not having to re-key a timesheet.
- Billr capabilities used
list_unbilledcreate_invoicelist_invoices
What you need first
- Logged, billable, uninvoiced work. Time without a rate cannot be attached until you set one.
- A key with the Read and draft profile.
- A decision about who gets billed for the month, because the run is per client.
Step by step
01Get the ids for the month you are billing
list_unbilledhas no date filter: it returns everything billable and uninvoiced, with each row carrying its owndate. To bill one month, read the date-scoped lists instead and filter to unbilled, billable work. Both page withnext_offset, and their totals cover the current page.list_time_entries { "client_name": "Harbor & Lane", "from": "2026-09-01", "to": "2026-09-30", "billed": "unbilled", "billable": true }02Fix anything flagged
Time entries with no rate are priced at zero and are refused by the invoice builder.
list_unbilledmarks them withmissing_rate: true; set a rate withupdate_time_entrybefore billing, which recomputes the amount from hours times rate.03Draft one invoice per client
Pass the client and the exact
time_entry_idsandexpense_idsyou selected for that month. Leaveline_itemsout: the server writes one line per source at the exact amount and includes the tracked seconds in the description. Give each client its ownrequest_id.create_invoice { "request_id": "8f2c1b74-3d5e-4a90-9b17-6e4a2c8d0f31", "client_id": "9f2a4d18-3b7c-4a6e-8f0d-1c5b2e9a7d44", "issue_date": "2026-09-30", "time_entry_ids": ["3f6c1a44-5b2d-4e71-9c08-7a1d3f5b9e22"], "expense_ids": ["d41b8e93-2a70-4c15-9b6f-5e8a1c3d7f08"] }04Confirm what cleared and what is left
Re-read the same date-scoped lists, or
list_unbilled. Attached work disappears because drafting marks it billed immediately, and anything still listed is work you chose not to bill or could not bill yet.
Worked example
Fictional account, field names as returned by the server
You say
Draft the September invoice for Harbor & Lane from time and expenses dated in September. Do not send it.
Your agent calls
list_time_entries { "client_name": "Harbor & Lane", "from": "2026-09-01", "to": "2026-09-30", "billed": "unbilled", "billable": true }list_expenses { "client_name": "Harbor & Lane", "from": "2026-09-01", "to": "2026-09-30", "billed": "unbilled", "billable": true }create_invoice { "request_id": "8f2c1b74-3d5e-4a90-9b17-6e4a2c8d0f31", "client_name": "Harbor & Lane", "issue_date": "2026-09-30", "time_entry_ids": [ "3f6c1a44-5b2d-4e71-9c08-7a1d3f5b9e22" ], "expense_ids": [ "d41b8e93-2a70-4c15-9b6f-5e8a1c3d7f08" ] }
Expected response, abridged
{
"summary": "Drafted INV-1148 for Harbor & Lane: $272.50 Source work was priced and linked atomically.",
"invoice": {
"invoice_number": "INV-1148",
"status": "draft",
"total": 272.5,
"line_items": [
{
"description": "Schema markup fixes (5400 seconds)",
"quantity": 1,
"rate": 225,
"amount": 225
},
{
"description": "Client lunch",
"quantity": 1,
"rate": 47.5,
"amount": 47.5
}
]
},
"linked_time_entry_ids": [
"3f6c1a44-5b2d-4e71-9c08-7a1d3f5b9e22"
],
"linked_expense_ids": [
"d41b8e93-2a70-4c15-9b6f-5e8a1c3d7f08"
]
}Limits and gotchas
list_unbilledhas no date filter, so a month-scoped run starts fromlist_time_entriesandlist_expenseswithfromandto, or from reading dates in the unbilled list.- Source-linked work must match the invoice client and currency. Cross-currency time cannot be attached.
- Once attached, the work is immutable while the invoice exists. Cancelling does not release it, and there is no supported unlink step.
- Each source id can be billed once. Passing an id already on another draft fails the whole call.
- Every list pages and its totals apply to the current page, so follow
next_offsetuntil it is null before trusting a month-level number.
Troubleshooting
- "Time must be unbilled, billable, priced and assigned to this client"
- One of the time entry ids is missing a rate, is non-billable, is already billed, or belongs to another client. Re-read
list_unbilledfor that client and fix the entry withupdate_time_entryfirst. - The draft total is lower than the unbilled list showed
- Some work stayed behind. Entries without a client stay in
unassignedand cannot ride on a client invoice; assign the client first. - A client was missed in the run
- Compare the date-scoped lists with the clients you iterated. Drafting removes work immediately, so a client lacking a draft still appears with its full set of entries.
Sources
Reviewed 2026-09-20 against Billr's own tool implementations and the client documentation linked above.
Read next
The draft is still editable, so correct it before sending. Sending is a separate call with its own scope.
Review the drafts