Kwill

Create a project and draft invoice

Create a new client, link a project to them, then create a draft invoice — all from a single script.

This guide chains three API calls to set up a client, a project, and a draft invoice ready for review in the dashboard.

APIs used: POST /clients · POST /projects · POST /invoices Related concepts: Draft-only invoices · Errors


Prerequisites

  • KWILL_API_KEY set in your environment
  • Workspace on the Studio plan or above

Step 1 — Create the client

A 201 response returns the client object. Copy the id for the next step.

curl -X POST https://usekwill.com/api/v1/clients \
  -H "Authorization: Bearer $KWILL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme Corp", "email": "billing@acme.com"}'

Step 2 — Create a project

Use the client's id as client_id, or use client_name and client_email to find-or-create:

curl -X POST https://usekwill.com/api/v1/projects \
  -H "Authorization: Bearer $KWILL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "<CLIENT_ID>",
    "name": "Website Redesign"
  }'

Step 3 — Create a draft invoice

Provide the client details, line items, total, and due date:

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": "2025-01-15"
  }'

The invoice is created as a draft. Open it in the dashboard to review and send it to the client. See Draft-only invoices for more context.


Complete script

// create-project-invoice.mjs — run with: node create-project-invoice.mjs
// Requires: KWILL_API_KEY in environment

const BASE = 'https://usekwill.com/api/v1';

async function kwillPost(path, body) {
  const res = await fetch(BASE + path, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.KWILL_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`POST ${path} failed ${res.status}: ${err.error ?? ''}`);
  }
  return res.json();
}

const client = await kwillPost('/clients', {
  name: 'Acme Corp',
  email: 'billing@acme.com',
});
console.log(`Client: ${client.id}`);

const project = await kwillPost('/projects', {
  client_id: client.id,
  name: 'Website Redesign',
});
console.log(`Project: ${project.id}`);

const invoice = await kwillPost('/invoices', {
  client_name: 'Acme Corp',
  client_email: 'billing@acme.com',
  line_items: [
    { description: 'Website Redesign', quantity: 1, rate: 2500 },
  ],
  total: 2500,
  due_date: '2025-01-15',
});
console.log(`Invoice: ${invoice.id}  status=${invoice.status}`);
console.log('Open the Kwill dashboard to review and send.');

On this page