Opbox

Accounting & Invoices API

Create, manage, and track invoices with full lifecycle support. Invoices can be linked to matters, synced to external accounting software, and include aging analysis, revenue breakdowns, and dashboard-level statistics.

Endpoints

MethodEndpointDescription
GET/api/invoicesList invoices with optional filters
POST/api/invoicesCreate a new invoice (ADMIN/OWNER)
GET/api/invoices/:idGet a single invoice by ID
PATCH/api/invoices/:idUpdate an invoice (ADMIN/OWNER)
DELETE/api/invoices/:idDelete a draft invoice (ADMIN/OWNER)
POST/api/invoices/:id/syncPush invoice to external accounting system or pull status (ADMIN/OWNER)
GET/api/invoices/statsInvoice summary statistics and aging buckets
GET/api/accounting/statsDashboard-level accounting metrics (revenue, monthly trends, top clients)

List Invoices

Returns a paginated list of invoices for your workspace. Supports filtering by status, matter, and date range.

GET /api/invoices?status=AUTHORISED&matterId=cm_matter_789&from=2026-01-01&to=2026-02-28&page=1&pageSize=25

Query Parameters

ParameterTypeDescription
statusstringFilter by status: DRAFT, SUBMITTED, AUTHORISED, PAID, VOIDED, OVERDUE
matterIdstringFilter by linked matter ID
fromstringIssue date range start (YYYY-MM-DD)
tostringIssue date range end (YYYY-MM-DD)
pagenumberPage number (default: 1)
pageSizenumberResults per page (default: 25, max: 100)

Response

