Read the platform's whole month on its own Stripe balance
const url = 'https://api.aerandil.com/v1/platform-earnings?month=example';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.aerandil.com/v1/platform-earnings?month=example' \ --header 'Authorization: Bearer <token>'A fold over every line the platform-ledger worker read off the platform’s own Stripe balance in a UTC calendar month, across every tenant: hotels — every merchant account’s lines, the per-account month (/v1/merchant-accounts/{id}/platform-earnings) summed; platform — the lines no hotel owns, recorded at the operator’s own tenant (AERANDIL_PLATFORM_TENANT_ID): its payouts, Stripe’s fees on the platform and the tax on them, reserves, and what no merchant account holds (unattributed); net — every line, the balance’s change. ties_to_stripe is the arithmetic of Stripe’s Balance summary report run in UTC — Activity (every category bar the payouts: count, gross, fee, net), Total payouts, and their sum — and by_category its balance-change-from-activity summary, so the operator ties the month to Stripe to the penny. unplaced_count is what was read while no operator tenant was configured: counted, never recorded, so a month carrying any will not tie. The platform operator’s read (tenant_admin:write).
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”The UTC calendar month, YYYY-MM.
Responses
Section titled “Responses”The platform’s month.
object
object
object
Every hotel’s lines: the per-account month summed.
object
object
The platform’s own lines, each bucket the net of its lines.
object
object
object
object
Examplegenerated
{ "account_count": 1, "from": "2026-04-15", "line_count": 1, "month": "example", "platform_tenant_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "timezone": "example", "to": "2026-04-15", "totals": [ { "by_category": [ { "count": 1, "fee": "example", "gross": "example", "net": "example", "reporting_category": "example" } ], "currency": "example", "hotels": { "account_count": 1, "dispute_costs": { "amounts_recovered": "example", "amounts_withdrawn": "example", "carried": "example", "fees_charged": "example", "fees_recovered": "example" }, "gross_captured": "example", "net": "example", "platform_fees_earned": "example", "processor_fees_paid": "example", "refunded": "example", "unexplained": "example" }, "net": "example", "platform": { "line_count": 1, "net": "example", "other": "example", "payouts": "example", "reserves": "example", "stripe_fees": "example", "tax_on_fees": "example", "unattributed": "example" }, "ties_to_stripe": { "activity": { "count": 1, "fee": "example", "gross": "example", "net": "example" }, "balance_change": "example", "payouts": { "count": 1, "net": "example" } } } ], "unplaced_count": 1}Headers
Section titled “Headers”Always no-store. Object and link state is live data and is never cacheable.
The bearer authenticated but does not hold the scope this operation requires.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}month is missing or not YYYY-MM.
Structured error wrapper. Every non-2xx response from any Aerandil endpoint serialises to this shape; the HTTP status carries the failure class (4xx/5xx), the body adds a stable code for programmatic dispatch plus a human-readable message.
object
object
Stable, programmatic error code (e.g. unauthorized, forbidden, not_found, invalid_body, invalid_url, precondition_failed, no_secondary_key). Clients dispatch on code, not on the message (which may be localised or contextualised in future versions).
Request-id correlation handle echoed on the request-id response header — support teams correlate without scraping logs.
Human-readable explanation of the failure.
Per-error structured detail. The shape varies by code (e.g. forbidden_action carries {"action": "..."}; precondition_failed carries {"current_version": N}).
Examplegenerated
{ "error": { "code": "example", "instance_id": "example", "message": "example", "parameters": "example" }}