> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rafftechnologies.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Changelog

> Track all changes to the Raff API

<sub>Updated May 25, 2026</sub>

# API Changelog

All changes to the Raff public API. Current version: **v1.0.0** (beta).

🟢 Added · 🔵 Updated · 🟡 Deprecated · 🔴 Removed · 🟣 Fixed

***

## v1.0.0 (Beta)

### May 25, 2026

**Catalog — API**

* 🟢 **Added** — `out_of_stock` field on `VMPricingPlan` — `GET /api/v1/public/pricing/vm`. Marks a plan as sold out. Informational only — the plan is still listed and can be ordered.

**Catalog — CLI**

* 🟢 **Added** — `STOCK` column on `raff pricing vm`, showing `In Stock` / `Sold Out`.

**Catalog — Terraform**

* 🟢 **Added** — `out_of_stock` attribute on `data.raff_vm_pricing` plans.

### May 14, 2026

**Virtual Machines — API**

* 🔵 **Updated** — Backups now run as **incremental backup series** instead of one full image per call. Only changed blocks are stored after the first baseline, cutting storage and transfer dramatically. Existing backups taken before this change keep working unchanged — they restore identically to today.
* 🔵 **Updated** — `storage_size` on `Backup` is now **MB** (was GB). Incremental restore points are often a few MB; the previous integer-GB column rounded them up to 1 GB and overstated both display and billing. Existing rows have been backfilled (`old_value_in_GB * 1024`) so customer-visible amounts stay consistent. Clients should display in MB up to 1024, else convert to GB.
* 🟢 **Added** — `increment_id` field on `Backup` — `GET /api/v1/backups`. Position of a restore point within an incremental series; `null` for legacy standalone backups.
* 🟢 **Added** — **Delete backup series** — `DELETE /api/v1/backups/{id}/chain`. Removes every restore point in a series in one call. Use this when [Delete backup](/api-reference/virtual-machines/delete-backup) reports that older points depend on the one being deleted.
* 🟢 **Added** — **Reset backup series** — `POST /api/v1/vms/{id}/backups/reset-chain`. Starts a fresh baseline on the next backup; existing restore points stay restorable.

### May 10, 2026

**Virtual Machines — API**

* 🟢 **Added** — `mac` field on `VMNetwork` — `GET /api/v1/vms/{id}/networks`. Stable per-NIC MAC address. The backend already returned it; spec now documents it so generated clients expose it.

**Volumes — API**

* 🟣 **Fixed** — `pricing_id` now auto-derived from `volume_type` + `region` on `POST /api/v1/volumes`. The public spec never required customers to supply it, but the billing middleware did — every CLI/Terraform/curl request was returning 400 until you looked it up out-of-band.
* 🟣 **Fixed** — `filesystem_type` is now honored. A wire-mapping bug in vm-service was discarding the value and validating `volume_type` (e.g. `nvme`) as if it were a filesystem, rejecting all valid `ext4` / `xfs` / `""` combinations with "filesystem\_type must be empty (manual), ext4, or xfs".
* 🔵 **Updated** — pricing\_id required-error now points at `raff pricing vm` (CLI) and `data.raff_vm_pricing` (Terraform) alongside the HTTP path.

**Billing — API**

* 🟣 **Fixed** — Add-payment-method (`POST /api/v1/billing/payment-methods`) now returns 503 if Airwallex's payment-source linking step fails, instead of saving an unusable row that looked like a working primary card. Customers no longer end up with a dashboard-confirmed card that fails the first time the API tries to charge it.
* 🟣 **Fixed** — "Payment method not configured for automatic billing" error correctly identifies the affected row (filters by `provider_type` and non-empty source ID) instead of firing on any active payment row.
* 🔵 **Updated** — Error messages link to `app.rafftechnologies.com` regardless of environment (was hardcoded to a local-dev hostname).

**Virtual Machines — CLI**

* 🟢 **Added** — `raff vm create --no-vpc` — create a VM with only a public IP, no VPC at all. (raff-cli v0.3.5)
* 🟢 **Added** — `MAC` column on `raff vm networks`. (raff-cli v0.3.6)
* 🔵 **Updated** — `raff vm create --help` long help spells out all four networking modes (existing VPC / new VPC / no VPC / auto VPC). (raff-cli v0.3.4)
* 🔵 **Updated** — `raff vm get` shows base disk and attached volumes as separate rows (was a single collapsed "Storage" row). (raff-cli v0.3.4)
* 🔵 **Updated** — `vm networks` public-pool NICs show `(public pool)` instead of an empty `NETWORK` cell. (raff-cli v0.3.4)

