Expenses System

Track property expenses with flexible billing assignment, tenant invoicing, and split cost management.

Overview

The Expenses system allows property managers to record, categorize, and assign property-related costs to the appropriate party. Every expense includes a payableBy field that determines who is financially responsible.

Payable ByDescription
OWNERDeducted from owner payout at end of month
TENANTInvoiced to tenant as an outstanding charge
PMAbsorbed by the property management company
INSURANCETracked for insurance claim reimbursement
SPLITCost divided among multiple parties by percentage

Creating Expenses

Expenses can be created from three entry points in the application: the dedicated expense form, the property detail page, or directly from a unit page. Each path pre-fills context such as property ID and unit ID.

Create Expense Request
{
  "propertyId": "prop_abc123",
  "unitId": "unt_456",
  "category": "MAINTENANCE",
  "description": "HVAC filter replacement",
  "amount": 18500,
  "payableBy": "OWNER",
  "vendorName": "CoolAir Services",
  "date": "2025-01-15",
  "recurring": false,
  "receiptUrl": null
}

Tenant Invoicing Flow

When an expense is assigned to a tenant, the system automatically creates a Payment record, sends an invoice email, and surfaces the charge on the tenant dashboard alongside rent.

Flow: Expense created (payableBy: TENANT) → Payment record generated → Invoice email sent → Charge appears on tenant dashboard → Tenant pays via card or ACH → Ledger entry recorded.

Tenant Expense Invoice Payload
{
  "expenseId": "exp_789",
  "tenantId": "tnt_012",
  "amount": 25000,
  "description": "Broken window repair - Unit 4B",
  "dueDate": "2025-02-01",
  "status": "PENDING",
  "paymentId": "pay_inv001"
}

Split Expenses

Split expenses distribute a single cost across multiple parties. Each split entry specifies a party type and a percentage. The sum of all percentages must equal 100.

Split Expense Configuration
{
  "expenseId": "exp_split001",
  "amount": 50000,
  "payableBy": "SPLIT",
  "splits": [
    { "party": "OWNER", "percentage": 60, "amount": 30000 },
    { "party": "TENANT", "percentage": 30, "amount": 15000 },
    { "party": "PM", "percentage": 10, "amount": 5000 }
  ]
}

Approval Workflow

Expenses submitted by maintenance staff or vendors enter aPENDING state. The property manager reviews and either approves or rejects each expense. Approved expenses proceed to invoicing or payout deduction. Rejected expenses are marked with a reason and archived.

StatusDescription
PENDINGAwaiting PM review and approval
APPROVEDApproved and queued for invoicing or payout deduction
REJECTEDRejected with reason, archived for records

Recurring Expenses

Expenses marked as recurring are automatically duplicated on the 1st of each month by the recurring-expenses cron job. The new expense inherits all fields from the original, with the date set to the current month. If the expense is tenant-payable, a new invoice is also generated automatically.

Recurring Expense Configuration
{
  "expenseId": "exp_rec001",
  "recurring": true,
  "frequency": "MONTHLY",
  "category": "UTILITIES",
  "description": "Common area electricity",
  "amount": 12000,
  "payableBy": "TENANT",
  "nextDuplicateDate": "2025-03-01"
}

Receipt Upload

Each expense supports one or more receipt attachments. Supported formats include JPEG, PNG, and PDF. Receipts are uploaded to cloud storage and linked to the expense record via a signed URL.

Receipt Attachment
{
  "expenseId": "exp_789",
  "receipts": [
    {
      "id": "rcpt_001",
      "fileName": "hvac-invoice.pdf",
      "fileType": "application/pdf",
      "fileSize": 245000,
      "url": "https://storage.doorstax.com/receipts/rcpt_001.pdf",
      "uploadedAt": "2025-01-15T10:30:00.000Z"
    }
  ]
}

API Reference

All expense endpoints require authentication and are scoped to the property manager's organization.

MethodEndpointDescription
POST/api/expensesCreate a new expense
GET/api/expensesList expenses with filters
GET/api/expenses/:idGet expense details
PUT/api/expenses/:idUpdate an expense
DELETE/api/expenses/:idDelete an expense
POST/api/expenses/:id/approveApprove a pending expense
POST/api/expenses/:id/rejectReject a pending expense
POST/api/expenses/:id/receiptsUpload a receipt attachment