> ## Documentation Index
> Fetch the complete documentation index at: https://docs.billbooks.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Log expenses via API

> Recording expenses, how invoice-linking works, and a gap you should know about

Expenses can stand alone (just a record of money spent) or get linked to an invoice so a client is billed for them. That link is one-directional and system-managed, and there's a real gap in how deletion is guarded that's worth reading before you build against this endpoint.

## Create an expense

```bash theme={null}
curl -X POST https://app.billbooks.com/api/public-api/v1/expenses \
  -H "Authorization: Bearer bb_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "date": "2026-08-18",
    "amount": 84.50,
    "vendor": "Adobe",
    "category_id": 6,
    "client_id": 4821,
    "billable": true,
    "currency": "USD"
  }'
```

<Warning>
  Don't send `is_invoiced` or `invoice_id` on create, even set to `false` or `0`. Submitting either field at all rejects the entire request with `422`. Those two fields are system-managed and only ever get set by the Invoices endpoint's own linking logic, when a line item on an invoice bills this expense.
</Warning>

## How invoice-linking actually happens

There's no "link this expense to that invoice" call on the Expenses endpoint. The link is created from the other direction: when you create or edit an invoice and include a line item with an `expense_id`, that's what sets the expense's `is_invoiced` and `invoice_id` fields. See [Create and send an invoice](/guides/create-and-send-an-invoice) for the invoice side of this.

If you edit that invoice later and remove the line referencing the expense (remember, `items` is a full replace on invoice `PUT`), the link is reversed as part of that edit.

## List and filter expenses

```bash theme={null}
curl "https://app.billbooks.com/api/public-api/v1/expenses?filter[status]=unbilled&filter[datestart]=2026-08-01&filter[dateend]=2026-08-31" \
  -H "Authorization: Bearer bb_live_your_key_here"
```

Available filters: `vendor`, `category_id`, `client_id`, `project_id`, `datestart`/`dateend` (date range), `currency`, and free-text `q`. `filter[status]` accepts pass-through pseudo-filters like `unbilled`, `invoiced`, `billable`, `non-billable`, `withreceipts`, `withoutreceipts`, and `recurring`, not independently re-validated by this endpoint, they're whatever the underlying expense model accepts.

## Deleting an expense

```bash theme={null}
curl -X DELETE "https://app.billbooks.com/api/public-api/v1/expenses?id=203" \
  -H "Authorization: Bearer bb_live_your_key_here"
```

<Warning>
  This is a real gap, not a documented design choice: deleting an expense has no guard rail at all, unlike Clients or Items, which block deletion when the record is already in use. An expense that's already linked to an invoice (`is_invoiced` is true) can be deleted outright through this endpoint. Doing so orphans the invoice line item that references it, the invoice keeps the line, but the expense record behind it is gone.
</Warning>

If your integration deletes expenses programmatically, check `is_invoiced` yourself first and treat a `true` value as a reason to hold off, the API won't stop you.

## What's next

* [Create and send an invoice](/guides/create-and-send-an-invoice) for how `expense_id` on a line item creates the link
* [Errors](/errors) for the full error envelope shape
