Bills

Bills represent purchase transactions from vendors in Crane Ledger's accounts payable system. They track expenses, vendor payments, and automatically create corresponding accounting transactions. Bills are the counterpart to invoices for managing business expenses and purchases.

The Bill Object

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

A bill represents a purchase transaction from a vendor.

{
  "id": "bil_xxxxxxxxxxxxxxxx",
  "object": "bill",
  "organization_id": "org_xxxxxxxxxxxxxxxx",
  "bill_number": "BILL-2024-001",
  "order_number": "PO-12345",
  "status": "draft",
  "contact_id": "con_xxxxxxxxxxxxxxxx",
  "contact_name": "Office Supplies Co",
  "contact_email": "billing@officesupplies.com",
  "contact_tax_number": "US987654321",
  "currency_id": "CUR_USD",
  "currency_rate": "1.0000",
  "billed_at": "2024-01-10",
  "due_at": "2024-02-09",
  "amount": "1250.00",
  "category_id": "cat_xxxxxxxxxxxxxxxx",
  "notes": "Monthly office supplies order",
  "parent_id": null,
  "created_by": "usr_xxxxxxxxxxxxxxxx",
  "created_at": "2024-01-10T14:30:00Z",
  "updated_at": "2024-01-10T14:30:00Z",
  "metadata": {
    "payment_terms": "net_30",
    "po_number": "PO-2024-001"
  }
}

Attributes

AttributeTypeDescription
idstringUnique identifier with bil_ prefix
bill_numberstringSequential bill number
statusenumCurrent status (draft, received, partial, paid, cancelled, overdue)
contact_idstringVendor contact
amountstringTotal bill amount before tax
billed_atdateBill date
due_atdatePayment due date
currency_idstringBill currency
category_idstringBill category
notesstringBill notes
order_numberstringPurchase order reference

Create Bill

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

Creates a new purchase bill with line items, taxes, and vendor details.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe ID of the organization

Request Body

ParameterTypeRequiredDescription
bill_numberstringYesUnique bill number
contact_idstringYesVendor contact ID
billed_atdateYesBill date (YYYY-MM-DD)
due_atdateYesPayment due date (YYYY-MM-DD)
category_idstringNoBill category
notesstringNoBill notes
order_numberstringNoPurchase order reference
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_yyyyyyyyyyyyyyyy",
  "success": true,
  "data": {
    "status": "queued",
    "estimated_completion": "2024-01-10T14:30:10Z",
    "bill_preview": {
      "number": "BILL-2024-001",
      "total_amount": "1250.00",
      "total_tax": "250.00",
      "grand_total": "1500.00"
    }
  },
  "error": null,
  "duration_ms": 0,
  "credit_cost": 5
}

List Bills

GET/organizations/:organization_id/bills
Auth required

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

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID

Query Parameters

ParameterTypeDescription
statusenumFilter by status (draft, received, paid, etc.)
contact_idstringFilter by vendor contact
limitintegerNumber of results (default: 20, max: 100)
offsetintegerPagination offset

Response

{
  "object": "list",
  "data": [
    {
      "id": "bil_xxxxxxxxxxxxxxxx",
      "bill_number": "BILL-2024-001",
      "status": "paid",
      "contact_name": "Office Supplies Co.",
      "amount": "500.00",
      "issued_at": "2024-01-10",
      "due_at": "2024-02-10",
      "created_at": "2024-01-10T09:15:00Z"
    }
  ],
  "has_more": false,
  "total_count": 1
}

Get Bill

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

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

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Response

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


Update Bill

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

Updates an existing bill. Only draft bills can be modified.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Request Body

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


Delete Bill

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

Deletes a draft bill. Received or paid bills cannot be deleted.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Receive Bill

POST/organizations/:organization_id/bills/:id/receive
Auth required
1 credits

Marks a bill as received and updates its status.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Record Bill Payment

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

Records a payment for a bill, creating the corresponding accounting transaction.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Request Body

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

Get Bill History

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

Returns the status change history for a bill.

Path Parameters

ParameterTypeRequiredDescription
organization_idstringYesThe organization ID
idstringYesThe bill ID

Response

[
  {
    "status": "draft",
    "changed_at": "2024-01-10T09:15:00Z",
    "changed_by": "user_xxx"
  },
  {
    "status": "received",
    "changed_at": "2024-01-12T11:30:00Z",
    "changed_by": "user_xxx"
  },
  {
    "status": "paid",
    "changed_at": "2024-01-15T14:45:00Z",
    "changed_by": "user_xxx"
  }
]

Bill Lifecycle

Status Flow

draft → received → partial → paid
   ↓      ↓        ↓       ↓
cancelled  overdue

Status Descriptions

StatusDescriptionActions Available
draftBill created but not receivedEdit, receive, delete
receivedBill received from vendorRecord payment, cancel
partialPartial payment madeRecord additional payments, cancel
paidFully paidGenerate receipt, create debit note
cancelledBill cancelledReactivate (if draft), create debit note
overduePast due dateSend reminders, record payment, dispute

Expense Categories

Common Bill Categories

