API Reference
Get remaining credits
Two numbers for the account behind the key: everything credited to it and everything it has spent. Any key on the account reads the same pair.
GET/api/v1/credits
The key in the header is the whole request: there are no path, query or body parameters, and no way to ask for a period — both numbers cover the entire life of the account. The call itself costs nothing and works at any balance, including zero.
Response
| Field | Type | Description |
|---|---|---|
| data. | numberrequired | Everything credited to the account, in US dollars: the current balance plus everything already charged. It is not a sum of your transfers — a correction made on our side moves it too, and the service fee on a top-up never enters it. |
| data. | numberrequired | Everything charged to the account, in US dollars, summed from its request log — the same amounts you see per request in usage.cost and in the account area. |
Scroll the table sideways for the description.
{
"data": {
"total_credits": 250.0,
"total_usage": 173.418244
}
}Both are lifetime totals carried to six decimal places, and neither is windowed: nothing resets at midnight, at the start of a month or thirty days back. total_usage only ever grows; total_credits goes down only if a balance correction is made, or for as long as a request is in flight (below). For spend inside the current day, week or month, and for any ceiling set on the account, read the key route instead.
Remaining balance
There is no remaining field. Subtract: total_credits - total_usage is the money left to spend, and it is the same figure the account area shows. In the example above that is 76.581756.
curl -s https://api.gtokens.io/api/v1/credits \
-H "Authorization: Bearer sk-sl-your-key" \
| jq '.data.total_credits - .data.total_usage'import requests
r = requests.get(
"https://api.gtokens.io/api/v1/credits",
headers={"Authorization": "Bearer sk-sl-your-key"},
timeout=30,
)
r.raise_for_status()
data = r.json()["data"]
remaining = data["total_credits"] - data["total_usage"]
if remaining < 1.0: # stop before requests start coming back 402
raise SystemExit(f"balance is down to {remaining:.2f}")const r = await fetch('https://api.gtokens.io/api/v1/credits', {
headers: { Authorization: 'Bearer sk-sl-your-key' },
})
if (!r.ok) throw new Error(`credits: ${r.status}`)
const { data } = await r.json()
const remaining = data.total_credits - data.total_usage
if (remaining < 1) throw new Error(`balance is down to ${remaining.toFixed(2)}`)Both fields arrive as JSON doubles, so the difference can come out with a floating tail such as 76.58175600000001. Compare it against a threshold rather than testing for zero, and stop a batch while the threshold is still above the price of one request: once the balance cannot cover a request, that request comes back 402 payment_required and is not charged.
Before a request goes upstream we hold an estimate of its price against the balance, and the charge reaches total_usage only when the request settles. So while requests are in flight the difference is smaller than the money you actually have — never larger. The held estimate returns the moment the request finishes, whether it succeeded or failed, and a hold left behind by a request that never finished is returned on its own.
Errors
Every error arrives in the same envelope: the HTTP status repeated in error.code, a message meant for a human, and the code to branch on in error.metadata.error_type.
{
"error": {
"code": 401,
"message": "missing bearer token",
"metadata": {
"error_type": "authentication",
"reason": "invalid_credentials"
}
}
}| Status | When it happens | error_type |
|---|---|---|
| 401 | No Authorization header, a header that is not a bearer token, or a key that is unknown or revoked. | authentication |
| 403 | The key is valid, but the account is suspended. Reissuing the key changes nothing here. | permission_denied |
| 500 | Our side failed. The body carries no detail beyond this; the request is safe to repeat. | server |
Scroll the table horizontally for the typed code.
Every status and typed codeAuthorization
The key goes in as a bearer token, here as on every other route:
Authorization: Bearer sk-sl-…
The two numbers belong to the account, not to the key that asked for them: keys of one account share one balance, so all of them return the same pair.
How keys are issued and used