Billing API 🟡 BETA

Invoicing, payments, quotes, tax rates, and recurring billing management.


Base URL

/api/billing

Authentication

All endpoints require a valid session token via Authorization: Bearer <token> header. Invoice voiding and deletion require admin or billing_admin role.


Endpoints

Invoices

GET /api/billing/invoices

Lists invoices with optional filters.

ParameterTypeRequiredDescription
statusstringNodraft, sent, paid, overdue, void
customer_idstringNoFilter by customer
fromstringNoISO 8601 start date
tostringNoISO 8601 end date
pageintegerNoPage number (default: 1)
limitintegerNoItems per page (default: 20)

Response:

{
  "invoices": [
    {
      "id": "inv_001",
      "number": "INV-2025-0042",
      "customer_id": "cust_001",
      "customer_name": "Acme Corp",
      "status": "sent",
      "total": 5400.00,
      "currency": "BRL",
      "due_date": "2025-06-15",
      "issued_at": "2025-06-01T10:00:00Z",
      "paid_at": null
    }
  ],
  "total": 42,
  "page": 1,
  "limit": 20
}

POST /api/billing/invoices

Creates a new invoice.

ParameterTypeRequiredDescription
customer_idstringYesCustomer ID
itemsarrayYesLine items (see below)
currencystringNoCurrency code (default: BRL)
due_datestringYesISO 8601 due date
notesstringNoInternal notes
tax_rate_idstringNoApplied tax rate
discount_percentnumberNoDiscount percentage

Line item object:

FieldTypeRequiredDescription
descriptionstringYesItem description
quantityintegerYesQuantity
unit_pricenumberYesPrice per unit
unitstringNoUnit of measure

Request Body:

{
  "customer_id": "cust_001",
  "items": [
    {
      "description": "BotServer Pro License (Annual)",
      "quantity": 1,
      "unit_price": 4800.00
    },
    {
      "description": "Custom Integration Setup",
      "quantity": 8,
      "unit_price": 150.00,
      "unit": "hours"
    }
  ],
  "currency": "BRL",
  "due_date": "2025-07-01",
  "tax_rate_id": "tax_001",
  "notes": "Annual renewal + onboarding"
}

Response:

{
  "id": "inv_002",
  "number": "INV-2025-0043",
  "customer_id": "cust_001",
  "status": "draft",
  "subtotal": 6000.00,
  "tax": 960.00,
  "discount": 0,
  "total": 6960.00,
  "currency": "BRL",
  "due_date": "2025-07-01",
  "items": [
    { "description": "BotServer Pro License (Annual)", "quantity": 1, "unit_price": 4800.00, "total": 4800.00 },
    { "description": "Custom Integration Setup", "quantity": 8, "unit_price": 150.00, "total": 1200.00 }
  ],
  "created_at": "2025-06-04T10:00:00Z"
}

Overdue Invoices

GET /api/billing/invoices/overdue

Returns all invoices past their due date.

Response:

{
  "overdue": [
    {
      "id": "inv_003",
      "number": "INV-2025-0038",
      "customer_id": "cust_005",
      "customer_name": "StartupXYZ",
      "total": 2400.00,
      "currency": "BRL",
      "due_date": "2025-05-15",
      "days_overdue": 20,
      "status": "overdue"
    }
  ],
  "count": 3,
  "total_overdue_amount": 8400.00
}

Invoice Operations

GET /api/billing/invoices/:id

Retrieves a single invoice with full details.

ParameterTypeRequiredDescription
idstringYesInvoice ID

Response:

