Invoices

Invoices represent accounts receivable — money owed to your business by customers.

Invoice Status Flow

text
draft → open (finalized) → partially_paid → manual_paid / stripe_paid
                          ↘ void / uncollectible
Status Description
draft Editable, not yet issued. No journal entry, nothing in Stripe
open Finalized, awaiting payment
partially_paid Some payment received
stripe_paid Fully paid through the Stripe payment link
manual_paid Fully paid via linked bank transaction(s)
void Cancelled after finalization
uncollectible Written off as bad debt

Create an Invoice

bash
curl -X POST "https://api.ondayzero.com/api/v1/invoices" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "019ab37c-c057-7000-8000-000000000001",
    "due_date": "2026-11-01",
    "description": "October retainer",
    "line_items": [
      {
        "description": "Monthly retainer",
        "quantity": 1,
        "unit_price": 250000
      },
      {
        "variant_id": "019ab37c-0a71-7000-8000-000000000001",
        "quantity": 3
      }
    ]
  }'

unit_price is in cents. 250000 = $2,500.00.

Two kinds of line item:

  • Custom — omit variant_id (or send "custom"); description and unit_price are required, quantity defaults to 1.
  • Catalog — pass a product variant_id (or a catalog_item_id) and a quantity; the catalog price applies unless you send unit_price to override it.

Optional fields: issue_date, invoice_number (otherwise assigned on finalize), currency, project_id, fulfillment_location_id (warehouse to deduct inventory from), historical: true (import an already-issued invoice without side effects), and recurring (see Recurring Templates).

The invoice is created as a draft. Edit it with PUT /api/v1/invoices/{invoice_id} (send the fields you want to change plus id); delete a draft with DELETE /api/v1/invoices/{invoice_id}.

Finalize an Invoice

Draft invoices must be finalized before they can be sent or paid:

bash
curl -X PUT "https://api.ondayzero.com/api/v1/invoices/{invoice_id}/finalize" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Finalization moves the status to open, assigns the invoice number if it was blank, posts the AR journal entry, and — when Stripe is connected — creates the Stripe invoice so a hosted payment link exists. Only draft invoices can be finalized.

Send an Invoice

bash
curl -X POST "https://api.ondayzero.com/api/v1/invoices/{invoice_id}/send" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"attach_pdf": true, "cc_sender": false, "custom_message": "Thanks for your business!"}'

GET /api/v1/invoices/{invoice_id}/pdf returns a fresh PDF URL; PUT /api/v1/invoices/{invoice_id}/delivered marks an invoice delivered when you send it yourself.

List Invoices

bash
curl "https://api.ondayzero.com/api/v1/invoices?status=open&sort_by=due_date&descending=false&limit=50" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Filters: status, customer_id, number, search, due_date_from / due_date_to, product_id / variant_id, plus the standard pagination parameters. GET /api/v1/invoices/aging returns the AR aging summary and GET /api/v1/invoices/metrics the headline numbers.

Stripe Payment Links

If Stripe is connected, finalized invoices carry a hosted_invoice_url for customers to pay online; GET /api/v1/invoices/{invoice_id}/payment-link returns it on demand. Payments made there are recorded automatically via Stripe webhooks and move the invoice to stripe_paid. POST /api/v1/invoices/{invoice_id}/stripe/sync re-checks Stripe if a payment seems to be missing.

Record a Manual Payment

Link a bank transaction to the invoice:

bash
curl -X POST "https://api.ondayzero.com/api/v1/invoices/{invoice_id}/payments" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{"transaction_id": "TRANSACTION_UUID", "amount": 250000, "paid_on": "2026-10-28"}'

Partial amounts move the invoice to partially_paid; paying the balance moves it to manual_paid. Payments can be updated (PATCH …/payments/{payment_id}), removed (DELETE), or moved to another invoice (POST …/payments/{payment_id}/move). GET /api/v1/invoices/suggestions lists AI-matched transaction/invoice pairs you can accept or reject, and POST /api/v1/invoices/bulk-payments records many payments at once.

If you don't have a transaction to link, PUT /api/v1/invoices/{invoice_id}/paid marks the invoice paid outright (and /unpaid reverses that).

Void an Invoice

bash
curl -X PUT "https://api.ondayzero.com/api/v1/invoices/{invoice_id}/void" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"

Voiding reverses the AR journal entry and voids the Stripe invoice if there is one. Only open invoices can be voided: drafts should be deleted instead, and paid invoices cannot be voided (remove the payments first, or write the balance off with PUT /api/v1/invoices/{invoice_id}/uncollectible).