Every SERP API bill ends the same way: you find out you're out of credits when a request fails with 1020. But there's a way to see the number before that happens, and it costs nothing to check — GET /account/credits is a documented utility endpoint that doesn't consume search credits at all.
I wired this into my monitoring scripts last month after a nightly job died at 2am on an empty balance. Now the job checks the balance first, alerts before the threshold, and I haven't been surprised since.
What the endpoint gives you
Per the docs, GET /account/credits returns the current balance for the account that owns an active API key. The response separates what you have into:
-
credits— the total you can spend right now -
permanent_credits— the portion with no calendar expiry -
expiring_credits— the portion tied to a subscription cycle, withexpiring_expires_atas a Unix timestamp in seconds; it's0when no limited-time credits are active
That split matters. If your balance looks healthy but most of it is expiring credits, you have a scheduling problem, not a budget problem — use the permanent balance for long-term plans and burn the expiring one first.
Auth is the same as everywhere else: the key goes in the X-API-Key header. URL query parameters are not accepted, so don't try ?api_key=. The endpoint is rate limited to 60 requests per minute per account — plenty for a pre-flight check, and the docs confirm it doesn't consume search credits. Field definitions are in SerpBase's endpoint documentation.
The pre-flight check
import requests
API = "https://api.serpbase.dev"
KEY = "your_api_key" # your key here
def balance() -> dict:
resp = requests.get(f"{API}/account/credits",
headers={"X-API-Key": KEY}, timeout=15)
data = resp.json()
if data.get("status") != 0:
raise RuntimeError(f"{data.get('status')}: {data.get('error')}")
return data
if __name__ == "__main__":
b = balance()
print(f"total: {b['credits']}")
print(f"permanent: {b['permanent_credits']}")
print(f"expiring: {b['expiring_credits']} (expires_at={b['expiring_expires_at']})")
Three ways I use it in practice:
-
Pre-flight guard. Before a batch job starts, fetch the balance and compare it against
len(keywords) * credits_per_request. If the balance is short, alert and skip the run instead of dying halfway through with a partial CSV. -
Expiry awareness. When
expiring_creditsis non-zero, logexpiring_expires_atnext to the daily run — if you're burning 40 credits a day with 400 expiring, you have ten days to use them, and that's a signal to move monitoring to a weekly cadence rather than buy more. -
Post-run reconciliation. After a batch, subtract the run's successful request count from the starting balance. If the numbers don't line up, the
request_idon each response is the stable identifier to correlate with support.
FAQ
Does checking the balance really cost nothing? Yes — the docs list it as 0 credits. That's the whole point: you can check as often as you need inside the 60 requests/minute limit.
Why did my balance check fail with 1001? Same as any other endpoint — missing, invalid, or revoked key. The header name is X-API-Key; query-string keys are not accepted.
Can I check the balance from the MCP server? The MCP tools cover the six search endpoints. For balance checks, call this endpoint directly — it's a plain GET with the same key.
How often should a scheduled job check? Once per run is enough for a daily job. If you run hourly batches, once an hour stays far below the 60/min limit.
Add the pre-flight guard to your next batch script tonight — it's four lines, and it turns "why did my job die" into "my job told me it was low before it started".
Top comments (0)