Zeng Book
ProductIndustriesIntegrationsPricingResources
Sign inContact salesTry it free
Introduction
  • Overview
  • Quickstart
API reference
  • Authentication
  • Errors
  • Rate limits
  • Pagination
  • Interactive explorer
Resources
  • Organization
  • Leads
  • Clients
  • Projects
  • Quotations
  • Invoices
Integrations
  • Overview
  • Webhooks
  • Public portal
  • Zapier
  • Make / n8n recipes
  • Xero (coming soon)

Resources

Invoices

Invoices are issued documents, optionally linked to a quotation. The detail endpoint includes line items and recorded payments.

List invoices

GET/api/v1/invoices

Returns invoices in your org, newest first, cursor-paginated.

Query parameters:

  • limit, cursor — see pagination.
  • status — optional, one of DRAFT, SENT, PAID, OVERDUE, VOID.
terminal
curl "https://www.zengbook.com/api/v1/invoices?status=OVERDUE" \
  -H "Authorization: Bearer zb_live_..."
200 OK (list)
{
  "data": [
    {
      "id": "inv_01HX...",
      "number": "INV-2026-0117",
      "title": "Progress claim #2 — May",
      "status": "OVERDUE",
      "clientId": "cli_01HX...",
      "projectId": "prj_01HX...",
      "quotationId": "qtn_01HX...",
      "notes": null,
      "issuedAt": "2026-04-30T00:00:00.000Z",
      "dueDate": "2026-05-14T00:00:00.000Z",
      "gstRateAtIssue": 0.09,
      "retentionPct": 0.05,
      "createdAt": "2026-04-30T01:22:14.000Z",
      "updatedAt": "2026-05-15T00:00:01.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "eyJpZC..."
}

Get an invoice

GET/api/v1/invoices/{id}

Returns one invoice, including its line items (sorted by sortOrder asc) and recorded payments (newest first).

terminal
curl https://www.zengbook.com/api/v1/invoices/inv_01HX... \
  -H "Authorization: Bearer zb_live_..."
200 OK (detail)
{
  "id": "inv_01HX...",
  "number": "INV-2026-0117",
  "title": "Progress claim #2 — May",
  "status": "OVERDUE",
  "clientId": "cli_01HX...",
  "projectId": "prj_01HX...",
  "quotationId": "qtn_01HX...",
  "notes": null,
  "issuedAt": "2026-04-30T00:00:00.000Z",
  "dueDate": "2026-05-14T00:00:00.000Z",
  "gstRateAtIssue": 0.09,
  "retentionPct": 0.05,
  "items": [
    {
      "id": "ili_01HX...",
      "description": "Phase 2 — Carpentry installation (40%)",
      "qty": 1,
      "unitPrice": 18000,
      "sortOrder": 0
    }
  ],
  "payments": [
    {
      "id": "pmt_01HX...",
      "amount": 5000,
      "paidAt": "2026-05-09T00:00:00.000Z",
      "method": "BANK_TRANSFER",
      "note": "Partial — DBS FAST"
    }
  ],
  "createdAt": "2026-04-30T01:22:14.000Z",
  "updatedAt": "2026-05-15T00:00:01.000Z"
}

Status lifecycle

  • DRAFT — created but not issued.
  • SENT — issued; due date set.
  • PAID — full payment recorded.
  • OVERDUE — past dueDate without full payment. Set automatically by an hourly cron.
  • VOID — cancelled; no further mutations expected.

Computing totals

The same algorithm as quotations applies. Subtotal → retention → net → GST → total. The payments array tells you how much is still outstanding:

typescript
const subtotal = items.reduce((s, it) => s + it.qty * it.unitPrice, 0)
const retention = subtotal * (inv.retentionPct ?? 0)
const net = subtotal - retention
const gst = net * inv.gstRateAtIssue
const total = net + gst

const paid = payments.reduce((s, p) => s + p.amount, 0)
const outstanding = total - paid

Related webhook events

  • invoice.created
  • invoice.sent
  • invoice.paid
  • invoice.overdue (fired by the hourly cron)
  • invoice.voided
  • payment.recorded

See the event reference for payload shapes.