{
  "operating_expenses": [
    {
      "name": "Office Supplies",
      "category_id": "cat_office_supplies",
      "typical_vendors": ["Office Depot", "Staples", "Amazon Business"]
    },
    {
      "name": "Professional Services",
      "category_id": "cat_professional_services",
      "typical_vendors": ["Law Firms", "Consultants", "Accountants"]
    },
    {
      "name": "Marketing & Advertising",
      "category_id": "cat_marketing",
      "typical_vendors": ["Google Ads", "Facebook", "PR Agencies"]
    },
    {
      "name": "Travel & Entertainment",
      "category_id": "cat_travel",
      "typical_vendors": ["Airlines", "Hotels", "Uber", "Restaurants"]
    },
    {
      "name": "Utilities",
      "category_id": "cat_utilities",
      "typical_vendors": ["Electric Company", "Internet Provider", "Phone Company"]
    }
  ],
  "cost_of_goods_sold": [
    {
      "name": "Inventory Purchases",
      "category_id": "cat_inventory",
      "typical_vendors": ["Wholesalers", "Manufacturers", "Distributors"]
    }
  ],
  "capital_expenditures": [
    {
      "name": "Equipment & Furniture",
      "category_id": "cat_equipment",
      "typical_vendors": ["Office Furniture Stores", "Computer Dealers"]
    },
    {
      "name": "Software & Licenses",
      "category_id": "cat_software_expenses",
      "typical_vendors": ["Software Companies", "SaaS Providers"]
    }
  ]
}

Three-Way Matching

Three-way matching ensures accurate bill processing by comparing purchase orders, receipts, and invoices.

Matching Process

// Three-way matching validation
function validateThreeWayMatch(purchaseOrder, goodsReceipt, vendorBill) {
  const matches = {
    quantity: false,
    price: false,
    total: false
  };

  // 1. Quantity Match
  matches.quantity = purchaseOrder.items.every((poItem, index) => {
    const receiptItem = goodsReceipt.items[index];
    const billItem = vendorBill.items[index];
    return poItem.quantity === receiptItem.quantity &&
           receiptItem.quantity === billItem.quantity;
  });

  // 2. Price Match
  matches.price = purchaseOrder.items.every((poItem, index) => {
    const billItem = vendorBill.items[index];
    return poItem.unitPrice === billItem.unitPrice;
  });

  // 3. Total Match
  const poTotal = calculateTotal(purchaseOrder.items);
  const billTotal = calculateTotal(vendorBill.items);
  matches.total = Math.abs(poTotal - billTotal) < 0.01;

  return {
    matches,
    allMatch: matches.quantity && matches.price && matches.total,
    discrepancies: {
      quantity: !matches.quantity,
      price: !matches.price,
      total: !matches.total
    }
  };
}

// Usage
const match = validateThreeWayMatch(po, receipt, bill);
if (!match.allMatch) {
  console.log("Three-way match failed:", match.discrepancies);
  // Handle discrepancies (approval workflow, vendor notification, etc.)
}

Approval Workflows

def process_bill_approval(bill, match_result):
    """Process bill through approval workflow based on matching results"""

    if match_result['allMatch']:
        # Auto-approve perfectly matched bills
        return approve_bill(bill, "auto_approved")

    # Manual approval required for discrepancies
    if match_result['discrepancies']['total']:
        # Large total discrepancy - escalate to finance manager
        return escalate_to_finance_manager(bill, match_result)

    elif match_result['discrepancies']['price']:
        # Price discrepancy - requires department head approval
        return require_department_approval(bill, match_result)

    elif match_result['discrepancies']['quantity']:
        # Quantity discrepancy - may be acceptable with explanation
        return require_explanation(bill, match_result)

    return bill

Recurring Bills

Setting Up Recurring Expenses

{
  "recurring_bill_template": {
    "contact_id": "con_vendor_utilities",
    "category_id": "cat_utilities",
    "items": [
      {
        "name": "Electricity",
        "quantity": 1,
        "price": 450.00,
        "tax_id": "tax_vat_5"
      },
      {
        "name": "Internet",
        "quantity": 1,
        "price": 89.99,
        "tax_id": "tax_vat_20"
      }
    ],
    "notes": "Monthly utility bill"
  },
  "schedule": {
    "frequency": "monthly",
    "start_date": "2024-02-01",
    "auto_receive": true,
    "payment_method": "bank_transfer"
  }
}

Recurring Bill Management

// Update recurring bill amounts
async function updateRecurringBill(billId, newAmounts) {
  // Future API - update recurring template
  const response = await fetch(`/organizations/${orgId}/bills/${billId}/recurring`, {
    method: 'PUT',
    headers: { ...authHeaders, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      items: newAmounts,
      effective_date: '2024-03-01'
    })
  });

  return response.json();
}

// Pause recurring bill (e.g., during office closure)
async function pauseRecurringBill(billId, resumeDate) {
  const response = await fetch(`/organizations/${orgId}/bills/${billId}/recurring/pause`, {
    method: 'POST',
    headers: { ...authHeaders, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      resume_date: resumeDate,
      reason: 'Office renovation'
    })
  });

  return response.json();
}

Vendor Management

Preferred Vendors