**Volumes — CLI**

* 🔵 **Updated** — `raff volume create --type` help enumerates `nvme` (was a misleading "e.g. standard"). (raff-cli v0.3.3)
* 🔵 **Updated** — `raff pricing volume` table view shows the `ID` column. (raff-cli v0.3.3)

**Networking — CLI**

* 🔵 **Updated** — Security-group attachment count now labeled "Attached VMs" everywhere (was inconsistent — `VMS` in list, `Attached NICs` in get). (raff-cli v0.3.4)
* 🔴 **Removed** — Unexplained `SIZE` column from `raff sg get` rules subtable. (raff-cli v0.3.4)

**Virtual Machines — Terraform**

* 🟢 **Added** — `data "raff_vm_networks"` — list NICs for a VM with MAC, IP, gateway, and security-group binding. (terraform-provider-raff v0.1.8)
* 🟢 **Added** — `skip_vpc` argument on `raff_vm`. (terraform-provider-raff v0.1.7)
* 🔵 **Updated** — `raff_vm` schema descriptions for `vpc_id` / `vpc_name` / `vpc_cidr` / `delete_vpc` / `volume_action` rewritten to spell out the actual contract instead of one-liners. (terraform-provider-raff v0.1.6)
* 🔵 **Updated** — `volume_type = "nvme"` in README and Registry index examples (was an invalid `"standard"`). (terraform-provider-raff v0.1.4)

**Networking — Terraform**

* 🟢 **Added** — `data "raff_vpc_cidr_suggestions"` — fetch a non-overlapping CIDR for declarative VPC sizing. (terraform-provider-raff v0.1.9)
* 🟢 **Added** — `data "raff_security_group_templates"` — look up template IDs to pass to `raff_security_group.template_id`. (terraform-provider-raff v0.1.9)

**Team & Access — Terraform**

* 🟢 **Added** — `data "raff_permissions"` — read-only catalog of permission identifiers; supports `scope` filter (`account` / `project`). (terraform-provider-raff v0.1.9)

**Reference — site**

* 🔵 **Updated** — Terraform Registry sidebar collapsed from 7 noisy buckets to a single `Virtual Machines` subcategory. (terraform-provider-raff v0.1.5)

**Catalog — CLI / Terraform**

* 🟣 **Fixed** — `category` filter on `raff template list` (CLI v0.3.7) and `data.raff_templates` (terraform-provider-raff v0.1.10) — flag help, schema description, and README/Registry examples all incorrectly claimed values like `linux` / `windows`. The real enum is `os` (Linux/Windows OS templates) or `marketplace` (pre-baked apps); OS family (`linux` / `windows` / `alpine` / etc.) lives on the `os_type` response field with no API-level filter today.

**Virtual Machines — Terraform**

* 🟣 **Fixed** — `raff_vm` Create now waits for the VM to reach `active` before returning. Previously `terraform apply` returned as soon as the API accepted the request, so `public_ipv4` / `private_ipv4` were empty until the customer ran `terraform refresh`. Default timeout 15 minutes; override with `timeouts { create = "20m" }`. (terraform-provider-raff v0.1.11)
* 🔵 **Updated** — `volume_action` description on `raff_vm` rewritten to clarify it only governs volumes **not** under Terraform management (attached out-of-band via dashboard / CLI). Volumes managed by `raff_volume` in the same config are destroyed by Terraform independently. (terraform-provider-raff v0.1.11)

***

**Compute — CLI**

* 🟢 **Added** — `raff volume list|get|create|delete|resize|attach|detach` — documentation page for block storage volume commands.
* 🟢 **Added** — `raff snapshot list|get|create|rename|restore|delete` — documentation page for VM and volume snapshots.
* 🟢 **Added** — `raff backup list|get|create|restore|delete` and `raff backup schedule list|get|create|update|delete` — documentation page for backups and recurring schedules.

**Networking — Terraform**

