# Invoices

> Create and manage invoices — accounts receivable workflows.

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

---

# 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](/docs/guides/recurring)).

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](/docs/guides/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`).
