expense_create
Logs a new expense — amount_cents must be integer CENTS (a decimal string via amount also works, and category resolves to a category_id by name). A same-amount, same-UTC-day duplicate for the same user is refused as CONFLICT unless you resend identically with force: true. Status is honor-or-refuse: admin/owner creators land 'approved' by default (or may request it explicitly), everyone else always starts 'draft'. NEXT: expense_submit sends a draft into the approval queue.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| cost | No | Alias of amount — same decimal money STRING parsing. | |
| date | No | YYYY-MM-DD (omitted = today). | |
| force | No | Resend an identical expense_create with force: true to save it despite a same-amount, same-UTC-day duplicate match; omitted or false leaves the duplicate check refusing with CONFLICT. | |
| notes | No | ||
| total | No | Alias of amount — same decimal money STRING parsing. | |
| amount | No | Decimal money STRING ("23.50") — the platform converts; integer CENTS ($23.50 → 2350) via amount_cents is also accepted. | |
| status | No | ||
| vendor | No | ||
| category | No | Category by name or slug, e.g. 'food'. | |
| currency | No | ||
| ocr_json | No | ||
| tax_type | No | ||
| tags_json | No | ||
| approved_at | No | ||
| approved_by | No | ||
| category_id | No | ||
| description | No | Alias of notes — used only when notes is not also supplied. | |
| receipt_key | No | ||
| rejected_at | No | ||
| amount_cents | No | ||
| expense_date | No | ||
| submitted_at | No | ||
| tax_rate_bps | No | ||
| category_name | No | Alias of category — resolves to category_id by name or slug. | |
| recurrence_id | No | ||
| reimbursed_at | No | ||
| subtotal_cents | No | ||
| rejection_reason | No | ||
| tax_amount_cents | No |