* 🟢 **Added** — `raff_vpc` documentation page — VPC resource, CIDR immutability, gateway computed attrs.
* 🟢 **Added** — `raff_ip` documentation page — floating IP reservation.
* 🟢 **Added** — `raff_security_group` documentation page — firewall rulesets with nested `rule` blocks and template seeding.

**Compute — Terraform**

* 🟢 **Added** — `raff_volume`, `raff_snapshot`, `raff_backup`, `raff_backup_schedule` documentation pages — covering immutability rules, retention semantics, and the "don't manage schedule-created backups" guidance.

**Team & Access — CLI**

* 🟢 **Added** — `raff ssh-key`, `raff api-key`, `raff member`, `raff role`, `raff permission`, `raff invitation` documentation pages — full coverage of IAM commands.
* 🟢 **Added** — `raff project member` subcommands documented under `raff project` — list, get, add, update, remove.

**Team & Access — Terraform**

* 🟢 **Added** — `raff_ssh_key`, `raff_api_key`, `raff_role`, `raff_member`, `raff_project_member` documentation pages — including the `secret` returned-once warning on `raff_api_key` and the composite ID format on `raff_project_member`.

**Catalog — CLI / Terraform**

* 🟢 **Added** — `raff region`, `raff template`, `raff pricing` (CLI) and a consolidated `data-sources` page (Terraform) covering `raff_regions`, `raff_templates`, and the `*_pricing` family.

**Reference — site**

* 🔵 **Updated** — Reference tab CLI and Terraform groups in `docs.json` reorganized to expose every command group and resource in the sidebar.
* 🔵 **Updated** — `reference/cli/introduction.mdx` and `reference/terraform/introduction.mdx` refreshed with the full surface — coverage table now lists every resource group instead of the original 5–7.

### May 8, 2026

**Volumes — API**

* 🟢 **Added** — **Volume CRUD + attach/detach** — `GET/POST /api/v1/volumes`, `GET/DELETE /api/v1/volumes/{id}`, `POST /api/v1/volumes/{id}/attach`, `POST /api/v1/volumes/{id}/detach`. Create is async (202 Accepted).
* 🔴 **Removed** — `vm_id`, `vm_internal_id`, `image_id`, `attached_volume_id` fields from volume responses (OpenNebula internal identifiers). Use `id` and `product_vm` instead.

**Snapshots — API**

* 🟢 **Added** — **Snapshot CRUD + restore + rename** — `GET/POST /api/v1/snapshots`, `GET/DELETE /api/v1/snapshots/{id}`, `POST /api/v1/snapshots/{id}/restore`, `PATCH /api/v1/snapshots/{id}/rename`. Supports VM and volume sources (`resource_type: vm|volume`). `Snapshot.status = active` indicates the source has been reverted to this snapshot.

**Backups — API**

* 🟢 **Added** — **Backup CRUD + restore** — `GET/POST /api/v1/backups`, `GET/DELETE /api/v1/backups/{id}`, `POST /api/v1/backups/{id}/restore`. Create and restore are async (202 Accepted).
* 🟢 **Added** — **Backup schedules** — `GET/POST /api/v1/backup-schedules`, `GET/PATCH/DELETE /api/v1/backup-schedules/{id}`. Daily or weekly with configurable retention.
* 🔴 **Removed** — `schedule_id`, `backup_id`, `vm_id` from backup/schedule responses (OpenNebula internal identifiers). Use `id` and `product_vm`.

**SSH Keys — API**

* 🟢 **Added** — **SSH key CRUD** — `GET/POST /api/v1/ssh-keys`, `GET/PUT/DELETE /api/v1/ssh-keys/{id}`. Account-scoped (no `X-Project-ID` required).

**Team & Access — API**