{
  "preferred_vendors": [
    {
      "contact_id": "con_vendor_office_depot",
      "vendor_name": "Office Depot",
      "categories": ["office_supplies", "furniture"],
      "payment_terms": "net_30",
      "discount_rate": "5",
      "contract_expiry": "2024-12-31",
      "performance_rating": "A"
    },
    {
      "contact_id": "con_vendor_staples",
      "vendor_name": "Staples",
      "categories": ["office_supplies"],
      "payment_terms": "net_15",
      "discount_rate": "3",
      "contract_expiry": "2024-06-30",
      "performance_rating": "B"
    }
  ]
}

Vendor Performance Tracking

def calculate_vendor_metrics(vendor_id, period_months=12):
    """Calculate vendor performance metrics"""

    bills = get_bills_for_vendor(vendor_id, period_months)
    payments = get_payments_for_vendor(vendor_id, period_months)

    metrics = {
        "total_billed": sum(bill['total'] for bill in bills),
        "total_paid": sum(payment['amount'] for payment in payments),
        "average_payment_time": calculate_average_payment_time(bills, payments),
        "on_time_payment_rate": calculate_on_time_rate(bills, payments),
        "invoice_accuracy": calculate_accuracy_rate(bills),
        "dispute_rate": calculate_dispute_rate(bills)
    }

    # Assign performance rating
    if metrics['on_time_payment_rate'] > 0.95 and metrics['invoice_accuracy'] > 0.98:
        metrics['rating'] = 'A'
    elif metrics['on_time_payment_rate'] > 0.90 and metrics['invoice_accuracy'] > 0.95:
        metrics['rating'] = 'B'
    else:
        metrics['rating'] = 'C'

    return metrics

Bill Payment Strategies

Payment Terms Optimization

// Calculate optimal payment dates
function optimizePaymentDates(bills, cashFlow) {
  const paymentSchedule = [];

  // Sort bills by due date
  bills.sort((a, b) => new Date(a.due_at) - new Date(b.due_at));

  bills.forEach(bill => {
    const dueDate = new Date(bill.due_at);
    const paymentTerms = bill.payment_terms || 'net_30';

    // Calculate optimal payment date based on cash flow and terms
    let optimalPaymentDate = new Date(dueDate);

    if (cashFlow.isConstrained(dueDate)) {
      // Delay payment within terms if cash flow is tight
      optimalPaymentDate = new Date(Math.min(
        dueDate.getTime() + (paymentTerms.days * 24 * 60 * 60 * 1000),
        dueDate.getTime() + (30 * 24 * 60 * 60 * 1000) // Max 30 days
      ));
    } else {
      // Pay early for discounts
      optimalPaymentDate = new Date(dueDate.getTime() - (2 * 24 * 60 * 60 * 1000));
    }

    paymentSchedule.push({
      bill_id: bill.id,
      vendor: bill.contact_name,
      amount: bill.total,
      due_date: dueDate,
      optimal_payment_date: optimalPaymentDate,
      savings: calculateEarlyPaymentDiscount(bill)
    });
  });

  return paymentSchedule;
}

Cash Flow Management

def optimize_bill_payment_schedule(bills, available_cash, payment_priorities):
    """Optimize bill payment schedule based on cash flow and priorities"""

    # Sort bills by priority and due date
    prioritized_bills = sort_bills_by_priority(bills, payment_priorities)

    payment_schedule = []
    remaining_cash = available_cash

    for bill in prioritized_bills:
        if bill['total'] <= remaining_cash:
            # Can pay in full
            payment_schedule.append({
                'bill_id': bill['id'],
                'amount': bill['total'],
                'payment_date': bill['due_at'],
                'status': 'scheduled'
            })
            remaining_cash -= bill['total']

        elif remaining_cash > 0:
            # Can pay partial amount
            payment_schedule.append({
                'bill_id': bill['id'],
                'amount': remaining_cash,
                'payment_date': bill['due_at'],
                'status': 'partial'
            })
            remaining_cash = 0

        else:
            # Cannot pay - mark as pending
            payment_schedule.append({
                'bill_id': bill['id'],
                'amount': 0,
                'payment_date': None,
                'status': 'pending'
            })

    return payment_schedule

Bill Best Practices

Vendor Relationship Management

  • Preferred Vendor Programs: Negotiate better terms with high-performing vendors
  • Payment Terms: Optimize payment schedules for cash flow
  • Volume Discounts: Consolidate purchases for better pricing
  • Performance Tracking: Monitor vendor reliability and quality

Approval Workflows

  • Amount-based Approvals: Different approval levels for different bill amounts
  • Department Approvals: Route bills to appropriate department heads
  • Three-way Matching: Automate approval for matched bills
  • Exception Handling: Manual review for discrepancies

Tax Compliance

  • Input Tax Credits: Track recoverable taxes for VAT/GST systems
  • Withholding Taxes: Handle contractor payments correctly
  • Tax Reporting: Maintain proper documentation for tax authorities

Bill Processing Timeline

Process bills promptly to maintain good vendor relationships and take advantage of early payment discounts. Delayed processing can impact cash flow forecasting and vendor terms.


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.