Expenses API

Create an Expense

POST /api/v2/expenses

Creates a project expense. For LLM cost tracking, use the “LLM Usage” expense category from your company.

Request Body

Field Type Required Description
project_id string Yes Project ID
expense_category_id string Yes Expense category ID
spent_date string Yes Date of expense (YYYY-MM-DD)
total_cost number Yes* Total cost amount
units number Yes* Quantity
notes string No Description
billable boolean No Whether the expense is billable
source string No web, cli, api, or agent
metadata object No JSON object, max 4KB

*Provide either total_cost or units.

Example Request

curl -X POST https://app.keito.ai/api/v2/expenses \
  -H "Authorization: Bearer kto_xxxxx" \
  -H "Keito-Account-Id: your_company_id" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "project_id_here",
    "expense_category_id": "category_id_here",
    "spent_date": "2026-05-05",
    "total_cost": 0.135,
    "notes": "LLM usage for review session",
    "source": "agent",
    "metadata": {
      "session_id": "550e8400-e29b-41d4-a716-446655440000",
      "model": "claude-opus-4-6",
      "input_tokens": 30000,
      "output_tokens": 15000
    }
  }'

List Expenses

GET /api/v2/expenses

Returns a paginated list of expenses.

Query Parameters

Parameter Type Description
page number Page number
per_page number Results per page
source string Filter by source
project_id string Filter by project
client_id string Filter by client
user_id string Filter by user
from string Start date, inclusive
to string End date, inclusive
is_billed boolean Filter billed status
invoice_id string Filter expenses linked to a Keito invoice ID
updated_since string ISO timestamp lower bound

Example Request

curl "https://app.keito.ai/api/v2/expenses?source=agent&from=2026-05-01" \
  -H "Authorization: Bearer kto_xxxxx" \
  -H "Keito-Account-Id: your_company_id"

Invoice Linkage

Expense responses include the read-only invoice_id field:

Field Type Description
invoice_id string or null The Keito invoice ID linked to the expense, or null when no Keito invoice link exists

The link covers expenses attached directly to an invoice line and expenses included in a grouped invoice line. It is a Keito invoice ID, never a Harvest invoice ID or an invoice number. Use it with the Invoices API when your credential has permission to read that invoice.

is_billed: true does not guarantee an invoice link. Expenses marked billed manually or imported as billed without a Keito invoice link return invoice_id: null. Do not infer an invoice from billed status.

To list an invoice’s linked expenses, pass its ID:

curl "https://app.keito.ai/api/v2/expenses?invoice_id=invoice_id_here" \
  -H "Authorization: Bearer kto_xxxxx" \
  -H "Keito-Account-Id: your_company_id"

The filter combines with existing filters and pagination and only narrows expenses your credential can already read. Do not send invoice_id in POST or PATCH requests; invoice linkage is managed through the invoice workflow.

Personal read-only sync keys cannot call the Expenses API.