API reference

Accounting expenses

Create and inspect paid, reconciled expenses in your workspace accounting records. In live mode, every expense also creates its linked accounting outflow transaction; successful creations fire expense.created.

https://api.mytabulon.com/v1

List expenses

Use exact reference lookups to reconcile external processors safely, or filter by vendor, category, and expense date. Pagination uses the standard limit and offset envelope.

GET/accounting/expensesaccounting.expenses.read

List expenses. Filters: reference, vendor, category, created_at_gte, created_at_lte, limit, offset.

response
{
  "object": "list",
  "url": "/v1/accounting/expenses",
  "data": [
    {
      "object": "expense",
      "id": "019f...",
      "vendor": "Dodo Payments",
      "category": "operations",
      "amount": "1091.76",
      "currency": "NGN",
      "exchange_rate": "1.00000000",
      "amount_base": "1091.76",
      "expense_date": "2026-07-28",
      "status": "paid",
      "reference": "dodo:pay_example:payment_fees",
      "is_reconciled": true,
      "chart_account_code": "6000",
      "chart_account_name": "Operations Expense"
    }
  ],
  "total": 1,
  "limit": 25,
  "offset": 0,
  "has_more": false
}

Create an expense

vendor, a positive amount, and a stable reference are required. New live-mode expenses are marked paid and reconciled, assigned to an expense chart account, and mirrored into the accounting transaction ledger as an outflow.

POST/accounting/expensesaccounting.expenses.write

Create a paid, reconciled expense. Send an Idempotency-Key header for transport-safe retries.

request
{
  "vendor": "Dodo Payments",
  "category": "operations",
  "description": "Dodo processor fee for pay_example",
  "amount": 1091.76,
  "currency": "NGN",
  "expense_date": "2026-07-28",
  "payment_method": "dodo_balance",
  "reference": "dodo:pay_example:payment_fees",
  "tax_treatment": "standard_expense",
  "tax_rate": 0,
  "tax_amount": 0
}
response
{
  "object": "expense",
  "id": "019f...",
  "vendor": "Dodo Payments",
  "category": "operations",
  "amount": "1091.76",
  "currency": "NGN",
  "exchange_rate": "1.00000000",
  "amount_base": "1091.76",
  "expense_date": "2026-07-28",
  "payment_method": "dodo_balance",
  "status": "paid",
  "reference": "dodo:pay_example:payment_fees",
  "is_reconciled": true,
  "chart_account_code": "6000",
  "chart_account_name": "Operations Expense",
  "created": true
}

References and duplicate protection

Treat reference as the immutable external accounting identifier. Repeating a reference with the same vendor, category, currency, amount, and base amount returns the existing expense with created: false. Reusing it with different accounting values returns HTTP 409 with code reference_conflict. This reference check complements the Idempotency-Key header, so duplicate protection survives a lost client-side state file.

Currency and chart accounts

The workspace currency is the base currency. When the expense currency differs, include a positive exchange_rate; amount_base is calculated as amount × exchange_rate and rounded to two decimals. Pass chart_account_id to use an active expense account in the workspace, or omit it to use Operations Expense (code 6000). Optional tax fields are tax_treatment, tax_rate, and tax_amount.

Test and live parity

The core create/list contract and reference-based duplicate protection are available with mtb_test_ and mtb_live_ keys. Test keys write isolated sandbox expense objects and never modify live accounting tables. Move to production by swapping to a live key carrying accounting.expenses.read and/or accounting.expenses.write.