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

POST/organizations/:organization_id/invoices
Auth required
5 credits

An 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

AttributeTypeDescription
idstringUnique identifier with inv_ prefix
invoice_numberstringSequential invoice number
statusenumCurrent status (draft, sent, viewed, partial, paid, cancelled, overdue)
contact_idstringCustomer contact
amountstringTotal invoice amount before tax
issued_atdateInvoice issue date
due_atdatePayment due date
currency_idstringInvoice currency
category_idstringInvoice category
notesstringInvoice notes (visible to customer)
footerstringInvoice footer text

Create Invoice

POST/organizations/:organization_id/invoices
Auth required
5 credits

Creates a new sales invoice with line items, taxes, and customer details.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe ID of the organization

Request Body

ParameterTypeRequiredDescription
invoice_numberstringYesUnique invoice number
contact_idstringYesCustomer contact ID
issued_atdateYesInvoice issue date (YYYY-MM-DD)
due_atdateYesPayment due date (YYYY-MM-DD)
category_idstringNoInvoice category
notesstringNoInvoice notes
footerstringNoInvoice footer
itemsarrayYesLine items array

Line Items Structure

Each item in the items array:

ParameterTypeRequiredDescription
namestringYesItem name/description
skustringNoStock keeping unit
quantitynumberYesQuantity (decimal)
pricenumberYesUnit price
tax_idstringNoTax 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

GET/organizations/:organization_id/invoices
Auth required

Returns a list of invoices for the organization with optional filtering.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID

Query Parameters

ParameterTypeDescription
statusenumFilter by status (draft, sent, paid, etc.)
contact_idstringFilter by customer contact
limitintegerNumber of results (default: 20, max: 100)
offsetintegerPagination 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

GET/organizations/:organization_id/invoices/:id
Auth required

Retrieves the details of a specific invoice including line items and taxes.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Response

Returns the complete invoice object with line items, taxes, and payment history.


Update Invoice

PUT/organizations/:organization_id/invoices/:id
Auth required
2 credits

Updates an existing invoice. Only draft invoices can be modified.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Request Body

Same structure as Create Invoice, but all fields are optional.


Delete Invoice

DELETE/organizations/:organization_id/invoices/:id
Auth required
5 credits

Deletes a draft invoice. Sent or paid invoices cannot be deleted.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Send Invoice

POST/organizations/:organization_id/invoices/:id/send
Auth required
1 credits

Marks an invoice as sent and updates its status.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Generate Invoice PDF

GET/organizations/:organization_id/invoices/:id/pdf
Auth required
1 credits

Generates and returns a PDF version of the invoice.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Response

Returns the PDF file as binary content with Content-Type: application/pdf.


Record Invoice Payment

POST/organizations/:organization_id/invoices/:id/payments
Auth required
2 credits

Records a payment against an invoice, creating the corresponding accounting transaction.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe invoice ID

Request Body

ParameterTypeRequiredDescription
amountstringYesPayment amount
payment_datedateYesDate of payment
payment_methodstringNoPayment method (check, wire, etc.)
referencestringNoPayment reference number

Get Invoice History

GET/organizations/:organization_id/invoices/:id/history
Auth required

Returns the status change history for an invoice.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe 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

StatusDescriptionActions Available
draftInvoice created but not sentEdit, send, delete
sentInvoice sent to customerMark viewed, record payment, cancel
viewedCustomer has viewed invoiceRecord payment, send reminder, cancel
partialPartial payment receivedRecord additional payments, cancel
paidFully paidGenerate receipt, create credit note
cancelledInvoice cancelledReactivate (if draft), create credit note
overduePast due dateSend reminders, record payment, write off

Automatic Status Transitions

  • Overdue: Automatically set when due_at date 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.