curl --request POST \
--url https://api.rafftechnologies.com/api/v1/vms/{id}/ip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Project-ID: <x-project-id>' \
--data '
{
"ip_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"security_groups": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
]
}
'import requests
url = "https://api.rafftechnologies.com/api/v1/vms/{id}/ip"
payload = {
"ip_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"security_groups": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"]
}
headers = {
"X-Project-ID": "<x-project-id>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Project-ID': '<x-project-id>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
ip_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
security_groups: ['3c90c3cc-0d44-4b50-8888-8dd25736052a']
})
};
fetch('https://api.rafftechnologies.com/api/v1/vms/{id}/ip', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rafftechnologies.com/api/v1/vms/{id}/ip",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ip_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'security_groups' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Project-ID: <x-project-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.rafftechnologies.com/api/v1/vms/{id}/ip"
payload := strings.NewReader("{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Project-ID", "<x-project-id>")
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rafftechnologies.com/api/v1/vms/{id}/ip")
.header("X-Project-ID", "<x-project-id>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rafftechnologies.com/api/v1/vms/{id}/ip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Project-ID"] = '<x-project-id>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"data": {
"vm_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ip_address": "<string>",
"nic_id": 123,
"mac": "<string>"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "Payment Required",
"message": "Insufficient balance for subscription"
}{
"error": "Billing validation failed",
"reason": "banned",
"message": "Payment failed. Please update your payment method."
}{
"error": "<string>",
"message": "<string>"
}Attach floating IP to VM
Attach a floating public IP to a virtual machine. Pick one of two modes:
Option A — attach a reserved IP (use ip_id)
Pass ip_id set to a previously reserved IP (from POST /api/v1/ips/reserve or GET /api/v1/ips?reserved=true). The IP must:
- belong to the same account
- not be currently attached to another VM
- have
reserved: true
No new billing on attach — you’re already paying for the reserved IP.
A VM can hold up to 4 public IPv4 addresses. The first IPv4 on a VM becomes its primary address; additional IPv4s must be reserved IPs attached with ip_id.
Option B — auto-assign a new IP (use type)
Leave ip_id empty and pass type to allocate a fresh IP from the pool:
type: IPv4(default if omitted)type: IPv6
Auto-assign is available only while the VM has no public IP of that family, and the IP is included with the VM at no extra charge. It is not reserved: detaching releases it back to the shared pool.
Notes
- Auto-assign (
type) fails if the VM already has a public IP of the same family — attach a reserved IP (ip_id) to add more IPv4s, up to 4 total. - Optionally pass
security_groups(UUID array) to apply security groups to the new NIC.
curl --request POST \
--url https://api.rafftechnologies.com/api/v1/vms/{id}/ip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--header 'X-Project-ID: <x-project-id>' \
--data '
{
"ip_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"security_groups": [
"3c90c3cc-0d44-4b50-8888-8dd25736052a"
]
}
'import requests
url = "https://api.rafftechnologies.com/api/v1/vms/{id}/ip"
payload = {
"ip_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"security_groups": ["3c90c3cc-0d44-4b50-8888-8dd25736052a"]
}
headers = {
"X-Project-ID": "<x-project-id>",
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Project-ID': '<x-project-id>',
'X-API-Key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
ip_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
security_groups: ['3c90c3cc-0d44-4b50-8888-8dd25736052a']
})
};
fetch('https://api.rafftechnologies.com/api/v1/vms/{id}/ip', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rafftechnologies.com/api/v1/vms/{id}/ip",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'ip_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'security_groups' => [
'3c90c3cc-0d44-4b50-8888-8dd25736052a'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>",
"X-Project-ID: <x-project-id>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.rafftechnologies.com/api/v1/vms/{id}/ip"
payload := strings.NewReader("{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Project-ID", "<x-project-id>")
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rafftechnologies.com/api/v1/vms/{id}/ip")
.header("X-Project-ID", "<x-project-id>")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rafftechnologies.com/api/v1/vms/{id}/ip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Project-ID"] = '<x-project-id>'
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"ip_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"security_groups\": [\n \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"message": "<string>",
"data": {
"vm_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ip_address": "<string>",
"nic_id": 123,
"mac": "<string>"
}
}{
"error": "<string>",
"message": "<string>"
}{
"error": "<string>",
"message": "<string>"
}{
"error": "Payment Required",
"message": "Insufficient balance for subscription"
}{
"error": "Billing validation failed",
"reason": "banned",
"message": "Payment failed. Please update your payment method."
}{
"error": "<string>",
"message": "<string>"
}Authorizations
API key for authentication. Each key is bound to a specific account.
Headers
Project ID. Required for all mutating operations (create, delete, power actions, resize).
Path Parameters
VM ID (UUID)
Body
Provide either ip_id (attach an existing reserved IP) or type (auto-allocate a new IP). Don't combine — ip_id takes precedence and type is ignored when both are sent.
ID of a previously reserved IP. The IP must belong to the same account, be reserved, and not already attached to another VM. No new billing on attach — you're already paying for the reserved IP. Use this to add up to 4 public IPv4 addresses to a VM.
IP family to auto-allocate. Used only when ip_id is omitted. Defaults to IPv4. Available only while the VM has no public IP of that family; the IP is included with the VM at no extra charge and is released back to the pool on detach.
IPv4, IPv6 Security group IDs (UUIDs) to apply to the new NIC.