Billing and usage
Your subscription has a monthly base and a metered seat-day price. CrossTrade computes seat-days from its own records and reports them to Stripe; you can read the same ledger.
What a seat-day is
For each UTC day, CrossTrade counts the distinct members whose seat overlapped the day while your service was billable (active, or past_due within its grace period) for any positive length of time.
- A day's count only grows while the day is open. A member whose seat ends during the day is still charged for that day; the seat drops out of the count on the next day. If you start a day with 100 seats, add 5 and then end 25, that day bills 105.
- A seat that ends exactly at midnight is not charged for the next day.
- A member revoked and reopened the same day counts once.
- A suspension that starts at noon still charges that day; a day fully inside a suspension charges nothing, even after you pay and service resumes.
- Once a payment is past due, the grace deadline is fixed at that moment and billing never extends past it, however late the housekeeping runs.
Each seat-day is charged to the calendar month that contains it.
The usage endpoint
GET /v1/api/partner/usage?from=YYYY-MM-DD&to=YYYY-MM-DD uses a partner token with partner:read. See GET Usage for headers, query parameters and Python/JavaScript/cURL examples. Supply both dates or omit both. The requested range is inclusive and may span at most 92 days; only closed UTC days are returned. Without dates, the endpoint returns the current month's closed days. On the first of a month, the default list is empty with a total of zero and to is the previous month's last day.
{
"success": true,
"usage": {
"from": "2026-10-01",
"to": "2026-10-04",
"days": [
{
"day": "2026-10-01",
"quantity": 11,
"state": "accepted",
"delivery_state": "accepted",
"computed_at": "2026-10-02T00:20:03Z",
"accepted_at": "2026-10-02T00:20:04Z",
"reconciled_at": null,
"reconciliation_state": "pending",
"invoice": null,
"error": null,
"difference": null
},
{
"day": "2026-10-02",
"quantity": 0,
"state": "reconciled",
"delivery_state": "not_required",
"computed_at": "2026-10-03T00:20:01Z",
"accepted_at": null,
"reconciled_at": "2026-10-03T00:20:01Z",
"reconciliation_state": "matched",
"invoice": null,
"error": null,
"difference": null
},
{
"day": "2026-10-03",
"quantity": 13,
"state": "accepted",
"delivery_state": "accepted",
"computed_at": "2026-10-04T00:20:02Z",
"accepted_at": "2026-10-04T00:20:03Z",
"reconciled_at": null,
"reconciliation_state": "pending",
"invoice": null,
"error": null,
"difference": null
},
{
"day": "2026-10-04",
"quantity": null,
"state": "pending_computation",
"delivery_state": "pending",
"computed_at": null,
"accepted_at": null,
"reconciled_at": null,
"reconciliation_state": "pending",
"invoice": null,
"error": null,
"difference": null
}
],
"total": 24,
"total_is_estimate": true,
"open_seats": 12,
"as_of": "2026-10-05T00:10:05Z"
},
"meta": {
"requestId": "preq_b1c2d3e4f5a60718"
}
}
| Field | Meaning |
|---|---|
from, to | The inclusive window actually answered; to never reaches the open day |
days[].day | The UTC day |
days[].quantity | Seat-days billed for that day; null while pending_computation |
days[].state | The ledger state of the day, listed below |
days[].delivery_state | pending, accepted (Stripe's meter took it), not_required (zero seats), or the ledger state while sending |
days[].computed_at, accepted_at, reconciled_at | When the day was frozen, accepted by Stripe, and reconciled against Stripe's daily meter summary (zero-seat days reconcile locally) |
days[].reconciliation_state | pending, matched or mismatch. Meter reconciliation and later invoice checks can identify discrepancies |
days[].invoice | Reconciled invoice reference (id, quantity, period_start, period_end), or null. Its quantity describes the invoice period, not necessarily this one day's seats |
days[].error | The last send error for the day, null when none |
days[].difference | Invoice-period quantity minus the ledger total for that period once compared, null before |
total | Sum of the known quantities in the window; pending computation contributes zero to this sum, not proof of zero usage |
total_is_estimate | true until every day in the window is reconciled |
open_seats | Seats open at report time; future usage depends on later seat and service-state changes |
as_of | When the report was built |
States per day: computed (frozen, not yet sent), submitting, accepted (Stripe took the event; daily meter reconciliation is pending), reconciled, unknown (the send result is uncertain and checked against meter evidence before any retry), rejected, manual_review. A zero-seat day is reconciled with delivery_state: not_required. Days not yet computed appear as pending_computation, never as zeros.
total_is_estimate becomes false when every returned day is reconciled; this can happen before an invoice exists. Later invoice checks compare metered quantities for the invoice period and can flag discrepancies. Invoice totals can also include the base fee, taxes and discounts.