{
  "id": "inv_002",
  "number": "INV-2025-0043",
  "customer_id": "cust_001",
  "customer_name": "Acme Corp",
  "status": "draft",
  "subtotal": 6000.00,
  "tax": 960.00,
  "tax_rate_name": "ICMS 16%",
  "discount": 0,
  "total": 6960.00,
  "currency": "BRL",
  "due_date": "2025-07-01",
  "issued_at": null,
  "paid_at": null,
  "items": [
    { "description": "BotServer Pro License (Annual)", "quantity": 1, "unit_price": 4800.00, "total": 4800.00 },
    { "description": "Custom Integration Setup", "quantity": 8, "unit_price": 150.00, "total": 1200.00 }
  ],
  "payments": [],
  "created_at": "2025-06-04T10:00:00Z",
  "updated_at": "2025-06-04T10:00:00Z"
}

PUT /api/billing/invoices/:id

Updates a draft invoice.

ParameterTypeRequiredDescription
idstringYesInvoice ID
itemsarrayNoUpdated line items
due_datestringNoUpdated due date
notesstringNoUpdated notes
tax_rate_idstringNoUpdated tax rate
discount_percentnumberNoUpdated discount

Request Body:

{
  "due_date": "2025-07-15",
  "discount_percent": 5
}

Response:

{
  "id": "inv_002",
  "status": "draft",
  "subtotal": 6000.00,
  "discount": 300.00,
  "tax": 912.00,
  "total": 6612.00,
  "due_date": "2025-07-15",
  "updated_at": "2025-06-04T11:00:00Z"
}

DELETE /api/billing/invoices/:id

Deletes a draft invoice. Sent or paid invoices cannot be deleted — use void instead.

ParameterTypeRequiredDescription
idstringYesInvoice ID

Response:

{
  "success": true,
  "message": "Draft invoice deleted"
}

Send Invoice

PUT /api/billing/invoices/:id/send

Sends an invoice to the customer via email.

ParameterTypeRequiredDescription
idstringYesInvoice ID
emailstringNoOverride recipient email
messagestringNoCustom email message

Request Body:

{
  "email": "billing@acme.com",
  "message": "Olá, segue a fatura referente ao mês de maio."
}

Response:

{
  "id": "inv_002",
  "status": "sent",
  "sent_to": "billing@acme.com",
  "sent_at": "2025-06-04T12:00:00Z"
}

Void Invoice

PUT /api/billing/invoices/:id/void

Voids a sent invoice (cannot be undone).

ParameterTypeRequiredDescription
idstringYesInvoice ID
reasonstringYesVoid reason

Request Body:

{
  "reason": "Duplicate invoice created in error"
}

Response:

{
  "id": "inv_002",
  "status": "void",
  "voided_at": "2025-06-04T13:00:00Z",
  "void_reason": "Duplicate invoice created in error"
}

Payments

GET /api/billing/payments

Lists all payments.

ParameterTypeRequiredDescription
invoice_idstringNoFilter by invoice
statusstringNocompleted, pending, failed, refunded
fromstringNoISO 8601 start date
tostringNoISO 8601 end date
pageintegerNoPage number
limitintegerNoItems per page

Response:

{
  "payments": [
    {
      "id": "pay_001",
      "invoice_id": "inv_001",
      "amount": 5400.00,
      "currency": "BRL",
      "method": "bank_transfer",
      "status": "completed",
      "reference": "PIX-2025-0601-001",
      "paid_at": "2025-06-05T14:00:00Z"
    }
  ],
  "total": 38,
  "total_amount": 145600.00
}

POST /api/billing/payments

Records a payment against an invoice.

ParameterTypeRequiredDescription
invoice_idstringYesInvoice ID
amountnumberYesPayment amount
methodstringYespix, bank_transfer, credit_card, boleto, cash
referencestringNoTransaction reference
paid_atstringNoISO 8601 payment date (default: now)
notesstringNoPayment notes

Request Body:

{
  "invoice_id": "inv_001",
  "amount": 5400.00,
  "method": "pix",
  "reference": "PIX-2025-0605-002",
  "paid_at": "2025-06-05T14:30:00Z"
}

Response:

