API Reference
Invoices
Manage invoices and their lifecycle.
REST /api/v1API key authentication14 endpoints
GET
/api/v1/invoicesList invoices with filters
Query schema
const listQuerySchema = z.object({
contactId: z.string().uuid().optional(),
projectId: z.string().uuid().optional(),
status: z.enum(['draft', 'sent', 'viewed', 'partial', 'paid', 'overdue', 'void']).optional(),
dateFrom: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
dateTo: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
includeVoid: z
.string()
.transform((v) => v === 'true')
.optional(),
limit: z.coerce.number().int().min(1).max(100).default(50),
offset: z.coerce.number().int().min(0).default(0),
});Response200JSON response with data and pagination envelopes.
POST
/api/v1/invoicesCreate a new invoice
JSON body schema
const createBodySchema = z.object({
contactId: z.string().uuid().optional(),
attentionContactId: z.string().uuid().optional(),
projectId: z.string().uuid().optional(),
invoiceNumber: z.string().max(50).optional(),
issueDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
dueDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
billingAddress: z.string().optional(),
currency: z.string().length(3).default('AUD'),
openingStatement: z.string().optional(),
notes: z.string().optional(),
paymentTerms: z.string().optional(),
});Response201JSON response with a data envelope.
DELETE
/api/v1/invoices/:idDelete an invoice (draft only)
Path parametersid: string
Response204No response body.
GET
/api/v1/invoices/:idGet invoice by ID with lines
Path parametersid: string
Response200JSON response with a data envelope.
PATCH
/api/v1/invoices/:idUpdate an invoice (draft only)
Path parametersid: string
JSON body schema
const updateBodySchema = z.object({
contactId: z.string().uuid().optional(),
attentionContactId: z.string().uuid().nullable().optional(),
projectId: z.string().uuid().nullable().optional(),
invoiceNumber: z.string().max(50).optional(),
issueDate: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
dueDate: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
billingAddress: z.string().nullable().optional(),
currency: z.string().length(3).optional(),
openingStatement: z.string().nullable().optional(),
notes: z.string().nullable().optional(),
paymentTerms: z.string().nullable().optional(),
});Response200JSON response with a data envelope.
GET
/api/v1/invoices/:id/linesList all lines for an invoice
Path parametersid: string
Response200JSON response with a data envelope.
POST
/api/v1/invoices/:id/linesAdd a line to an invoice
Path parametersid: string
JSON body schema
const lineTypeEnum = z.enum([
'fixed',
'progress',
'from_time',
'from_expenses',
'previously_billed',
'group',
'notes',
]);
const createLineSchema = z.object({
description: z.string().min(1),
quantity: z.number().min(0).default(1),
unitValue: z.number().default(0),
taskId: z.string().uuid().optional(),
lineType: lineTypeEnum.default('fixed'),
sortOrder: z.number().int().min(0).optional(),
});Response201JSON response with a data envelope.
DELETE
/api/v1/invoices/:id/lines/:lineIdDelete an invoice line
Path parametersid: stringlineId: string
Response204No response body.
PATCH
/api/v1/invoices/:id/lines/:lineIdUpdate an invoice line
Path parametersid: stringlineId: string
JSON body schema
const lineTypeEnum = z.enum([
'fixed',
'progress',
'from_time',
'from_expenses',
'previously_billed',
'group',
'notes',
]);
const updateLineSchema = z.object({
description: z.string().min(1).optional(),
quantity: z.number().min(0).optional(),
unitValue: z.number().optional(),
taskId: z.string().uuid().nullable().optional(),
lineType: lineTypeEnum.optional(),
sortOrder: z.number().int().min(0).optional(),
});Response200JSON response with a data envelope.
GET
/api/v1/invoices/:id/paymentsList all payments for an invoice
Path parametersid: string
Response200JSON response with a data envelope.
POST
/api/v1/invoices/:id/paymentsRecord a payment for an invoice
Path parametersid: string
JSON body schema
const createPaymentSchema = z.object({
amount: z.number().positive(),
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
method: z.enum(['bank_transfer', 'check', 'credit_card', 'cash', 'other']).optional(),
reference: z.string().max(100).optional(),
notes: z.string().optional(),
});Response201JSON response with a data envelope.
DELETE
/api/v1/invoices/:id/payments/:paymentIdDelete a payment (manual payments only)
Path parametersid: stringpaymentId: string
Response204No response body.
POST
/api/v1/invoices/:id/sendMark invoice as sent
Path parametersid: string
JSON body schema
const sendBodySchema = z.object({
sendEmail: z.boolean().default(false),
emailRecipients: z.array(z.string().email()).optional(),
});Response200JSON response with a data envelope.
POST
/api/v1/invoices/:id/voidVoid an invoice
Path parametersid: string
JSON body schema
const voidBodySchema = z.object({
reason: z.string().optional(),
});Response200JSON response with a data envelope.