Skip to content

Daily charge journal

GET
/billing/usage/days
curl --request GET \
--url 'https://api.flotera.com/api/v1/billing/usage/days?limit=50&range=7d' \
--cookie __Host-erm_session=<__Host-erm_session>

One row per closed UTC day: how many managed server-days were billable, at what frozen plan rate, and the charge that was posted. This replaces the hourly journal — a day is the settlement unit (14 §2.2, §2.6).

limit
integer
default: 50 >= 1 <= 200

Page size.

range

Named period over UTC days, deliberately not LedgerRange: the settlement unit here is the UTC day (14 §2.2), while the ledger’s ranges are expanded in the tenant timezone. Resolving one with the other would put a day in a period it was not charged in.

string
Allowed values: 7d month prev_month

Named period, expanded server-side into UTC days. Mutually exclusive with from/to and with day (422 otherwise).

day

UTC calendar day.

string format: date

One UTC day, returned with its composition in server_summary and exception rows in servers. Neither is included in list responses: they are the explanation of one charge, not a column of the journal.

server
string
<= 128 characters

Point lookup inside one day’s breakdown: a literal name substring (LIKE metacharacters are escaped) or an exact server UUID. Requires day (422 otherwise); an empty or blank value is ignored. With this filter servers carries the matches instead of exceptions.

from

UTC calendar day.

string format: date

First UTC day of the closed interval [from, to].

to

UTC calendar day.

string format: date

Last UTC day of the closed interval [from, to].

Daily usage rows, newest day first.

Media typeapplication/json
object
items
required
Array<object>
<= 200 items

One closed UTC day. charge_usd is what the ledger actually posted for that day, including the month-to-date rounding carry, so the rows sum to the ledger and not to a re-computed estimate (D-12).

object
day
required

UTC calendar day.

string format: date
billable_server_days
required
integer
plan
Any of:

Internal catalog code. Not the public label — labels are not unique.

string
<= 64 characters /^[a-z][a-z0-9_-]{1,63}$/
monthly_price_per_server_usd

Frozen assignment price the day was charged at.

string | null
/^-?[0-9]+(\.[0-9]{1,6})?$/
charge_usd
required

Decimal value serialized as a string, never a JSON number.

string
/^-?[0-9]+(\.[0-9]{1,6})?$/
status
required

no_op — nothing was billable that day and no entry was written; shadow — the run computed the day without moving the balance; failed — the day could not be priced and the cursor did not move.

string
Allowed values: posted no_op shadow failed
block_reason

Machine code of why a failed day was not priced, e.g. no_plan_assignment. Always null on any other status. A blocked day stops the settlement chain — the cursor must advance day by day, so every later day stays uncalculated too. Without the reason on the wire, the owner sees a red chip and no way to tell an empty day from a stalled one, and the only visible symptom of a stalled chain is money that never arrives.

string | null
<= 64 characters /^[a-z][a-z0-9_]{1,63}$/
settled_at

RFC 3339 UTC with microsecond precision, or null.

string | null format: date-time
servers

Exception rows, present only when a single day was requested; null in list responses. Carries only the servers whose day needs explaining — not billable, or present for less than the whole billable window — because on a large fleet the full roster is thousands of identical lines; server_summary replaces it. Partial-but-billable rows sort first: chronically silent servers are homogeneous, while partial days are that day’s story. With server= the array carries search matches instead. Capped at 200; server_summary.exceptions is the uncapped count.

Array<object> | null
<= 200 items

One server’s evidence for one closed UTC day: the frozen counters the billable/not decision was taken from (14 §2.4), plus what this server contributed to the day’s charge.

object
server_id
required
string format: uuid
name

null when the server has since been removed from the registry.

string | null
<= 128 characters
billable
required
boolean
telemetry_batches
required

Distinct accepted batches observed inside the billable window.

integer
connected_seconds
required

Union of presence intervals clipped to the billable window.

integer
registration_accepted
boolean
first_inventory_accepted
boolean
amount_usd

This server’s share of the day’s charge, null when the server was not billable. Shares are the split of the posted amount, so they sum to it exactly — they are not a re-computation of the daily rate.

string | null
/^-?[0-9]+(\.[0-9]{1,6})?$/
server_summary
Any of:

How many servers reported that day and how. Computed by the server: both the billable criteria and the billable window are settlement rules (14 §2.4), and a client-side copy would eventually explain a charge with different arithmetic.

object
total
required

Servers that reported that day, billable or not.

integer
billable
required
integer
not_billable
required
integer
full_presence
required

Presence union covered the whole billable window, second to second. Exact equality on purpose: presence union absorbs small reconnects, so real fleets show either zero gap or a large one, and any tolerance here would be an invented threshold.

integer
first_day
required

Registration and first inventory accepted that day (criterion 3).

integer
exceptions
required

Rows matching the exception predicate (not billable, or partial presence) before the servers cap is applied.

integer
Example
{
"items": [
{
"charge_usd": "12.340000",
"status": "posted"
}
]
}

Missing/invalid credentials (code=unauthorized).

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

Authenticated but not permitted. code=forbidden — role/scope mismatch; code=feature_not_entitled — the plan does not include the capability; code=account_frozen — the account is frozen and this operation is declared x-ermeon-frozen: deny. The three are deliberately distinct: only the last one is fixed by a top-up (13 §5.6).

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}

Request failed validation (code=validation_failed), with per-field errors.

Media typeapplication/problem+json

RFC 9457 problem document with a stable machine code.

object
type
required
string format: uri
title
required
string
<= 256 characters
status
required
integer
>= 100 <= 599
code
required

Stable machine-readable error code (03 §2.4).

string
Allowed values: unauthorized forbidden csrf_rejected not_found conflict idempotency_conflict validation_failed rate_limited payload_too_large unsupported_agent_version temporarily_unavailable offline_queue_full online_queue_full plan_required server_limit_reached feature_not_entitled account_in_grace account_frozen payment_pending payment_expired payment_amount_mismatch change_already_pending change_already_applied change_effective reserve_not_covered direction_changed
detail
string
<= 2048 characters
instance
string
<= 512 characters
request_id

UUID (v7 for new entities; v4 accepted during migration).

string format: uuid
errors
Array<object>
<= 100 items
object
path
required

JSON Pointer to the offending field.

string
<= 512 characters
code
required
string
<= 64 characters
Example
{
"type": "https://ermeon.com/problems/validation",
"code": "unauthorized"
}