Invoices
Invoices are the core of Crane Ledger's accounts receivable system. They represent sales transactions to customers, including line items, taxes, due dates, and payment tracking. Invoices automatically create corresponding accounting transactions when processed.
The Invoice Object
/organizations/:organization_id/invoicesAn invoice represents a sales transaction sent to a customer.
{
"id": "inv_xxxxxxxxxxxxxxxx",
"object": "invoice",
"organization_id": "org_xxxxxxxxxxxxxxxx",
"invoice_number": "INV-2024-001",
"order_number": "ORD-12345",
"status": "draft",
"contact_id": "con_xxxxxxxxxxxxxxxx",
"contact_name": "Acme Corporation",
"contact_email": "billing@acme.com",
"contact_tax_number": "US123456789",
"currency_id": "CUR_USD",
"currency_rate": "1.0000",
"issued_at": "2024-01-15",
"due_at": "2024-02-14",
"amount": "1250.00",
"category_id": "cat_xxxxxxxxxxxxxxxx",
"notes": "Payment due within 30 days",
"footer": "Thank you for your business",
"parent_id": null,
"created_by": "usr_xxxxxxxxxxxxxxxx",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"metadata": {
"payment_terms": "net_30",
"po_number": "PO-12345"
}
}
Attributes
| Attribute | Type | Description |
|---|---|---|
id | string | Unique identifier with inv_ prefix |
invoice_number | string | Sequential invoice number |
status | enum | Current status (draft, sent, viewed, partial, paid, cancelled, overdue) |
contact_id | string | Customer contact |
amount | string | Total invoice amount before tax |
issued_at | date | Invoice issue date |
due_at | date | Payment due date |
currency_id | string | Invoice currency |
category_id | string | Invoice category |
notes | string | Invoice notes (visible to customer) |
footer | string | Invoice footer text |
Create Invoice
/organizations/:organization_id/invoicesCreates a new sales invoice with line items, taxes, and customer details.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The ID of the organization |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
invoice_number | string | Yes | Unique invoice number |
contact_id | string | Yes | Customer contact ID |
issued_at | date | Yes | Invoice issue date (YYYY-MM-DD) |
due_at | date | Yes | Payment due date (YYYY-MM-DD) |
category_id | string | No | Invoice category |
notes | string | No | Invoice notes |
footer | string | No | Invoice footer |
items | array | Yes | Line items array |
Line Items Structure
Each item in the items array:
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Item name/description |
sku | string | No | Stock keeping unit |
quantity | number | Yes | Quantity (decimal) |
price | number | Yes | Unit price |
tax_id | string | No | Tax rate to apply |
Response
{
"request_id": "req_xxxxxxxxxxxxxxxx",
"success": true,
"data": {
"status": "queued",
"estimated_completion": "2024-01-15T10:30:10Z",
"invoice_preview": {
"number": "INV-2024-001",
"total_amount": "1500.00",
"total_tax": "300.00",
"grand_total": "1800.00"
}
},
"error": null,
"duration_ms": 0,
"credit_cost": 5
}
List Invoices
/organizations/:organization_id/invoicesReturns a list of invoices for the organization with optional filtering.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | enum | Filter by status (draft, sent, paid, etc.) |
contact_id | string | Filter by customer contact |
limit | integer | Number of results (default: 20, max: 100) |
offset | integer | Pagination offset |
Response
{
"object": "list",
"data": [
{
"id": "inv_xxxxxxxxxxxxxxxx",
"invoice_number": "INV-2024-001",
"status": "paid",
"contact_name": "Acme Corporation",
"amount": "1250.00",
"issued_at": "2024-01-15",
"due_at": "2024-02-14",
"created_at": "2024-01-15T10:30:00Z"
}
],
"has_more": false,
"total_count": 1
}
Get Invoice
/organizations/:organization_id/invoices/:idRetrieves the details of a specific invoice including line items and taxes.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Response
Returns the complete invoice object with line items, taxes, and payment history.
Update Invoice
/organizations/:organization_id/invoices/:idUpdates an existing invoice. Only draft invoices can be modified.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Request Body
Same structure as Create Invoice, but all fields are optional.
Delete Invoice
/organizations/:organization_id/invoices/:idDeletes a draft invoice. Sent or paid invoices cannot be deleted.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Send Invoice
/organizations/:organization_id/invoices/:id/sendMarks an invoice as sent and updates its status.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Generate Invoice PDF
/organizations/:organization_id/invoices/:id/pdfGenerates and returns a PDF version of the invoice.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Response
Returns the PDF file as binary content with Content-Type: application/pdf.
Record Invoice Payment
/organizations/:organization_id/invoices/:id/paymentsRecords a payment against an invoice, creating the corresponding accounting transaction.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | string | Yes | Payment amount |
payment_date | date | Yes | Date of payment |
payment_method | string | No | Payment method (check, wire, etc.) |
reference | string | No | Payment reference number |
Get Invoice History
/organizations/:organization_id/invoices/:id/historyReturns the status change history for an invoice.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
organization_id | string | Yes | The organization ID |
id | string | Yes | The invoice ID |
Response
[
{
"status": "draft",
"changed_at": "2024-01-15T10:30:00Z",
"changed_by": "user_xxx"
},
{
"status": "sent",
"changed_at": "2024-01-15T14:20:00Z",
"changed_by": "user_xxx"
},
{
"status": "paid",
"changed_at": "2024-01-20T09:15:00Z",
"changed_by": "user_xxx"
}
]
Invoice Lifecycle
Status Flow
draft → sent → viewed → partial → paid
↓ ↓ ↓ ↓ ↓
cancelled overdue
Status Descriptions
| Status | Description | Actions Available |
|---|---|---|
draft | Invoice created but not sent | Edit, send, delete |
sent | Invoice sent to customer | Mark viewed, record payment, cancel |
viewed | Customer has viewed invoice | Record payment, send reminder, cancel |
partial | Partial payment received | Record additional payments, cancel |
paid | Fully paid | Generate receipt, create credit note |
cancelled | Invoice cancelled | Reactivate (if draft), create credit note |
overdue | Past due date | Send reminders, record payment, write off |
Automatic Status Transitions
- Overdue: Automatically set when
due_atdate passes and invoice is not fully paid - Viewed: Set when customer accesses invoice (future feature)
Invoice Calculations
Basic Calculation
function calculateInvoiceTotal(items, taxRates) {
let subtotal = 0;
let totalTax = 0;
items.forEach(item => {
const lineTotal = item.quantity * item.price;
subtotal += lineTotal;
if (item.tax_id) {
const taxRate = taxRates[item.tax_id];
const taxAmount = lineTotal * (taxRate / 100);
totalTax += taxAmount;
}
});
const grandTotal = subtotal + totalTax;
return {
subtotal: subtotal.toFixed(2),
tax: totalTax.toFixed(2),
total: grandTotal.toFixed(2)
};
}
// Example usage
const items = [
{ name: "Service A", quantity: 10, price: 50.00, tax_id: "vat_20" },
{ name: "Service B", quantity: 5, price: 100.00, tax_id: "vat_20" }
];
const taxRates = { "vat_20": 20.00 };
const totals = calculateInvoiceTotal(items, taxRates);
console.log(totals); // { subtotal: "1000.00", tax: "200.00", total: "1200.00" }
Multi-Tax Calculation
function calculateMultiTaxInvoice(items, taxDefinitions) {
let subtotal = 0;
const taxBreakdown = {};
items.forEach(item => {
const lineTotal = item.quantity * item.price;
subtotal += lineTotal;
// Apply multiple taxes per item
item.taxes.forEach(taxRef => {
const tax = taxDefinitions[taxRef.tax_id];
let taxAmount = 0;
switch (tax.type) {
case 'normal':
taxAmount = lineTotal * (tax.rate / 100);
break;
case 'compound':
// Tax on (subtotal + previous taxes)
const taxableAmount = lineTotal + (taxBreakdown[taxRef.tax_id] || 0);
taxAmount = taxableAmount * (tax.rate / 100);
break;
case 'fixed':
taxAmount = tax.rate;
break;
}
taxBreakdown[taxRef.tax_id] = (taxBreakdown[taxRef.tax_id] || 0) + taxAmount;
});
});
const totalTax = Object.values(taxBreakdown).reduce((sum, amount) => sum + amount, 0);
const grandTotal = subtotal + totalTax;
return {
subtotal: subtotal.toFixed(2),
taxBreakdown,
totalTax: totalTax.toFixed(2),
grandTotal: grandTotal.toFixed(2)
};
}
Invoice Templates
Service Invoice Template
{
"template": "service_invoice",
"defaults": {
"category_id": "cat_services",
"payment_terms": "net_30",
"footer": "Thank you for your business. Payment terms: Net 30 days.",
"item_defaults": {
"tax_id": "tax_vat_20"
}
},
"sections": [
{
"name": "services",
"label": "Services Provided",
"item_category": "service"
},
{
"name": "expenses",
"label": "Reimbursable Expenses",
"item_category": "expense"
}
]
}
Product Invoice Template
{
"template": "product_invoice",
"defaults": {
"category_id": "cat_sales",
"payment_terms": "net_15",
"footer": "Prices subject to change. Shipping costs not included.",
"item_defaults": {
"tax_id": "tax_sales_tax"
}
},
"sections": [
{
"name": "products",
"label": "Products Ordered",
"show_quantity": true,
"show_sku": true
},
{
"name": "discounts",
"label": "Discounts Applied",
"negative_amounts": true
}
]
}
Recurring Invoices
Setting Up Recurring Invoices
# Create a monthly recurring invoice template
recurring_invoice = {
"template_invoice": {
"contact_id": "con_subscription_customer",
"category_id": "cat_subscriptions",
"items": [
{
"name": "Monthly Software License",
"quantity": 1,
"price": 99.00,
"tax_id": "tax_vat_20"
}
],
"notes": "Monthly recurring charge"
},
"recurring_schedule": {
"frequency": "monthly",
"start_date": "2024-02-01",
"end_date": "2024-12-31",
"auto_send": True
}
}
# This would be implemented in future API versions
# The recurring system would automatically generate invoices
Recurring Invoice Management
// Pause recurring invoice
async function pauseRecurring(invoiceId) {
// Future API endpoint
const response = await fetch(`/organizations/${orgId}/invoices/${invoiceId}/recurring/pause`, {
method: 'POST',
headers: authHeaders
});
return response.json();
}
// Resume recurring invoice
async function resumeRecurring(invoiceId) {
// Future API endpoint
const response = await fetch(`/organizations/${orgId}/invoices/${invoiceId}/recurring/resume`, {
method: 'POST',
headers: authHeaders
});
return response.json();
}
// Update recurring amount
async function updateRecurringAmount(invoiceId, newAmount) {
// Future API endpoint
const response = await fetch(`/organizations/${orgId}/invoices/${invoiceId}/recurring`, {
method: 'PATCH',
headers: { ...authHeaders, 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: newAmount })
});
return response.json();
}
Invoice Best Practices
Numbering Schemes
- Sequential: INV-0001, INV-0002, etc.
- Date-based: INV-2024-0001, INV-2024-0002
- Customer-specific: CUST001-0001, CUST001-0002
Payment Terms
- Standard Terms: Net 15, Net 30, Net 60
- Custom Terms: "Due upon receipt", "50% deposit, 50% on completion"
- Late Payment: Late fees, interest calculations
Tax Compliance
- Accurate Tax Rates: Keep tax rates up to date
- Proper Tax Application: Apply correct taxes per jurisdiction
- Tax Documentation: Include tax IDs and compliance information
Customer Communication
- Clear Descriptions: Detailed line item descriptions
- Payment Instructions: Include payment methods and details
- Contact Information: Multiple contact methods for questions
Invoice Immutability
Once an invoice is sent (status: 'sent'), it should not be modified to maintain audit trails. Instead, create credit notes or new invoices for corrections.
Need help?
Create a free account to access our support portal. Once signed in, use the Support tab in your dashboard to submit a support ticket — our team typically responds within 24 hours.
- ✨ For LLMs/AI assistants: Read our structured API reference