* 🟢 **Added** — **Account Members** — `GET/POST /api/v1/members`, `GET/PATCH/DELETE /api/v1/members/{id}`. Email invite, direct add, or attach an API key as member.
* 🟢 **Added** — **Project Members** — `GET/POST /api/v1/projects/{id}/members`, `GET/PATCH/DELETE /api/v1/projects/{id}/members/{member_id}`.
* 🟢 **Added** — **Roles** — `GET/POST /api/v1/roles`, `GET/PATCH/DELETE /api/v1/roles/{id}`. Custom account- or project-scoped roles. System roles are read-only.
* 🟢 **Added** — **Permissions catalog** — `GET /api/v1/permissions`. Lists every permission string usable in role definitions. Requires a valid API key (no specific permission needed).
* 🟢 **Added** — **API Keys** — `GET/POST /api/v1/api-keys`, `GET/PATCH/DELETE /api/v1/api-keys/{id}`, `POST /api/v1/api-keys/{id}/regenerate`. Full secret only returned once at create or regenerate.
* 🟢 **Added** — **Invitations** — `POST /api/v1/invitations` (account), `POST /api/v1/projects/{id}/invitations` (project), `DELETE /api/v1/invitations/{id}` (cancel). Public spec deliberately omits `Invitation.token` since it's the acceptance secret.

**Cross-cutting — wire/spec alignment**

* 🔴 **Removed** — `vm_id` from VM responses, `vnet_id` / `vxlan_vni` / `router_vm_id` from VPC responses, `ip_group_id` / `subnet_id` / `vm_id` from floating IP responses, `network_id` / `mac` / `bridge` / `vxlan_vni` from VM network interface responses, and the legacy top-level `project_id` / `project_name` from API key responses. All are OpenNebula internal identifiers that the public spec already hid; the gateway response now matches the spec.

### April 30, 2026

**Virtual Machines — API**

* 🟢 **Added** — `skip_public_ip` and `skip_vpc` flags on **Create VM** — `POST /api/v1/vms`. Build VPC-only VMs (no public IP) or public-IP-only VMs (no VPC). Cannot be combined.

**Networking — API**

* 🟢 **Added** — **Floating IP reserve/release** — `POST /api/v1/ips/reserve`, `DELETE /api/v1/ips/{id}/reserve`, plus `GET /api/v1/ips`, `GET /api/v1/ips/{id}`, `POST /api/v1/ips/{id}/change`. Reserve runs through the same balance/billing checks as VM create (402 / 403). Release refunds remaining time pro-rata for subscription IPs.
* 🟢 **Added** — **VPC CRUD** — `POST/GET/PUT/DELETE /api/v1/vpcs[/{id}]` and `GET /api/v1/vpcs/cidr-suggestions`. Customers can now create and manage VPCs directly via the public API instead of only through VM creation.
* 🟢 **Added** — `?type=public|vpc|ipv6` query filter on **List VM network interfaces** — `GET /api/v1/vms/{id}/networks?type=public`.
* 🔵 **Updated** — `VMNetwork.type` enum now includes `ipv6`.
* 🔴 **Removed** — `mac` field from public `VMNetwork` schema (still in raw response for the dashboard, hidden from public API consumers).

**Networking — CLI**

* 🟢 **Added** — `raff ip list|get|reserve|release|change`
* 🟢 **Added** — `raff vpc list|get|create|update|delete|cidr-suggestions`
* 🟢 **Added** — `raff vm networks <vm-id> --type public|vpc|ipv6` filter

**Virtual Machines — API**

* 🟢 **Added** — **Update VM note** — `PATCH /api/v1/vms/{id}/notes/{type}` — replaces existing note content; returns 404 if no note exists yet (use `PUT` to create).
* 🟢 **Added** — **Append to VM note** — `POST /api/v1/vms/{id}/notes/{type}/append` — concatenates new content onto the existing note (newline-separated), creates the note if missing.
* 🟢 **Added** — `type` query filter on **Get VM notes** — `GET /api/v1/vms/{id}/notes?type=personal|account` to fetch only one scope.

**Virtual Machines — CLI**

* 🟢 **Added** — `raff vm notes update <vm-id> --type X --content Y` (errors if note missing)
* 🟢 **Added** — `raff vm notes append <vm-id> --type X --content Y`
* 🟢 **Added** — `raff vm notes get <vm-id> --type personal|account` filter
* 🟢 **Added** — `raff vm tags list <vm-id>` to discover tag IDs

### April 29, 2026

**Virtual Machines — API**

