Kwill

Draft-only invoices

Why POST /invoices creates a draft and how to send invoices to clients.

POST /invoices always creates an invoice with status: "draft". It cannot be sent or marked as paid via the API.

{
  "id": "inv_…",
  "number": "INV-0042",
  "status": "draft",
  "total": 2500.00,
  "due_date": "2024-12-01",
  "createdAt": "2024-11-01T09:00:00Z"
}

Why writes stay in the dashboard

Sending an invoice to a client involves:

  • Email delivery with a branded PDF attachment
  • Payment collection via Stripe (card, ACH, bank transfer)
  • Client portal where the client views, accepts, and pays

These workflows involve external services (email, Stripe), user-configurable templates, and client-facing UI — they are intentionally kept in the Kwill dashboard rather than exposed as API operations.


Lifecycle from the API's perspective

StatusHow it's set
draftSet automatically by POST /invoices.
sentSet by the dashboard when you click Send.
paidSet automatically when the client pays via the portal.
overdueSet automatically when the due date passes without payment.
voidSet by the dashboard when you void the invoice.

The API can read invoices in any status. Use GET /invoices to list all invoices.


Typical integration pattern

  1. API: POST /clients — ensure the client record exists.
  2. API: POST /invoices — create the draft with client_name, client_email, line_items, total, and due_date.
  3. Dashboard: Open the draft, review, and click Send.
  4. Webhook: Subscribe to invoice.paid to be notified when payment is collected. See Webhooks.

Creating a draft invoice

curl -X POST https://usekwill.com/api/v1/invoices \
  -H "Authorization: Bearer $KWILL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Acme Corp",
    "client_email": "billing@acme.com",
    "line_items": [
      { "description": "Website Redesign", "quantity": 1, "rate": 2500 }
    ],
    "total": 2500,
    "due_date": "2024-12-01"
  }'

On this page