{
  "invoices": [
    {
      "id": "cm_invoice_abc123",
      "invoiceNumber": "INV-0012",
      "contactName": "Acme Corp",
      "contactEmail": "billing@acme.com",
      "currency": "USD",
      "subtotal": 5000,
      "taxTotal": 500,
      "total": 5500,
      "status": "AUTHORISED",
      "lineItems": [
        {
          "description": "Legal consultation - Q1 2026",
          "quantity": 10,
          "unitPrice": 500,
          "taxRate": 10,
          "amount": 5000
        }
      ],
      "issueDate": "2026-02-01T00:00:00.000Z",
      "dueDate": "2026-03-01T00:00:00.000Z",
      "paidDate": null,
      "externalId": null,
      "syncedAt": null,
      "notes": "Q1 retainer invoice",
      "reference": "PO-2026-041",
      "matter": {
        "id": "cm_matter_789",
        "title": "Acme Corp Onboarding",
        "number": 12,
        "numberPrefix": "MAT"
      },
      "createdBy": {
        "id": "cm_user_123",
        "name": "Jane Smith",
        "email": "jane@example.com"
      },
      "createdAt": "2026-02-01T10:00:00.000Z",
      "updatedAt": "2026-02-01T10:00:00.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "pageSize": 25,
    "total": 48,
    "totalPages": 2
  }
}

Create Invoice

Creates a new invoice in DRAFT status. Invoice numbers are auto-generated sequentially (e.g. INV-0001). Subtotal, tax, and total are computed server-side from line items. Requires ADMIN or OWNER role.

POST /api/invoices
Content-Type: application/json

Request Body

{
  "matterId": "cm_matter_789",
  "contactName": "Acme Corp",
  "contactEmail": "billing@acme.com",
  "currency": "USD",
  "lineItems": [
    {
      "description": "Legal consultation - Q1 2026",
      "quantity": 10,
      "unitPrice": 500,
      "taxRate": 10,
      "amount": 5000
    },
    {
      "description": "Document preparation",
      "quantity": 1,
      "unitPrice": 750,
      "taxRate": 10,
      "amount": 750
    }
  ],
  "issueDate": "2026-02-01",
  "dueDate": "2026-03-01",
  "notes": "Q1 retainer invoice",
  "reference": "PO-2026-041"
}

Body Fields

FieldTypeRequiredDescription
contactNamestringYesClient or contact name (max 255 chars)
contactEmailstringNoClient email address
matterIdstringNoLink invoice to a matter (must belong to your org)
currencystringNo3-letter currency code (default: USD)
lineItemsarrayYesAt least one line item (see line item schema below)
issueDatestringYesIssue date in YYYY-MM-DD format
dueDatestringYesDue date in YYYY-MM-DD format
notesstringNoInvoice notes (max 2000 chars)
referencestringNoExternal reference or PO number (max 255 chars)

Line Item Schema

FieldTypeDescription
descriptionstringLine item description (max 500 chars)
quantitynumberQuantity (must be positive)
unitPricenumberPrice per unit
taxRatenumberTax rate as a percentage, 0-100 (default: 0)
amountnumberLine total before tax

Response (201 Created)

{
  "id": "cm_invoice_abc123",
  "invoiceNumber": "INV-0012",
  "contactName": "Acme Corp",
  "contactEmail": "billing@acme.com",
  "currency": "USD",
  "subtotal": 5750,
  "taxTotal": 575,
  "total": 6325,
  "status": "DRAFT",
  "lineItems": [
    {
      "description": "Legal consultation - Q1 2026",
      "quantity": 10,
      "unitPrice": 500,
      "taxRate": 10,
      "amount": 5000
    },
    {
      "description": "Document preparation",
      "quantity": 1,
      "unitPrice": 750,
      "taxRate": 10,
      "amount": 750
    }
  ],
  "issueDate": "2026-02-01T00:00:00.000Z",
  "dueDate": "2026-03-01T00:00:00.000Z",
  "paidDate": null,
  "externalId": null,
  "syncedAt": null,
  "notes": "Q1 retainer invoice",
  "reference": "PO-2026-041",
  "matter": {
    "id": "cm_matter_789",
    "title": "Acme Corp Onboarding",
    "number": 12,
    "numberPrefix": "MAT"
  },
  "createdBy": {
    "id": "cm_user_123",
    "name": "Jane Smith",
    "email": "jane@example.com"
  },
  "createdAt": "2026-02-01T10:00:00.000Z",
  "updatedAt": "2026-02-01T10:00:00.000Z"
}

Get Invoice

Returns a single invoice by ID, including the linked matter and creator details.

GET /api/invoices/:id

Response

{
  "id": "cm_invoice_abc123",
  "invoiceNumber": "INV-0012",
  "contactName": "Acme Corp",
  "contactEmail": "billing@acme.com",
  "currency": "USD",
  "subtotal": 6000,
  "taxTotal": 600,
  "total": 6600,
  "status": "SUBMITTED",
  "lineItems": [
    {
      "description": "Legal consultation - Q1 2026",
      "quantity": 12,
      "unitPrice": 500,
      "taxRate": 10,
      "amount": 6000
    }
  ],
  "issueDate": "2026-02-01T00:00:00.000Z",
  "dueDate": "2026-03-01T00:00:00.000Z",
  "paidDate": null,
  "externalId": null,
  "syncedAt": null,
  "notes": "Updated with additional hours",
  "reference": "PO-2026-041",
  "matter": {
    "id": "cm_matter_789",
    "title": "Acme Corp Onboarding",
    "number": 12,
    "numberPrefix": "MAT"
  },
  "createdBy": {
    "id": "cm_user_123",
    "name": "Jane Smith",
    "email": "jane@example.com"
  },
  "createdAt": "2026-02-01T10:00:00.000Z",
  "updatedAt": "2026-02-10T14:30:00.000Z"
}

Update Invoice

Updates an existing invoice. All fields are optional. When line items are updated, subtotal, tax, and total are recalculated automatically. Setting status to PAID will auto-set paidDate to the current date if not provided. Requires ADMIN or OWNER role.

PATCH /api/invoices/:id
Content-Type: application/json

Request Body

{
  "status": "SUBMITTED",
  "lineItems": [
    {
      "description": "Legal consultation - Q1 2026",
      "quantity": 12,
      "unitPrice": 500,
      "taxRate": 10,
      "amount": 6000
    }
  ],
  "notes": "Updated with additional hours"
}

Updatable Fields

FieldTypeDescription
statusstringTransition status: DRAFT, SUBMITTED, AUTHORISED, PAID, VOIDED, OVERDUE
contactNamestringUpdated contact name
contactEmailstringUpdated contact email
lineItemsarrayReplacement line items (recalculates totals)
paidDatestring | nullPayment date (YYYY-MM-DD) or null to clear
issueDatestringUpdated issue date (YYYY-MM-DD)
dueDatestringUpdated due date (YYYY-MM-DD)
notesstringInvoice notes (max 2000 chars)
referencestringExternal reference or PO number

Delete Invoice

Deletes an invoice. Only invoices with DRAFT status can be deleted. Non-draft invoices should be voided instead. Requires ADMIN or OWNER role.

DELETE /api/invoices/:id

Response

{ "success": true }

Error (409 Conflict)

{ "error": "Only draft invoices can be deleted. Void the invoice instead." }

Invoice Statistics

Returns aggregate invoice statistics including counts by status, outstanding and overdue amounts, monthly paid totals, and aging buckets. Aging buckets group overdue invoices by how many days past due: 0-15, 15-30, 30-60, and 60+ days.

GET /api/invoices/stats

Response

{
  "statusCounts": {
    "DRAFT": 5,
    "SUBMITTED": 8,
    "AUTHORISED": 12,
    "PAID": 30,
    "VOIDED": 2,
    "OVERDUE": 3
  },
  "totalOutstanding": 42500,
  "totalOverdue": 8200,
  "totalPaidThisMonth": 15750,
  "totalInvoiced": 185000,
  "agingBuckets": {
    "current": { "count": 4, "amount": 12000 },
    "days15": { "count": 3, "amount": 9500 },
    "days30": { "count": 2, "amount": 6800 },
    "days60plus": { "count": 1, "amount": 3200 }
  },
  "totalCount": 60
}

Aging Buckets

BucketRangeDescription
current0-15 daysRecently overdue invoices
days1515-30 daysModerately overdue
days3030-60 daysSignificantly overdue
days60plus60+ daysSeverely overdue, requires immediate attention

Accounting Dashboard Stats

Returns comprehensive accounting metrics for dashboard widgets: revenue summary, monthly revenue trends (last 12 months), revenue by fee category and board, and top clients ranked by total invoiced amount.

GET /api/accounting/stats

Response

{
  "summary": {
    "totalRevenue": 152500,
    "outstandingAmount": 42500,
    "currency": "USD",
    "invoiceCounts": {
      "draft": 5,
      "submitted": 8,
      "authorised": 12,
      "paid": 30,
      "overdue": 3,
      "voided": 2,
      "total": 60
    }
  },
  "monthlyRevenue": [
    { "month": "Mar 2025", "paid": 8200, "invoiced": 12500 },
    { "month": "Apr 2025", "paid": 9800, "invoiced": 14000 },
    { "month": "...", "paid": 0, "invoiced": 0 },
    { "month": "Feb 2026", "paid": 15750, "invoiced": 18200 }
  ],
  "revenueByFeeCategory": [
    { "category": "Legal Consultation", "revenue": 85000, "fees": 4250, "count": 34 },
    { "category": "Document Preparation", "revenue": 32000, "fees": 1600, "count": 18 },
    { "category": "Uncategorized", "revenue": 12500, "fees": 625, "count": 8 }
  ],
  "revenueByBoard": [
    { "id": "cm_template_abc", "name": "Client Onboarding", "total": 65000, "paid": 48000, "count": 22 },
    { "id": "cm_template_def", "name": "Compliance Review", "total": 42000, "paid": 35000, "count": 15 }
  ],
  "topIndividuals": [
    { "name": "Acme Corp", "email": "billing@acme.com", "total": 32500, "paid": 28000, "count": 8 },
    { "name": "Globex Inc", "email": "finance@globex.com", "total": 24000, "paid": 24000, "count": 6 }
  ]
}

Response Sections

SectionDescription
summaryTotal revenue, outstanding amount, primary currency, and counts by invoice status
monthlyRevenueLast 12 months of paid and invoiced amounts per month
revenueByFeeCategoryRevenue and fee totals grouped by matter line item fee category
revenueByBoardTotal and paid revenue grouped by matter board (template)
topIndividualsTop 10 individuals ranked by total invoiced amount, with paid breakdown

Accounting Sync

Syncs an invoice with external accounting software. Supports two actions: push (create or update the invoice externally) and pull (fetch the latest status from external system). Requires an active accounting integration configured in Settings > Integrations. Voided invoices cannot be pushed. Requires ADMIN or OWNER role.

POST /api/invoices/:id/sync
Content-Type: application/json

Request Body

FieldTypeDescription
actionstringpush (default) to send to external system, or pull to fetch latest status

Push Response

Creates the invoice in the external system and stores the external invoice ID. Draft invoices are pushed as DRAFT, all others as AUTHORISED.

{
  "invoice": {
    "id": "cm_invoice_abc123",
    "invoiceNumber": "INV-0012",
    "status": "AUTHORISED",
    "externalId": "acc_inv_a1b2c3d4",
    "syncedAt": "2026-02-10T14:30:00.000Z",
    "contactName": "Acme Corp",
    "total": 6600
  },
  "externalInvoiceId": "acc_inv_a1b2c3d4",
  "externalStatus": "AUTHORISED"
}

Pull Response

Fetches the current status from the external system and updates the local invoice. Only works for invoices that have been previously pushed (have an externalId).

{
  "invoice": {
    "id": "cm_invoice_abc123",
    "invoiceNumber": "INV-0012",
    "status": "PAID",
    "externalId": "acc_inv_a1b2c3d4",
    "syncedAt": "2026-02-15T09:00:00.000Z",
    "paidDate": "2026-02-14T00:00:00.000Z",
    "contactName": "Acme Corp",
    "total": 6600
  },
  "externalStatus": "PAID"
}

Invoice Status Lifecycle

StatusDescription
DRAFTInvoice created but not yet sent. Can be edited or deleted.
SUBMITTEDInvoice sent to the client, awaiting approval.
AUTHORISEDInvoice approved and awaiting payment.
PAIDInvoice fully paid. Sets paidDate automatically.
OVERDUEInvoice past due date and unpaid.
VOIDEDInvoice cancelled. Cannot be synced externally or deleted.

Permissions

  • Read: All authenticated workspace members can list and view invoices and stats.
  • Create / Update / Delete: Requires ADMIN or OWNER role.
  • Accounting Sync: Requires ADMIN or OWNER role and an active accounting integration.
  • Security: All changes require authentication.
  • Audit: All create, update, and delete operations are logged to the audit trail.