{
  "id": "pay_002",
  "invoice_id": "inv_001",
  "amount": 5400.00,
  "method": "pix",
  "status": "completed",
  "reference": "PIX-2025-0605-002",
  "paid_at": "2025-06-05T14:30:00Z",
  "invoice_status": "paid"
}

GET /api/billing/payments/:id

Retrieves details for a specific payment.

ParameterTypeRequiredDescription
idstringYesPayment ID

Response:

{
  "id": "pay_001",
  "invoice_id": "inv_001",
  "amount": 5400.00,
  "currency": "BRL",
  "method": "bank_transfer",
  "status": "completed",
  "reference": "PIX-2025-0601-001",
  "paid_at": "2025-06-05T14:00:00Z",
  "customer_id": "cust_001",
  "customer_name": "Acme Corp",
  "created_at": "2025-06-05T14:00:00Z"
}

Quotes

GET /api/billing/quotes

Lists all quotes.

ParameterTypeRequiredDescription
statusstringNodraft, sent, accepted, rejected, expired
customer_idstringNoFilter by customer
pageintegerNoPage number
limitintegerNoItems per page

Response:

{
  "quotes": [
    {
      "id": "qte_001",
      "number": "QT-2025-0012",
      "customer_id": "cust_003",
      "customer_name": "TechStart Ltda",
      "status": "sent",
      "total": 12000.00,
      "currency": "BRL",
      "valid_until": "2025-07-04",
      "created_at": "2025-06-01T10:00:00Z"
    }
  ],
  "total": 15
}

POST /api/billing/quotes

Creates a new quote.

ParameterTypeRequiredDescription
customer_idstringYesCustomer ID
itemsarrayYesLine items (same format as invoices)
currencystringNoCurrency (default: BRL)
valid_untilstringYesISO 8601 expiry date
notesstringNoQuote notes
tax_rate_idstringNoApplied tax rate

Request Body:

{
  "customer_id": "cust_003",
  "items": [
    { "description": "BotServer Enterprise License", "quantity": 1, "unit_price": 9600.00 },
    { "description": "Annual Support Plan", "quantity": 1, "unit_price": 2400.00 }
  ],
  "valid_until": "2025-07-04",
  "notes": "Enterprise package with priority support"
}

Response:

{
  "id": "qte_002",
  "number": "QT-2025-0013",
  "status": "draft",
  "subtotal": 12000.00,
  "total": 12000.00,
  "valid_until": "2025-07-04",
  "created_at": "2025-06-04T10:00:00Z"
}

GET /api/billing/quotes/:id

Retrieves a single quote.

ParameterTypeRequiredDescription
idstringYesQuote ID

Response:

{
  "id": "qte_001",
  "number": "QT-2025-0012",
  "customer_id": "cust_003",
  "customer_name": "TechStart Ltda",
  "status": "sent",
  "subtotal": 12000.00,
  "tax": 1920.00,
  "total": 13920.00,
  "currency": "BRL",
  "valid_until": "2025-07-04",
  "items": [
    { "description": "BotServer Enterprise License", "quantity": 1, "unit_price": 9600.00, "total": 9600.00 },
    { "description": "Annual Support Plan", "quantity": 1, "unit_price": 2400.00, "total": 2400.00 }
  ],
  "created_at": "2025-06-01T10:00:00Z"
}

DELETE /api/billing/quotes/:id

Deletes a draft or expired quote.

ParameterTypeRequiredDescription
idstringYesQuote ID

Response:

{
  "success": true,
  "message": "Quote deleted"
}

Accept / Reject Quote

PUT /api/billing/quotes/:id/accept

Marks a quote as accepted and optionally generates an invoice.

ParameterTypeRequiredDescription
idstringYesQuote ID
generate_invoicebooleanNoAuto-create invoice (default: false)

Request Body:

{
  "generate_invoice": true
}

Response:

{
  "id": "qte_001",
  "status": "accepted",
  "accepted_at": "2025-06-04T15:00:00Z",
  "invoice_id": "inv_004",
  "invoice_number": "INV-2025-0044"
}

