# Bills

> Create and manage bills — accounts payable workflows.

- **Category:** Guides
- HTML version: https://www.ondayzero.com/docs/guides/bills
- All guides: https://www.ondayzero.com/docs/guides/index.md
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

# Bills

Bills represent **accounts payable** — money your business owes to vendors for goods or services received.

## Bill Status Flow

```text
draft → forecasted (approved) → received → partially_paid → paid
      ↘ pending_approval ──────↗          ↘ canceled
```

| Status | Description |
|--------|-------------|
| `draft` | Editable, not yet approved. Not in the general ledger |
| `pending_approval` | Submitted for AP approval (when the approval workflow is enabled). Posts to the ledger only once approved and received |
| `forecasted` | Approved, awaiting receipt |
| `received` | Goods/services received; the AP journal entry has been posted |
| `partially_paid` | Some payment linked |
| `paid` | Fully paid via linked bank transaction(s) |
| `canceled` | Cancelled |

## Create a Bill

```bash
curl -X POST "https://api.ondayzero.com/api/v1/bills" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_id": "019ab37c-ae0d-7000-8000-000000000001",
    "description": "March office supplies",
    "type": "one_time",
    "expected_amount": 45000,
    "expected_paid_on_date": "2026-05-01",
    "bill_number": "INV-2026-0311"
  }'
```

> `expected_amount` is in cents. `45000` = $450.00. `type` is `one_time` or `recurring`.

Optional: `currency`, `s3_key` (an uploaded document to attach — see [File Uploads](/docs/guides/uploads)), `recurring` (schedule — see [Recurring Templates](/docs/guides/recurring)), and `submitted_for_review: true` to flag a client-submitted expense for the assigned advisor.

### Shortcut: create directly as received

If the bill has already arrived, skip the approve → receive steps and post it in one call:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/bills/received" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_id": "019ab37c-ae0d-7000-8000-000000000001",
    "amount": 45000,
    "ledger_id": "EXPENSE_LEDGER_UUID",
    "received_on": "2026-03-20",
    "due_on": "2026-04-30",
    "bill_number": "INV-2026-0311",
    "description": "March office supplies"
  }'
```

Pass `line_items` (`[{amount, description, ledger_id}]`) instead of a single `ledger_id` to split the expense across accounts.

### AI extraction from documents

Upload the vendor's PDF first (`POST /api/v1/bills/upload`, multipart `file`, returns an `s3_key`), then:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/bills/ai-create" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "single_bill_s3_keys": ["uploaded-file-key.pdf"]
  }'
```

`multi_bill_s3_key` handles one file containing several bills; `pasted_text` extracts from raw text. Extracted bills are created as drafts for review.

## Approve a Bill

Draft bills must be approved before they can be received or paid:

```bash
curl -X PATCH "https://api.ondayzero.com/api/v1/bills/{bill_id}/approval" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

This moves `draft` → `forecasted`. Businesses with the AP approval workflow enabled use `POST /api/v1/bills/{bill_id}/submit-for-ap-approval` instead, which moves the bill to `pending_approval` until an approver signs off.

## Mark as Received

When goods or services are received, record the final amount and the expense account:

```bash
curl -X PATCH "https://api.ondayzero.com/api/v1/bills/{bill_id}/receipt" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 45000,
    "ledger_id": "EXPENSE_LEDGER_UUID",
    "received_on": "2026-03-20",
    "due_on": "2026-04-30"
  }'
```

This posts the accounts payable journal entry (expense debit, AP credit). `amount` and `ledger_id` are required; `journal_entry_date` defaults to `received_on`. The bill must be `forecasted` (or `pending_approval` with approval granted) — receiving a `draft` returns `400`.

## Record a Payment

```bash
curl -X POST "https://api.ondayzero.com/api/v1/bills/{bill_id}/payments" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "transaction_id": "BANK_TRANSACTION_UUID",
    "amount": 45000,
    "paid_on": "2026-04-28"
  }'
```

A partial amount moves the bill to `partially_paid`; when payments cover the full balance the status becomes `paid`. `GET /api/v1/bills/{bill_id}/payments` lists them and `DELETE …/payments/{payment_id}` unlinks one. To split a single bank transaction across several bills (and optionally book the remainder straight to expense), use `POST /api/v1/bills/payments/batch`.

`PATCH /api/v1/bills/{bill_id}/payment-initiation` with `{"initiated": true}` flags a bill whose payment has been sent but hasn't cleared the bank yet.

## List Bills

```bash
curl "https://api.ondayzero.com/api/v1/bills?status=received&sort_by=expected_paid_on_date&descending=false" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

### Filter Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `status` | string | `draft`, `pending_approval`, `forecasted`, `received`, `partially_paid`, `paid`, `canceled` |
| `vendor_id` | UUID | Filter by vendor |
| `vendor_search` | string | Filter by vendor name (partial match) |
| `bill_number` | string | Exact bill number |
| `search` | string | Text search on bill fields |
| `payment_method` | string | Filter by payment method |
| `due_date_from` / `due_date_to` | date | Due-date range |

Plus the standard [pagination](/docs/guides/pagination) parameters. `GET /api/v1/bills/aging` returns the AP aging summary; `GET /api/v1/bills/upcoming` lists expected-but-not-yet-received bills.

## Payment Suggestions

DayZero can automatically match bank transactions to open bills:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/bills/payment-suggestions/trigger" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"min_confidence": 0.8}'
```

Review them with `GET /api/v1/bills/payment-suggestions`, then `POST …/payment-suggestions/{suggestion_id}/accept` or `/reject` individually, or `POST …/payment-suggestions/bulk-approve` with `{"min_confidence": 0.9}` to accept everything above a threshold.

## Cancel or Delete a Bill

```bash
curl -X PATCH "https://api.ondayzero.com/api/v1/bills/{bill_id}/cancellation" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

Cancelling keeps the record with status `canceled`. `DELETE /api/v1/bills/{bill_id}` removes a bill outright (soft delete); add `?force=true` to delete one that already has associated records such as payments or a journal entry.
