Skip to content

Balance and events

Scope billing:read. Top-ups are done in the dashboard.

{
"balance": "124.30",
"currency": "USD"
}

Scope billing:read. Parameters: offset, limit, type.

The order is fixed and cannot be configured: newest first, by created_at, ties broken by id. There is no sort parameter.

type: deposit, purchase, refund, commission, bonus - what each of them stands for, see Top-ups and bonuses.

external_reference is the external event that produced the movement, not the transaction identifier (that is id).

promo_code is filled for rows of type bonus - it is the code the bonus was credited for. For other types it is null.

GET /api/v1/events, scope events:read. Read forward from ?after=<id>, oldest first. Parameters: after, limit, type.

{
"events": [
{
"id": 881,
"type": "order.completed",
"occurred_at": "2026-08-28T12:00:04+00:00",
"order_id": 128,
"package_id": 42,
"data": {
"family": "traffic_gateway",
"client_reference": "deal-8891"
}
},
{
"id": 882,
"type": "package.traffic_low",
"occurred_at": "2026-08-28T18:31:00+00:00",
"order_id": 128,
"package_id": 42,
"data": {
"purchased_gb": "35.000",
"left_gb": "3.410"
}
}
],
"next_after": 882
}
TypeWhendata
order.provisioningthe order went into issuancefamily, client_reference
order.completedissuance succeeded; also arrives for an address renewalfamily, client_reference
order.failedthe order did not go through+ refunded
order.refundedthe money was returned+ refunded
package.traffic_lowthe remainder dropped below 10%purchased_gb, left_gb
package.traffic_exhaustedthe volume is used uppurchased_gb, left_gb
package.expiredthe term of a fixed address package has ended, the addresses do not answerexpired_at, cut_off (true - the password is disabled, a renewal issues a new one)
topup.crediteda top-up was creditedamount, external_reference
api_key.revokeda key was revokedapi_key_id, name

For package.* events the order_id field is the order the package was bought with.

  • Delivery is at-least-once: deduplicate by id.
  • next_after is the position for the next request; null means there are no new events.
  • An empty events means you have caught up with the log.
  • Events are kept for 30 days.
after = load_position()
while True:
params = {"limit": 200} | ({"after": after} if after else {})
body = session.get(f"{BASE}/api/v1/events", params=params, headers=AUTH).json()
for event in body["events"]:
if not already_handled(event["id"]):
handle(event)
mark_handled(event["id"])
if body["next_after"] is not None:
after = body["next_after"]
save_position(after)
if not body["events"]:
sleep(15)

Delivery is by polling the log only.