API Reference

Invoices

Manage invoices and their lifecycle.

REST /api/v1API key authentication14 endpoints
GET/api/v1/invoices

List 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/invoices

Create 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/:id

Delete an invoice (draft only)

Path parametersid: string
Response204No response body.
GET/api/v1/invoices/:id

Get invoice by ID with lines

Path parametersid: string
Response200JSON response with a data envelope.
PATCH/api/v1/invoices/:id

Update 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/lines

List all lines for an invoice

Path parametersid: string
Response200JSON response with a data envelope.
POST/api/v1/invoices/:id/lines

Add 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/:lineId

Delete an invoice line

Path parametersid: stringlineId: string
Response204No response body.
PATCH/api/v1/invoices/:id/lines/:lineId

Update 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/payments

List all payments for an invoice

Path parametersid: string
Response200JSON response with a data envelope.
POST/api/v1/invoices/:id/payments

Record 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/:paymentId

Delete a payment (manual payments only)

Path parametersid: stringpaymentId: string
Response204No response body.
POST/api/v1/invoices/:id/send

Mark 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/void

Void an invoice

Path parametersid: string
JSON body schema
const voidBodySchema = z.object({
  reason: z.string().optional(),
});
Response200JSON response with a data envelope.