Skip to main content
Updated May 8, 2026

Prerequisites

  • A Raff account (sign up)
  • An API key — see Generate an API key for the full dashboard create flow (Account Role, Project Role, expiration, and copy-once warning).
# Set these once for the rest of the quickstart
export RAFF_API_KEY="your_api_key_here"

Step 1: Check API Health

Verify the API is reachable (no authentication required):
curl https://api.rafftechnologies.com/health
{
  "status": "healthy"
}

Step 2: List Your VMs

Use your API key to list virtual machines on your account:
curl -H "X-API-Key: YOUR_API_KEY" \
  https://api.rafftechnologies.com/api/v1/vms
{
  "data": [],
  "total": 0
}

Step 3: Get a project ID

Mutating endpoints require an X-Project-ID header. List your projects and pick one:
curl -H "X-API-Key: $RAFF_API_KEY" \
  https://api.rafftechnologies.com/api/v1/projects
{
  "data": [
    {
      "id": "8c3e4d52-1a6b-4f1e-9a47-2f8a3b9c1d20",
      "name": "default",
      "slug": "default",
      "description": "Default project",
      "default_region": "us-east",
      "is_default": true
    }
  ]
}
export RAFF_PROJECT_ID="8c3e4d52-1a6b-4f1e-9a47-2f8a3b9c1d20"

Step 4: Browse the catalog

The public catalog tells you what’s available before you create anything — regions, OS templates, and per-resource pricing. No auth required for any catalog endpoint.
EndpointWhat it returns
GET /api/v1/public/regionsActive data center regions
GET /api/v1/public/templatesOS templates and marketplace apps (filter with ?category=os or ?category=marketplace)
GET /api/v1/public/pricing/vmVM pricing plans (the pricing_id value used on Create VM)
GET /api/v1/public/pricing/volumeVolume storage pricing
GET /api/v1/public/pricing/snapshotSnapshot storage pricing
GET /api/v1/public/pricing/backupBackup storage pricing
GET /api/v1/public/pricing/ipFloating IP pricing
For this quickstart, grab an OS template:
curl https://api.rafftechnologies.com/api/v1/public/templates?category=os
{
  "data": [
    {
      "id": "5ac21891-32e6-41ce-8a93-b5d6ab708b0d",
      "name": "Ubuntu 24.04 LTS (x64)",
      "category": "os",
      "region": "us-east"
    }
  ]
}
And a VM pricing plan:
curl https://api.rafftechnologies.com/api/v1/public/pricing/vm
Pick a pricing_id from the response — pricing_id: 1 is the cheapest Premium plan.

Step 5: Create a VM

curl -X POST https://api.rafftechnologies.com/api/v1/vms \
  -H "X-API-Key: $RAFF_API_KEY" \
  -H "X-Project-ID: $RAFF_PROJECT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-first-vm",
    "template_id": "5ac21891-32e6-41ce-8a93-b5d6ab708b0d",
    "pricing_id": 1,
    "region": "us-east"
  }'

Step 6: Check VM Status

Once created, fetch your VM details:
curl -H "X-API-Key: $RAFF_API_KEY" \
  https://api.rafftechnologies.com/api/v1/vms/{vm-id}
The VM will transition through statuses: initiatingprovisioningbootingactive.

Step 7: Control Your VM

Start, stop, or reboot your VM:
# Stop a VM
curl -X POST -H "X-API-Key: $RAFF_API_KEY" -H "X-Project-ID: $RAFF_PROJECT_ID" \
  https://api.rafftechnologies.com/api/v1/vms/{vm-id}/stop

# Start a VM
curl -X POST -H "X-API-Key: $RAFF_API_KEY" -H "X-Project-ID: $RAFF_PROJECT_ID" \
  https://api.rafftechnologies.com/api/v1/vms/{vm-id}/start

# Reboot a VM
curl -X POST -H "X-API-Key: $RAFF_API_KEY" -H "X-Project-ID: $RAFF_PROJECT_ID" \
  https://api.rafftechnologies.com/api/v1/vms/{vm-id}/reboot

