List completed billing-period statements
const url = 'https://api.nsin.cloud/wallet/period-statements';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.nsin.cloud/wallet/period-statements \ --header 'Authorization: Bearer <token>'A period statement is the frozen record of one closed billing period of one
subscription — the plan price, the period’s traffic bytes per tier, the rials
actually charged for that traffic, and the per-GB rates that were in force —
written once when the period closes at renewal, at a manual extension, or on
the drop into grace. It is deliberately not a tax document: no number, no VAT,
is_estimate false and not_a_tax_invoice true. The numbered counterpart of
the same close is the period-kind row in GET /invoices, which itemizes only
the overage actually debited from the wallet. Rows span every subscription on
the account, newest period_end first; limit defaults to 50 and is clamped
to 1–200, and there is no offset, so the newest 200 statements are all you can
reach. subscription_id is accepted but never applied — filter on each row’s
own subscription_id yourself.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters ”Responses
Section titled “ Responses ”Completed statements, newest first.
One billing period’s cost. For the period in progress the traffic figures are a running estimate.
object
Legacy two-tier column, on historical periods only.
object
Example generated
[ { "id": 1, "subscription_id": 1, "plan_id": 1, "plan_name": "example", "plan_term_id": 1, "billing_duration_days": 1, "quota_reset_days": 1, "period_start": "example", "period_end": "example", "plan_price_rials": 1, "traffic_cached_bytes": 1, "traffic_proxied_bytes": 1, "traffic_direct_bytes": 1, "traffic_bypass_bytes": 1, "traffic_charged_rials": 1, "by_domain": [ { "domain": "example", "cached_bytes": 1, "proxied_bytes": 1, "direct_bytes": 1, "estimated_charged_rials": 1 } ] }]Missing, malformed, revoked or expired API key, or a key whose owning
user row is gone. A key whose owning account has merely been deactivated
is not this: that is 403 with code: account_suspended, because the
credential itself is intact and re-issuing it changes nothing.
The error shape used by every endpoint. error is always present. code
is present only on the failures that have one — do not require it, and do
not parse error to recover it.
object
Human-readable description of what went wrong.
Stable machine-readable reason. Present on some failures only; the
wording of error may change, this will not.
account_suspended—403. The account behind the credential has been switched off, by an admin or by its provider. Every authenticated route answers this, so treat it as terminal rather than retrying.domain_disabled—409, not403. You have every right to the operation; the domain is simply switched off and is not being served, so its configuration cannot change. It stays readable, and writes work again once it is enabled.managed_by_reseller—403. The account is a reseller’s client and this surface belongs to its provider. See If your account is managed by a reseller.invite_email_mismatch—403fromPOST /invites/{token}/accept. The invitation was addressed to a different email; the body also carriesinvited_email, masked.
A panel session — not an API key — can additionally see
session_check_failed on a 503, which means the session could not
be verified, not that it is invalid. Retry it; do not discard the
token.
Examples
{ "error": "invalid API key"}The key exceeded its request budget (300 requests per minute by default).
The error shape used by every endpoint. error is always present. code
is present only on the failures that have one — do not require it, and do
not parse error to recover it.
object
Human-readable description of what went wrong.
Stable machine-readable reason. Present on some failures only; the
wording of error may change, this will not.
account_suspended—403. The account behind the credential has been switched off, by an admin or by its provider. Every authenticated route answers this, so treat it as terminal rather than retrying.domain_disabled—409, not403. You have every right to the operation; the domain is simply switched off and is not being served, so its configuration cannot change. It stays readable, and writes work again once it is enabled.managed_by_reseller—403. The account is a reseller’s client and this surface belongs to its provider. See If your account is managed by a reseller.invite_email_mismatch—403fromPOST /invites/{token}/accept. The invitation was addressed to a different email; the body also carriesinvited_email, masked.
A panel session — not an API key — can additionally see
session_check_failed on a 503, which means the session could not
be verified, not that it is invalid. Retry it; do not discard the
token.
Examples
{ "error": "rate limit exceeded"}