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/chargesEvery 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
| Parameter | Meaning |
|---|---|
status | Comma-separated: succeeded, pending, refunded, failed |
since / until | ISO timestamps, against created_at |
limit | Up to 250, default 100 |
cursor | The 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_type | What it is |
|---|---|
checkout_direct | The first payment that confirms a placement |
recurring_rent | A monthly rent invoice while the stay runs |
final_stub | The last partial month, prorated |
adjustment | A 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.