Top up credits
Add purchased credits to a tenant. Purely additive, idempotent on your key, and billed on assign. Addressed by tenant_id.
https://api.swarmz.net/functions/v1/platform-topupAdds purchased credits to a tenant. The operation is purely additive — it increments the tenant's topup_credits balance via the platform_topup_credits RPC and never replaces or resets existing balances. Address the tenant by tenant_id — the id returned by create — or fall back to your external_ref. Supply exactly one identifier.
Billed on assign
Top-up credits are billed to your platform account at the moment they are
assigned to the tenant, not when the tenant later spends them. A successful
top-up is a chargeable event — which is exactly why the idempotency_key is
required (see Idempotency).
Parameters
Prop
Type
Request
curl -X POST https://api.swarmz.net/functions/v1/platform-topup \
-H "Authorization: Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" \
-H "Content-Type: application/json" \
-d '{
"tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242",
"amount": 100,
"idempotency_key": "whmcs:1234:topup-2026-05-23-0001"
}'const res = await fetch('https://api.swarmz.net/functions/v1/platform-topup', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6',
'Content-Type': 'application/json',
},
body: JSON.stringify({
tenant_id: 'aa7d7fae-0386-4d8a-b977-72f856eac242',
amount: 100,
idempotency_key: 'whmcs:1234:topup-2026-05-23-0001',
}),
});
const data = await res.json();import requests
res = requests.post(
"https://api.swarmz.net/functions/v1/platform-topup",
headers={"Authorization": "Bearer sk_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"},
json={
"tenant_id": "aa7d7fae-0386-4d8a-b977-72f856eac242",
"amount": 100,
"idempotency_key": "whmcs:1234:topup-2026-05-23-0001",
},
)
data = res.json()Response
After the credit is applied the function re-reads workspace_billing and returns a fresh snapshot:
{
"ok": true,
"balances": {
"included_credits": 0,
"included_credits_used": 0,
"rollover_credits": 0,
"rollover_credits_used": 0,
"topup_credits": 100,
"daily_bonus_limit": 50,
"daily_bonus_used": 0
}
}| Field | Type | Description |
|---|---|---|
ok | boolean | Always true on success. |
balances | object | Fresh snapshot of the tenant's workspace_billing row. {} if the row could not be re-read (the top-up still applied). |
balances.included_credits | number | Monthly grant for the current cycle. |
balances.included_credits_used | number | Monthly grant consumed this cycle. |
balances.rollover_credits | number | Credits carried over from prior cycles. |
balances.rollover_credits_used | number | Rollover consumed this cycle. |
balances.topup_credits | number | The purchased-credit balance this endpoint increments. |
balances.daily_bonus_limit | number | Daily free-credit allowance. |
balances.daily_bonus_used | number | Daily free credits used today. |
Which fields matter for a tenant
For platform tenants, topup_credits, daily_bonus_limit, and
daily_bonus_used are the meaningful fields. The included_* / rollover_*
fields are returned for completeness and are driven by the plan +
plan-refresh cycle, not by this endpoint.
Errors
| Status | error | reason | When |
|---|---|---|---|
| 400 | missing_fields | tenant_id or external_ref required | Neither identifier supplied |
| 400 | invalid_amount | amount must be a positive finite number | amount is non-positive, non-finite, or not a number |
| 400 | missing_fields | idempotency_key required | idempotency_key absent or not a string |
| 401 | unauthorized | missing_bearer / invalid_key / account_disabled | See Authentication |
| 404 | tenant_not_found | — | No tenant matched the identifier under your account |
| 405 | method_not_allowed | — | Anything other than POST |
| 409 | suspended | — | The tenant is suspended |
| 410 | terminated | — | The tenant has been terminated |
| 409 | tenant_not_active | the client_status | The tenant exists but is in some other non-active state |
| 429 | rate_limited | per_key / per_ip | Rate limit hit — see Rate limits |
| 500 | topup_failed | RPC message | The platform_topup_credits RPC failed server-side; safe to retry with the same idempotency_key |
| 500 | internal_error | — | Unhandled server error; safe to retry with the same key |
Status checks run in order
The function checks suspended (409) → terminated (410) → any other
non-active state (409 tenant_not_active) before touching credits, so a
non-active tenant is never charged.
Idempotency
Top-up is idempotent on idempotency_key. A retry with the same key is a no-op at the RPC level — it does not add the amount again and does not bill again — and the endpoint still returns the current balances. Always reuse the same key when retrying a top-up after a network error or a 500. See Idempotency.
Notes
A suspended tenant rejects top-ups
Topping up a suspended tenant returns 409 suspended. Queue the top-up and
replay it after unsuspend. Because the idempotency key dedupes
the charge, the queued retry is safe — re-sending it once the tenant is active
applies the credit (and the bill) exactly once.
- Address the tenant by
tenant_idfromcreate;external_refis the fallback. - Top-up is for purchased credits only. The monthly grant and rollover are owned by the plan and the
plan-refreshcycle, not by this endpoint.
List your plans
Enumerate the named plans defined for your platform account. Each plan carries a stable code you map to a WHMCS product and later pass to create or plan.
Suspend a tenant
Reversibly pause a tenant — flip it to suspended, take its public site offline, and tear down running infrastructure. The prior state is captured for unsuspend to replay.