Bills
Bills represent accounts payable — money your business owes to vendors for goods or services received.
Bill Status Flow
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
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_amountis in cents.45000= $450.00.typeisone_timeorrecurring.
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:
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:
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:
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:
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
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
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:
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
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.