Authentication
Two credential types, both sent as Authorization: Bearer <value>.
1 — Short-lived JWT (interactive)
curl -s https://panel.cachivo-l7.com/api/v1/auth/login \
-H 'content-type: application/json' \
-d '{"email":"[email protected]","password":"…"}'
# -> {"access_token":"eyJ…","refresh_token":"eyJ…","token_type":"bearer"}
Access tokens last 15 minutes; refresh with POST /auth/refresh.
POST /auth/logout revokes every outstanding token for the user.
2 — Long-lived API token (automation)
curl -s -X POST https://panel.cachivo-l7.com/api/v1/tokens \
-H "authorization: Bearer $JWT" -H 'content-type: application/json' \
-d '{"label":"ci-bot","expires_in_days":365}'
# -> {"id":3,"token":"pp_…","note":"store this now — it is not shown again"}
Tokens are stored only as a SHA-256 digest — the value cannot be recovered.
Mint and revoke them in the dashboard under API Tokens, or via
DELETE /tokens/{id}. A token carries exactly its owner's permissions.
Roles
| Role | Can do |
admin | Everything: resellers, credit, PoP fleet, settings, audit, approvals |
reseller | Own servers, own wallet and API tokens |
Tenant isolation is enforced on every query. A request for another tenant's
object returns 404 — never 403 — so object existence never leaks.
Protected servers
| Endpoint | Notes |
GET/servers | List (tenant-scoped) — ?search= ?limit= ?offset= |
POST/servers | Create admin · reseller |
GET/servers/{id} | Fetch one |
POST/servers/{id}/suspend | Withdraw config + park DNS |
POST/servers/{id}/resume | Re-provision + re-publish |
POST/servers/{id}/approve | Approval gate admin |
DELETE/servers/{id} | Soft-delete + remove DNS |
curl -s -X POST https://panel.cachivo-l7.com/api/v1/servers \
-H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"origin_fqdn":"shop-origin.example.com","subdomain_label":"server33312",
"protocol":"https","origin_port":443}'
# -> {"id":7,"assigned_subdomain":"server33312.scrubbing.top","status":"active", …}
Self-service
| Endpoint | Notes |
GET/me | Who am I |
GET/me/servers | My servers |
GET/me/wallet | Credit balance + ledger reseller |
GETPOSTDEL/tokens | Manage API tokens |
Administration admin
| Endpoint | Notes |
GET/admin/overview | Counts: resellers, servers, PoP health |
GETPOST/admin/resellers | List / create resellers |
POST/admin/resellers/{id}/credit | Top up — auto-resumes suspended servers |
GETPOST/admin/pops | Fleet list / one-click add (202 + job id) |
POST/admin/pops/{id}/drain | Drain from the load balancer |
GET/admin/fleet | Live CPU / RAM / traffic per PoP |
GET/admin/pops/{id}/metrics | Time-series — ?minutes= ?resolution= |
GETPOST/admin/settings | grace_days, monthly_points, auto-approve |
GET/admin/audit | Append-only audit log |
Errors & limits
| Status | Meaning |
401 | Unauthenticated — missing, expired or revoked credential |
403 | Authenticated but the wrong role for this action |
404 | Not found or not yours (existence is never leaked) |
402 | Insufficient credit to activate or renew |
409 | Conflict — subdomain or name already taken |
422 | Validation error — check the detail field |
429 | Rate limited (login is throttled per IP and per account) |
All errors are returned as {"detail": "…"}.