Authentication
Attach the key to every request header. No key or a bad key returns 401.
curl -H "Authorization: Bearer vk_xxxxxxxx" \
https://onie.net/v1/vmScopes
A key can only call endpoints within the scopes you picked when creating it. Missing scope returns 403 with code `scope_required`.
catalog:read | Read plans and catalog |
|---|---|
vm:read | Read VMs, metrics and VM invoices |
vm:write | Power actions, minor changes, firewall, snapshots |
vm:create | CREATE new VMs (costs money) |
vm:plan | CHANGE PLAN / custom resize (costs money) |
vm:destroy | DELETE VMs |
vm:console | Open VNC console tickets |
sshkey:read | Read stored SSH keys |
sshkey:write | Add/remove SSH keys |
billing:read | Read wallet, invoices, payments (READ ONLY) |
shield:read | Read your own DDoS Shield |
shield:write | Write your own DDoS Shield rules |
Endpoints
62 endpoints. “Scope” is what the key must have.
catalog
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/vm/catalog | Plans, regions and OS images | catalog:read |
GET /v1/public/plans | Public price list of the site | catalog:read |
GET /v1/vm/prices | Unit prices per component (vCPU, RAM, disk) | catalog:read |
GET /v1/vm/custom-quote | Quote a custom configuration | catalog:read |
vm
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/vm | List VMs | vm:read |
GET /v1/vm/:id | Get one VM | vm:read |
GET /v1/vm/:id/metrics | CPU/RAM/disk/network over time | vm:read |
GET /v1/vm/:id/bandwidth | Bandwidth usage | vm:read |
GET /v1/vm/:id/volumes | Volumes of the VM | vm:read |
GET /v1/vm/:id/nics | Network interfaces and IPs | vm:read |
GET /v1/vm/:id/events | VM event log | vm:read |
GET /v1/vm/:id/jobs | Running jobs of the VM | vm:read |
GET /v1/vm/:id/billing | Billing of this VM | vm:read |
GET /v1/vm/:id/plan-quote | Quote before changing plan | vm:read |
GET /v1/vm/:id/plan-options | Plans this VM can switch to (same zone) | vm:read |
GET /v1/vm/:id/delete-preview | Preview before delete | vm:read |
GET /v1/vm/:id/firewall | Firewall rules | vm:read |
GET /v1/vm/:id/port-forwarding | Port forwarding rules | vm:read |
GET /v1/vm/:id/snapshots | List snapshots | vm:read |
GET /v1/vm/ops-key | The pre-attached ops SSH key (name + fingerprint, not a secret) | vm:read |
POST /v1/vm/:id/start | Start the VM | vm:write |
POST /v1/vm/:id/stop | Stop the VM (graceful) | vm:write |
POST /v1/vm/:id/force-stop | Force stop the VM | vm:write |
POST /v1/vm/:id/reboot | Reboot the VM | vm:write |
POST /v1/vm/:id/reset-password | Reset the admin password | vm:write |
POST /v1/vm/:id/ssh-key | Attach an SSH key to the VM | vm:write |
PATCH /v1/vm/:id | Rename / notes | vm:write |
POST /v1/vm/:id/firewall | Add a firewall rule | vm:write |
DELETE /v1/vm/:id/firewall/:rule_id | Delete a firewall rule | vm:write |
POST /v1/vm/:id/port-forwarding | Add a port-forwarding rule | vm:write |
DELETE /v1/vm/:id/port-forwarding/:rule_id | Delete a port-forwarding rule | vm:write |
POST /v1/vm/:id/snapshots | Create a snapshot | vm:write |
DELETE /v1/vm/:id/snapshots/:sid | Delete a snapshot | vm:write |
POST /v1/vm | Create a VM (charges the wallet) Idempotency-Key required | vm:create |
POST /v1/vm/:id/change-plan | Change plan (prorated) Idempotency-Key required | vm:plan |
POST /v1/vm/:id/change-custom | Custom resize Idempotency-Key required | vm:plan |
DELETE /v1/vm/:id | Delete the VM (data is lost) Idempotency-Key required | vm:destroy |
GET /v1/vm/:id/console | Get a one-time VNC console ticket | vm:console |
POST /v1/vm/:id/ssh-token | Get a one-time SSH WebSocket token | vm:console |
GET /v1/vm/:id/ai-agent/status | AI SSH Agent status and history | vm:read |
POST /v1/vm/:id/ai-agent/clear | Start a new AI SSH Agent session | vm:write |
POST /v1/vm/:id/ai-agent | Run AI SSH Agent (SSE stream) | vm:console |
GET /v1/vm/:id/console-shares | List active SSH session share links | vm:read |
POST /v1/vm/:id/console-shares | Create an SSH session share link | vm:console |
DELETE /v1/vm/:id/console-shares/:sid | Revoke an SSH session share link | vm:console |
sshkey
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/vm/sshkeys | List SSH keys | sshkey:read |
POST /v1/vm/sshkeys | Add an SSH key | sshkey:write |
DELETE /v1/vm/sshkeys/:id | Delete an SSH key | sshkey:write |
billing
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/billing/wallet | Wallet balance | billing:read |
GET /v1/billing/summary | Billing overview | billing:read |
GET /v1/billing/invoices | List invoices | billing:read |
GET /v1/billing/invoices/:id | Get one invoice | billing:read |
GET /v1/billing/payments | Payment history | billing:read |
GET /v1/billing/orders | Order history | billing:read |
GET /v1/client/usage | Current usage | billing:read |
shield
| Endpoint | What it does | Scope |
|---|---|---|
GET /v1/tenants/:tid/summary | DDoS Shield overview | shield:read |
GET /v1/tenants/:tid/targets | Protected IPs | shield:read |
GET /v1/tenants/:tid/targets/:id/rules | Rules of one IP | shield:read |
GET /v1/tenants/:tid/targets/:id/events | Attack events of one IP | shield:read |
GET /v1/tenants/:tid/traffic | Edge traffic | shield:read |
POST /v1/tenants/:tid/targets/:id/rules | Add a blocking rule | shield:write |
DELETE /v1/tenants/:tid/targets/:id/rules/:rid | Delete a blocking rule | shield:write |
Rate limits
120 per key per minute, 300 per account per minute. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; over the limit you get 429 with Retry-After (seconds to wait).
X-RateLimit-Limit: 120 X-RateLimit-Remaining: 118 X-RateLimit-Reset: 1758658800 Retry-After: 37 ← chỉ có khi 429 X-Request-Id: r7f2a9c1b4e8d0a63
Money-spending calls
Creating a VM, changing plan and deleting a VM require an Idempotency-Key header. Repeating the same value returns the earlier result instead of doing it again — a flaky network will not charge you twice.
curl -X POST https://onie.net/v1/vm \
-H "Authorization: Bearer vk_xxxxxxxx" \
-H "Idempotency-Key: don-hang-2026-09-23-001" \
-H "Content-Type: application/json" \
-d '{"plan":"vm-1-2","template":"ubuntu-24.04","hostname":"web-01"}'Error shape
Every error uses the same shape, with X-Request-Id so support can trace it.
{
"error": {
"code": "scope_required",
"message": "Khoá thiếu phạm vi quyền 'vm:write' cho POST /v1/vm/:id/start"
}
}Where to call from
This API is for your servers. CORS is not enabled, so it cannot be called from a browser. Never embed a key in client-side code.