Money & ALECharges & invoices

Charges and invoices

Two different pieces of money get called “billing”, and mixing them up is the commonest reconciliation mistake:

  • /billing/charges — what was charged on your placements. Rent, deposits and fees, paid to the landlord. Havnly never holds this money; it is a direct charge on the landlord’s own Stripe account.
  • /billing/invoices — what Havnly invoices you: subscription and coordination fees.

Both are read-only. POST to either returns 405.

The charge ledger

GET /billing/charges

Every charge raised across your organisation’s requests, newest first.

{
  "data": [
    {
      "id": "6b1a…",
      "reference": "REQ-6FED6B",
      "external_id": "CLM-88213",
      "property": { "name": "USC Village Apartment", "city": "Los Angeles", "state": "California" },
      "status": "succeeded",
      "charge_type": "checkout_direct",
      "amount": 3151.00,
      "platform_fee": 372.00,
      "currency": "cad",
      "covers_rent": true,
      "covers_deposit": false,
      "paid_at": "2026-09-14T10:22:41Z",
      "created_at": "2026-09-14T10:21:08Z"
    }
  ],
  "count": 100,
  "next_cursor": "2026-08-30T09:14:02Z",
  "totals": {
    "scope": "this page",
    "by_currency": {
      "cad": { "charged": 6151, "settled": 6151, "outstanding": 0, "refunded": 0, "platform_fees": 372 }
    }
  }
}

external_id is your own reference, so a charge can be matched back to a claim in your system without a lookup table.

Filters

ParameterMeaning
statusComma-separated: succeeded, pending, refunded, failed
since / untilISO timestamps, against created_at
limitUp to 250, default 100
cursorThe next_cursor from the previous page

Totals are per page, and per currency

totals.scope says "this page", because that is what it is. To total a period, page through it with since/until and add up as you go.

Totals are broken down by currency and never combined. Havnly places households in the US and Canada, so a portfolio can hold both USD and CAD charges; adding them would produce a number that looks right and is wrong.

Rent and deposit are separate rows

When a request names different payers for rent and deposit, a placement has two charge rows. covers_rent and covers_deposit say which is which.

platform_fee is Havnly’s fee, and it applies to rent only — never to deposits, pet rent, utilities or one-off fees. That is why a deposit row shows platform_fee: 0. See How the money works.

Charge types

charge_typeWhat it is
checkout_directThe first payment that confirms a placement
recurring_rentA monthly rent invoice while the stay runs
final_stubThe last partial month, prorated
adjustmentA correction agreed after the fact

Havnly’s invoices to you

GET /billing/invoices
{
  "data": [
    {
      "number": "HAV-2026-0041",
      "period": { "from": "2026-08-01", "to": "2026-08-31" },
      "status": "issued",
      "subtotal": 4200.00,
      "total": 4200.00,
      "paid_amount": 0,
      "balance": 4200.00,
      "due_at": "2026-09-30",
      "pdf_url": "https://…",
      "line_items": [
        { "type": "coordination", "description": "Placement coordination — 14 placements",
          "quantity": 14, "unit_price": 300.00, "amount": 4200.00 }
      ]
    }
  ],
  "count": 6,
  "outstanding_total": 4200.00
}

balance is what is still owed on each invoice, and outstanding_total is the sum across the unpaid ones — the number a finance system actually wants.

409 no_billing_account

Your API organisation is not yet linked to a carrier billing account. This is a one-time connection on our side; ask Havnly and it will start returning invoices. /billing/charges works regardless — the two are unrelated.

What you cannot do here

Take a payment. Rent and deposits are collected through a hosted Stripe checkout on the landlord’s own account, completed by a person in Havnly. There is no API call that moves money, by design: it is what keeps Havnly out of the flow of funds, and out of your PCI scope.

Refunds are requested through POST /claims/{ref}/refund-request and approved by the landlord.