* 🟢 **Added** — **Hard reboot VM** for unresponsive instances — `POST /api/v1/vms/{id}/reboot-hard`
* 🟢 **Added** — **Save VM disk as custom image** — `POST /api/v1/vms/{id}/save-image`
* 🟢 **Added** — **List VM network interfaces** — `GET /api/v1/vms/{id}/networks`
* 🟢 **Added** — **Attach/detach VM to/from VPC** — `POST/DELETE /api/v1/vms/{id}/vpc[/{nic_id}]`
* 🟢 **Added** — **Attach/detach floating IP** — `POST/DELETE /api/v1/vms/{id}/ip[/{nic_id}]`
* 🟢 **Added** — **Attach/detach security group to VM NIC** — `POST/DELETE /api/v1/vms/{id}/firewall[/{sg_id}/{nic_id}]`
* 🟢 **Added** — **Add/update/remove VM tags** — `POST/PATCH/DELETE /api/v1/vms/{id}/tags[/{tagId}]`
* 🟢 **Added** — **Get/upsert VM notes** (personal + account scopes) — `GET /api/v1/vms/{id}/notes`, `PUT /api/v1/vms/{id}/notes/{type}`
* 🔴 **Removed** — `vm_id` field from VM responses (was an OpenNebula internal identifier — use `id` instead)
* 🔵 **Updated** — `BillingError.reason` enum trimmed to currently-returned values: `banned`, `failed`, `no_billing_customer`. Insufficient balance now consistently returns `402` with a plain `Error` body.

**Virtual Machines — CLI**

* 🟢 **Added** — `raff vm hard-reboot`, `raff vm save-image`, `raff vm networks`, `raff vm vpc attach|detach`, `raff vm ip attach|detach`, `raff vm sg attach|detach`, `raff vm tags add|update|remove`, `raff vm notes get|set`

**Virtual Machines — Terraform**

* 🔴 **Removed** — `vm_id` computed attribute from `raff_vm` (was the OpenNebula int ID; use `id` instead)

### March 25, 2026

**General**

* 🟢 **Added** — Changelog tracking started

### March 15, 2026

**Virtual Machines — API**

* 🟢 **Added** — **Resize VM disk storage** without recreating — `POST /api/v1/vms/{id}/disk/resize`
* 🟢 **Added** — **Bulk delete VMs** in a single request — `DELETE /api/v1/vms/bulk`
* 🔵 **Updated** — **Create VM** now accepts `enable_ipv6` parameter for IPv6 support — `POST /api/v1/vms`

### March 10, 2026

**Virtual Machines — API**

* 🟢 **Added** — **Reinstall OS** on a running VM, keep your IP — `POST /api/v1/vms/{id}/reinstall`
* 🟢 **Added** — **Factory reset** VM to original state — `POST /api/v1/vms/{id}/factory-reset`
* 🟢 **Added** — **Reset root password** via API — `POST /api/v1/vms/{id}/reset-password`
* 🟢 **Added** — **Rename VMs** after creation — `POST /api/v1/vms/{id}/rename`

### March 5, 2026

**Volumes — API**

* 🟢 **Added** — **Resize block storage volumes** attached to VMs — `PATCH /api/v1/volumes/{id}`

### March 3, 2026

**Projects — API**

* 🟢 **Added** — **Organize resources into projects** — full CRUD via API
  * `GET /api/v1/projects` · `POST /api/v1/projects` · `GET /api/v1/projects/{id}` · `PUT /api/v1/projects/{id}` · `DELETE /api/v1/projects/{id}`

### March 1, 2026

**Virtual Machines — API**

* 🟢 **Added** — **Full VM lifecycle** — create, list, get details, delete
  * `GET /api/v1/vms` · `POST /api/v1/vms` · `GET /api/v1/vms/{id}` · `DELETE /api/v1/vms/{id}`
* 🟢 **Added** — **VM power control** — start, stop, reboot
  * `POST /api/v1/vms/{id}/start` · `POST /api/v1/vms/{id}/stop` · `POST /api/v1/vms/{id}/reboot`
* 🟢 **Added** — **Scale resources** — resize CPU and RAM on demand — `POST /api/v1/vms/{id}/resize`

**Catalog — API**

* 🟢 **Added** — **Browse available resources** — regions, OS templates, pricing (no auth required)
  * `GET /api/v1/public/regions` · `GET /api/v1/public/templates`
  * `GET /api/v1/public/pricing/vm` · `/volume` · `/snapshot` · `/backup` · `/ip`
