API overview
Base URL: https://api.hypercall.dev
| Surface | Auth | What |
|---|---|---|
/api/* | Authorization: Bearer uk_… | Your account and your sub-users |
/stats/{token} | none | Usage by opaque token |
/locations/* | none | Available countries, regions, cities, ASNs |
The full machine-readable spec is openapi.yaml. Import it
into Postman or Insomnia, or generate a client from it.
Authentication
curl -H "Authorization: Bearer $HYPERCALL_KEY" https://api.hypercall.dev/api/me
A missing or invalid key returns:
{ "message": "Invalid API key." }
Errors
| Status | Body | Meaning |
|---|---|---|
401 | {"message": "Invalid API key."} | Bad or missing credentials |
403 | {"message": "..."} | Account inactive, or lacks the capability |
404 | {"message": "Not found."} | Not found, or not yours (see below) |
422 | {"message": "..."} | Validation error |
422 | {"error": "..."} | Billing error, e.g. insufficient balance |
Note the two distinct 422 shapes: message means the request was malformed;
error means the request was valid but there is a billing problem, such as
insufficient balance.
404 is deliberately ambiguous. Asking about a sub-user that isn’t yours
returns 404, not 403; the API never confirms that an account you don’t own
exists.
Idempotency
Creating a sub-user (POST /api/users) and allocating data
(POST /api/users/{id}/allocate) accept an Idempotency-Key header. Retrying
with the same key replays the original response instead of doing the work
twice:
curl -H "Authorization: Bearer $HYPERCALL_KEY" \
-H 'Idempotency-Key: order-4417' \
-X POST -H 'Content-Type: application/json' \
-d '{"name": "customer-a", "gb": 50}' \
https://api.hypercall.dev/api/users
Use it for anything triggered by a queue, a webhook, or a user clicking twice.
The account model
Every account is the same kind of object. parent_id describes the whole
hierarchy:
parent_id: null: a top-level account.parent_idset: a sub-user, created by (and drawing budget from) its parent.
can_resell gates whether an account may create sub-users. Nesting can go as
deep as you need: a sub-user with can_resell can carve its own budget
further down, using the identical endpoints.
Bytes follow one rule everywhere:
remaining = max_bytes − allocated_bytes − bytes_used
allocated_bytes is what you’ve handed to sub-users; bytes_used is your own
proxy traffic. A parent pays once, at allocation. A sub-user’s consumption
never draws on the parent again.