Finding resource IDs

Every resource — VM, snapshot, backup, volume, key — gets an id at create time, returned in the create response. If you didn’t save it, the only way to find it later is to list the resource and pick the one you want. The dashboard does this internally; you do the same over the API.
ResourceList endpointNotes
VMsGET /api/v1/vmsFilter ?project_id=<uuid> or ?status=active
VolumesGET /api/v1/volumesFilter ?vm_id=<uuid> for volumes attached to one VM
SnapshotsGET /api/v1/snapshotsFilter ?vm_id=<uuid>, ?volume_id=<int>, or ?type=vm|volume
BackupsGET /api/v1/backupsFilter ?vm_id=<uuid>
Backup schedulesGET /api/v1/backup-schedulesFilter ?vm_id=<uuid>
SSH keysGET /api/v1/ssh-keysAccount-scoped, no filters
ProjectsGET /api/v1/projectsAccount-scoped
VPCsGET /api/v1/vpcsFilter ?region=us-east
Floating IPsGET /api/v1/ipsFilter ?status=available|reserved|attached
Security groupsGET /api/v1/security-groups
All list endpoints support limit (default 20–50) and offset for pagination. Pass X-Project-ID to scope to a single project where applicable.

Same flow in Python / Node.js / Go

Raff doesn’t ship a first-party SDK today — the API is plain REST + JSON, so any HTTP client works. Examples of the same Step 5 (create VM) below.
import os, requests

api_key = os.environ["RAFF_API_KEY"]
project_id = os.environ["RAFF_PROJECT_ID"]

resp = requests.post(
    "https://api.rafftechnologies.com/api/v1/vms",
    headers={
        "X-API-Key": api_key,
        "X-Project-ID": project_id,
        "Content-Type": "application/json",
    },
    json={
        "name": "my-first-vm",
        "template_id": "5ac21891-32e6-41ce-8a93-b5d6ab708b0d",
        "pricing_id": 1,
        "region": "us-east",
    },
    timeout=30,
)

if resp.status_code >= 400:
    raise RuntimeError(f"Create failed [{resp.status_code}]: {resp.text}")

print(resp.json()["data"]["id"])

Errors you’ll hit early

Every error response is JSON with an error (short label) and a message (human-readable detail). The HTTP statuses you’ll see most:
HTTP statusWhat it meansWhat to do
400Bad requestInspect message — usually a field validation issue (bad CIDR, password too short, missing pricing_id) or a missing X-Project-ID header on a mutating endpoint. Fix the payload and retry
401UnauthorizedThe X-API-Key is missing, malformed, expired, or revoked. Generate a new key in the dashboard
402Payment RequiredAccount balance is too low to provision. Top up and retry
403Billing validation failedAccount is banned, has a failed last payment, or has no_billing_customer. Check message.reason and resolve in the dashboard
404Not foundThe VM/project/resource ID isn’t reachable from this key. Double-check IDs and X-Project-ID
409ConflictResource state mismatch (e.g. resizing a VM that isn’t passive). Read message and adjust
429Rate limitedToo many requests — back off. Default tier is 30 RPS / burst 60 per API key; honor the Retry-After header. See Authentication for tier detail and how to upgrade
5xxServer errorRetry with exponential backoff. If it persists, support@rafftechnologies.com
A simple retry helper for 5xx and 429:
import time, requests

def call_with_retry(method, url, **kwargs):
    for attempt in range(5):
        resp = requests.request(method, url, timeout=30, **kwargs)
        if resp.status_code < 500 and resp.status_code != 429:
            return resp
        time.sleep(2 ** attempt)  # 1s, 2s, 4s, 8s, 16s
    resp.raise_for_status()
    return resp

Next Steps

Authentication

Learn about API key authentication and rate limits.

Create Your First VM

Step-by-step guide with VPC networking and SSH setup.
Last modified on May 8, 2026