---
title: "Arianet Cloud API"
description: "The Arianet Cloud API at api.ariaservice.net/cloud/v1 - servers, volumes, networks, firewalls, IPs, load balancers, images, pricing and rate limits."
url: https://docs.ariaservice.net/en/cloud-api
markdown: https://docs.ariaservice.net/en/cloud-api.md
language: en
---

# Arianet Cloud API

The Cloud API manages **Arianet Cloud** resources: servers, volumes, private networks, NAT gateways, firewalls, floating, elastic and primary IPs, load balancers, images, snapshots and backups. The [`arianet cloud`](https://docs.ariaservice.net/en/cli#arianet-cloud) CLI commands and the [Terraform provider](https://docs.ariaservice.net/en/terraform) are built on it.

- **Base URL:** `https://api.ariaservice.net/cloud/v1`
- **Format:** JSON over HTTPS
- **Auth:** a personal API token sent as a Bearer token ([Authentication](https://docs.ariaservice.net/en/authentication))
- **OpenAPI 3.1:** [`https://api.ariaservice.net/cloud/v1/openapi.json`](https://api.ariaservice.net/cloud/v1/openapi.json), browsable in the [interactive reference](https://docs.ariaservice.net/en/cloud-api-reference)

> **VPS or Cloud?**
VPS ordered through `/api/v1/servers` (the `arianet vps` commands) are documented in the [VPS API](https://docs.ariaservice.net/en/api-endpoints). This page covers Arianet Cloud only. Both APIs accept the same token.

## Quick start

1. Create a token in the panel at [cloud.ariaservice.net/users/api-tokens](https://cloud.ariaservice.net/users/api-tokens) with the scopes `cloud:servers:read` (every `GET`) and `cloud:servers:write` (every change).
2. Call the API:

```bash
export ARIANET_TOKEN="paste-your-token-here"
BASE=https://api.ariaservice.net/cloud/v1
AUTH="Authorization: Bearer $ARIANET_TOKEN"

curl -s $BASE/datacenters -H "$AUTH"                  # datacenter codes, e.g. ovh
curl -s "$BASE/plans?datacenter=ovh" -H "$AUTH"       # plan ids and prices
curl -s "$BASE/images?type=system" -H "$AUTH"         # image slugs, e.g. ubuntu-24.04

curl -s -X POST $BASE/servers -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"name":"web-1","datacenter":"ovh","plan_id":3,"image":"ubuntu-24.04","ssh_key_ids":[5],"labels":{"role":"web"}}'
```

The create answers `201` with the server, the `action_id` of its create action and a `root_password` that is shown **once** (it is never stored in the clear). `count` (1-10) creates several servers in one call. Follow the action until it finishes (see [Actions](#asynchronous-actions)).

## Authentication

```text
Authorization: Bearer <token>
```

| Scope | Allows |
|---|---|
| `cloud:servers:read` | every `GET` |
| `cloud:servers:write` | every `POST`, `PUT`, `PATCH` and `DELETE` |

Resources are always those of the token's account. A missing, invalid or revoked token answers `401`; a token without the needed scope, or used from an address outside its IP allowlist, answers `403`.

## Public price list

The price list needs **no token** and may be called from any origin (cached for a minute):

```bash
curl -s https://api.ariaservice.net/cloud/v1/public/pricing
curl -s "https://api.ariaservice.net/cloud/v1/public/pricing?datacenter=ovh"
```

```json
{
  "pricing": {
    "vat_included": false,
    "hours_per_month": 730,
    "server_types": [
      {
        "id": 1, "name": "C1", "group": "shared", "cores": 1, "memory_mb": 2048, "disk_gb": 20,
        "included_traffic_gb": 20000, "minimum_usage_hours": 1,
        "prices": [
          { "location": "ovh", "price_hourly": { "net": 900, "currency": "IRR" }, "price_monthly": { "net": 657000, "currency": "IRR" } }
        ]
      }
    ],
    "resources": [
      { "sku": "volume_gb", "location": "ovh", "unit": "...", "price_hourly": { "net": 0, "currency": "IRR" }, "price_monthly": { "net": 0, "currency": "IRR" } }
    ]
  }
}
```

`server_types` lists every plan with its price per location; `resources` lists every other price on sale (`primary_ipv4`, `floating_ipv4`, `floating_ipv6`, `elastic_ipv4`, `volume_gb`, `snapshot_gb`, `backup` as a percentage of the plan, load balancer types and `nat_gateway`). Prices exclude VAT and come from the same rows billing uses. `GET /pricing` (with a token) returns your account's own price rows.

## Lists, labels and projects

Every resource list takes:

| Parameter | Meaning |
|---|---|
| `label_selector` | Comma-separated terms that must all hold: `key=value`, `key!=value`, `key` (has the label) or `!key` (has not). Example: `env=prod,tier!=db`. A malformed selector answers `422 invalid_label_selector`. |
| `project_id` | Only resources in this project |
| `page`, `per_page` | Opt-in paging: `per_page` 1-100, default 25. Without `page` and `per_page` the whole list is returned as one page. |

```json
{ "data": [ { "id": 12, "name": "web-1" } ], "meta": { "pagination": { "page": 1, "per_page": 25, "previous_page": null, "next_page": null, "last_page": 1 } } }
```

Resources carry `labels` (key/value pairs) and belong to a project (the account's default project unless you pass `project_id` on create). `PATCH` changes name, labels, delete protection (`protection_delete`) and project; only the fields you send change.

## Asynchronous actions

A change that takes time answers `202` (or `201` for a create) with an `action_id`. Poll the action until `status` is `success` or `error`:

```bash
curl -s $BASE/actions/812 -H "$AUTH"
# {"data":{"id":812,"command":"create","status":"running","progress":40,"resource":{...},"error":null,"started_at":"...","finished_at":null}}
```

`GET /actions` lists the account's actions (newest first) and `GET /<resource>/{id}/actions` those of one resource. With the CLI: `arianet cloud actions wait <id>`.

## Errors

Every error uses one envelope:

```json
{ "error": "Human-readable message", "code": "not_found", "reason": "..." }
```

Branch on `code`, which is stable. `reason` narrows it when there is more than one way to hit it (for example the resource for `quota_exceeded`). The codes each HTTP status can carry are listed under `x-error-codes` in the OpenAPI document.

| HTTP | Typical `code` |
|---|---|
| 400 | `invalid_input` |
| 401 | `unauthorized` |
| 402 | not enough balance for the order |
| 403 | `forbidden`, `identity_needed` |
| 404 | `not_found` |
| 409 | the resource's state does not allow this now (`already_attached`, `ip_change_fee_not_confirmed`, ...) |
| 422 | well-formed but refused (`datacenter_closed`, `invalid_label_selector`, `quota_exceeded`, `plan_sold_out`, ...) |
| 423 | `locked`, `server_locked`, `lb_locked`: the resource is busy with another operation |
| 429 | `rate_limit_exceeded` |
| 503 | `unavailable`, `datacenter_unavailable`, ... (carries `Retry-After`) |

## Rate limits

Each token's account and user may make **3600 requests an hour** and **60 a minute**. Every answer carries:

| Header | Meaning |
|---|---|
| `RateLimit-Limit` | Requests allowed in the current window |
| `RateLimit-Remaining` | Requests left in the window |
| `RateLimit-Reset` | Seconds until the window resets |

Over the limit the answer is `429` with code `rate_limit_exceeded` and a `Retry-After` header (seconds). Wait that long before retrying. A `503` also carries `Retry-After`.

```bash
curl -s -D - -o /dev/null $BASE/servers -H "$AUTH" | grep -i -e ratelimit -e retry-after
```

## Servers

| Method and path | What it does |
|---|---|
| `GET /servers` | List servers |
| `POST /servers` | Create one server, or up to 10 with `count` |
| `GET /servers/{id}` | One server |
| `PATCH /servers/{id}` | Change `name`, `labels`, `protection_delete`, `protection_rebuild` or `project_id` |
| `DELETE /servers/{id}` | Delete a server (options below) |
| `POST /servers/{id}/actions/{op}` | `poweron`, `poweroff` (hard), `shutdown` (ACPI), `reboot`, `reset`, `rebuild` (`{"image":"..."}`), `change_plan` (`{"plan_id":4}`), `enable_rescue`, `disable_rescue`, `reset_password`, `change_ipv4` (`{"confirm_paid":true}` for a paid change) |
| `POST /servers/{id}/actions/attach_to_network`, `detach_from_network` | Private networks |
| `POST /servers/{id}/actions/enable_backup`, `disable_backup`, `change_backup_window`, `create_backup`, `restore_backup` | Backups |
| `POST /servers/{id}/actions/create_image` | Snapshot the server |
| `GET /servers/{id}/costs` | What the server costs (below) |
| `GET /servers/{id}/actions`, `/backups`, `/snapshots`, `/metrics`, `/networking`, `/storage`, `/events`, `/ip-changes` | Details and history |
| `POST /servers/{id}/console` | A single-use VNC console link, valid for 60 seconds |

Create body fields: `name`, `datacenter`, `plan_id`, `image` (required); `ssh_key_ids`, `ssh_keys`, `user_data` (cloud-init, at most 32 KiB), `start_after_create`, `firewall_ids`, `networks`, `volume_ids`, `backups`, `labels`, `project_id`, `count`. `image` is a slug such as `ubuntu-24.04`, or `snapshot:<id>` / `backup:<id>`.

### Deleting a server

```bash
curl -s -X DELETE "$BASE/servers/12?keep_backups=true&delete_snapshots=true" -H "$AUTH"
```

| Query parameter | Default | Meaning |
|---|---|---|
| `keep_backups` | `false` | Keep the finished backups as snapshots, billed per GB until you delete them (`402` when the balance does not cover them) |
| `delete_snapshots` | `false` | Delete the server's snapshots too; protected ones stay. By default snapshots survive the server and stay billed. |
| `reason` | - | Why: `price`, `performance`, `ip_filtered`, `no_longer_needed`, `migrating`, `support` or `other` |
| `note` | - | A few words why (required with `reason=other`, at most 500 characters) |

A server with delete protection must have it turned off first (`PATCH /servers/{id}` with `{"protection_delete": false}`).

### Server costs

`GET /servers/{id}/costs` returns the server's current hourly and monthly rate per billed piece and what its copies would cost after a delete:

```json
{
  "data": {
    "server_id": 12,
    "hours_per_month": 730,
    "lines": [
      { "type": "server", "id": 12, "name": "web-1", "sku": "...", "quantity": 1, "unit": "...", "hourly_price": 3300, "monthly_price": 2409000, "currency": "IRR" },
      { "type": "volume", "id": 7, "name": "data", "sku": "volume_gb", "quantity": 50, "unit": "...", "hourly_price": 0, "monthly_price": 0, "currency": "IRR" }
    ],
    "totals": [ { "currency": "IRR", "hourly_price": 3300, "monthly_price": 2409000 } ],
    "snapshots":    { "count": 1, "size_gb": 20, "hourly_price": 0, "monthly_price": 0, "currency": "IRR" },
    "kept_backups": { "count": 0, "size_gb": 0,  "hourly_price": 0, "monthly_price": 0, "currency": "IRR" }
  }
}
```

Line `type` is `server`, `primary_ipv4`, `floating_ip`, `elastic_ip`, `volume` or `backup`; `quantity` is 1, a volume's GB, or the backup's percent of the plan. `totals` sums the lines per currency. `snapshots` stay billed after a delete; `kept_backups` only with `keep_backups=true`. (Numbers above are illustrative.)

## Other resources

| Resource | Paths |
|---|---|
| Volumes | `/volumes`, `/volumes/{id}`, `POST /volumes/{id}/actions/{op}` (`attach` with `server_id`, `detach`, `resize` with `size_gb`, grow only), `GET /volume-prices` |
| Private networks | `/networks`, `/networks/{id}`, `POST /networks/{id}/subnets`, `DELETE /networks/{id}/subnets/{subnet}`, `PUT /networks/{id}/routes` |
| NAT gateways | `/nat-gateways`, `/nat-gateways/{id}` |
| Firewalls | `/firewalls`, `/firewalls/{id}` (`PUT` replaces the rules), `PUT /firewalls/{id}/servers`, `POST /firewalls/{id}/actions/{op}` (`apply_to_resources`, `remove_from_resources`) |
| Floating IPs | `/floating-ips`, `/floating-ips/{id}`, `POST /floating-ips/{id}/actions/{op}` (`assign`, `unassign`, `change_dns_ptr`) |
| Elastic IPs | `/elastic-ips`, `/elastic-ips/{id}`, `POST /elastic-ips/{id}/actions/{op}` (`assign`, `unassign`) |
| Primary IPs | `/primary-ips`, `/primary-ips/{id}`, `POST /primary-ips/{id}/actions/change_dns_ptr` |
| Load balancers | `/load-balancers`, `/load-balancers/{id}`, `POST /load-balancers/{id}/actions/{op}` (services, targets, type, algorithm, private network), `GET /load-balancers/{id}/health`, `GET /load-balancer-types` |
| Images | `GET /images`, `GET /images/custom`, `GET /datacenters/{code}/images` |
| Snapshots and backups | `/snapshots`, `/snapshots/{id}`, `/backups`, `/backups/{id}`, `POST /backups/{id}/actions/convert` (keep a backup as a snapshot) |
| Catalog and account | `GET /datacenters`, `GET /plans`, `GET /pricing`, `GET /public/pricing`, `GET /limits` |
| Actions | `GET /actions`, `GET /actions/{id}`, `GET /actions/{id}/events` |

Every field, body and answer is in the [interactive reference](https://docs.ariaservice.net/en/cloud-api-reference) and the [OpenAPI document](https://api.ariaservice.net/cloud/v1/openapi.json).

## Tools

- [CLI](https://docs.ariaservice.net/en/cli#arianet-cloud): `arianet cloud ...`
- [Terraform provider](https://docs.ariaservice.net/en/terraform): `ariaservice/arianet`
