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), recurring (schedule — see Recurring Templates), 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 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.