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
| Status | How it's set |
|---|---|
draft | Set automatically by POST /invoices. |
sent | Set by the dashboard when you click Send. |
paid | Set automatically when the client pays via the portal. |
overdue | Set automatically when the due date passes without payment. |
void | Set 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
- API:
POST /clients— ensure the client record exists. - API:
POST /invoices— create the draft withclient_name,client_email,line_items,total, anddue_date. - Dashboard: Open the draft, review, and click Send.
- Webhook: Subscribe to
invoice.paidto 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"
}'