Skip to content

List completed billing-period statements

GET
/wallet/period-statements
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.

subscription_id
integer
limit
integer

Completed statements, newest first.

Media type application/json
Array<object>

One billing period’s cost. For the period in progress the traffic figures are a running estimate.

object
id
integer
subscription_id
integer
plan_id
integer
plan_name
string
plan_term_id
integer
billing_duration_days
integer
quota_reset_days
integer
period_start
string
period_end
string
plan_price_rials
integer
traffic_cached_bytes
integer
traffic_proxied_bytes
integer
traffic_direct_bytes
integer
traffic_bypass_bytes

Legacy two-tier column, on historical periods only.

integer
traffic_charged_rials
integer
by_domain
Array<object>
object
domain
string
cached_bytes
integer
proxied_bytes
integer
direct_bytes
integer
estimated_charged_rials
integer
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.

Media type application/json

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
error
required

Human-readable description of what went wrong.

string
code

Stable machine-readable reason. Present on some failures only; the wording of error may change, this will not.

  • account_suspended403. 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_disabled409, not 403. 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_reseller403. 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_mismatch403 from POST /invites/{token}/accept. The invitation was addressed to a different email; the body also carries invited_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.

string
Examples
Example invalidKey
{
"error": "invalid API key"
}

The key exceeded its request budget (300 requests per minute by default).

Media type application/json

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
error
required

Human-readable description of what went wrong.

string
code

Stable machine-readable reason. Present on some failures only; the wording of error may change, this will not.

  • account_suspended403. 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_disabled409, not 403. 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_reseller403. 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_mismatch403 from POST /invites/{token}/accept. The invitation was addressed to a different email; the body also carries invited_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.

string
Examples
Example limited
{
"error": "rate limit exceeded"
}