PUT /api/billing/quotes/:id/reject

Marks a quote as rejected.

ParameterTypeRequiredDescription
idstringYesQuote ID
reasonstringNoRejection reason

Request Body:

{
  "reason": "Budget constraints — will revisit next quarter"
}

Response:

{
  "id": "qte_001",
  "status": "rejected",
  "rejected_at": "2025-06-04T15:30:00Z",
  "rejection_reason": "Budget constraints — will revisit next quarter"
}

Billing Statistics

GET /api/billing/stats

Returns billing overview statistics.

ParameterTypeRequiredDescription
periodstringNomonth, quarter, year (default: month)

Response:

{
  "period": "2025-06",
  "revenue": {
    "total": 85400.00,
    "collected": 62300.00,
    "pending": 18700.00,
    "overdue": 4400.00
  },
  "invoices": {
    "total": 42,
    "paid": 28,
    "sent": 8,
    "overdue": 4,
    "draft": 2
  },
  "quotes": {
    "total": 15,
    "accepted": 6,
    "rejected": 3,
    "pending": 6
  },
  "conversion_rate": 40.0,
  "average_payment_days": 18
}

Tax Rates

GET /api/billing/tax-rates

Lists configured tax rates.

Response:

{
  "tax_rates": [
    {
      "id": "tax_001",
      "name": "ICMS 16%",
      "rate": 16.0,
      "type": "percentage",
      "applies_to": "all",
      "active": true
    },
    {
      "id": "tax_002",
      "name": "ISS 5%",
      "rate": 5.0,
      "type": "percentage",
      "applies_to": "services",
      "active": true
    },
    {
      "id": "tax_003",
      "name": "PIS 1.65%",
      "rate": 1.65,
      "type": "percentage",
      "applies_to": "all",
      "active": true
    }
  ]
}

Recurring Billing

GET /api/billing/recurring

Lists recurring billing schedules.

Response:

{
  "recurring": [
    {
      "id": "rec_001",
      "customer_id": "cust_001",
      "customer_name": "Acme Corp",
      "plan": "BotServer Pro",
      "amount": 400.00,
      "currency": "BRL",
      "interval": "monthly",
      "next_billing_date": "2025-07-01",
      "status": "active",
      "invoices_generated": 6,
      "created_at": "2025-01-01T00:00:00Z"
    }
  ]
}

Payment Methods

MethodCodeDescription
PIXpixInstant payment (Brazil)
Bank Transferbank_transferTED/DOC transfer
Credit Cardcredit_cardVisa, Mastercard, Amex
BoletoboletoBrazilian bank slip
CashcashCash payment

Response Codes

CodeDescription
200Success
201Created
204No Content (deletion)
400Bad Request
401Unauthorized
403Forbidden
404Resource not found
409Conflict (e.g., already paid)
500Internal Server Error

ERP Features (Inventory, GL, Procurement)

Billing is the unified finance/ERP app. The suite exposes these HTMX fragments:

GET /api/ui/billing/inventory                    # inventory table
GET /api/ui/billing/gl/accounts                  # GL accounts
GET /api/ui/billing/gl/balance-sheet             # balance sheet
GET /api/ui/billing/gl/income-statement          # income statement
GET /api/ui/billing/procurement                  # purchase orders
GET /api/ui/billing/procurement/orders           # purchase orders alias

These read from the ERP data tables (erp_inventory, erp_procurement, gl_accounts, gl_journal_entries). The billing app shell shows tabs for Invoices, Payments, Quotes, Inventory, GL and Procurement.

Subscription Lifecycle (JSON)

POST /api/billing/subscription/upgrade   # { plan_id: "shared" }
POST /api/billing/subscription/cancel    # { reason: "..." }
GET  /api/billing/invoices/export        # CSV download
GET  /api/billing/invoices/unpaid        # <option> list for payment forms

See Also