curl --request POST \
--url https://compute.{region}.basaltic.sh/v1/images \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "debian-13",
"source_url": "https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...",
"description": "Debian 13 (Trixie)",
"os": "debian",
"os_version": "13",
"architecture": "amd64",
"version": "20260807",
"current": true,
"eol_date": "2026-08-31",
"min_disk_gb": 10,
"min_ram_mb": 1024,
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
'import requests
url = "https://compute.{region}.basaltic.sh/v1/images"
payload = {
"name": "debian-13",
"source_url": "https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...",
"description": "Debian 13 (Trixie)",
"os": "debian",
"os_version": "13",
"architecture": "amd64",
"version": "20260807",
"current": True,
"eol_date": "2026-08-31",
"min_disk_gb": 10,
"min_ram_mb": 1024,
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'debian-13',
source_url: 'https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...',
description: 'Debian 13 (Trixie)',
os: 'debian',
os_version: '13',
architecture: 'amd64',
version: '20260807',
current: true,
eol_date: '2026-08-31',
min_disk_gb: 10,
min_ram_mb: 1024,
tags: {environment: 'production', team: 'backend'},
attributes: {}
})
};
fetch('https://compute.{region}.basaltic.sh/v1/images', 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://compute.{region}.basaltic.sh/v1/images",
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([
'name' => 'debian-13',
'source_url' => 'https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...',
'description' => 'Debian 13 (Trixie)',
'os' => 'debian',
'os_version' => '13',
'architecture' => 'amd64',
'version' => '20260807',
'current' => true,
'eol_date' => '2026-08-31',
'min_disk_gb' => 10,
'min_ram_mb' => 1024,
'tags' => [
'environment' => 'production',
'team' => 'backend'
],
'attributes' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://compute.{region}.basaltic.sh/v1/images"
payload := strings.NewReader("{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://compute.{region}.basaltic.sh/v1/images")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://compute.{region}.basaltic.sh/v1/images")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}"
response = http.request(request)
puts response.read_body{
"image": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"crn": "crn:compute:sa-saopaulo-1:my-account:image/ubuntu-24.04/architecture/amd64/version/20260901",
"name": "ubuntu-24.04",
"architecture": "amd64",
"version": "20260807",
"status": "active",
"faults": [
{
"code": "BACKUP_FAILED",
"severity": "error",
"message": "Backup upload failed.",
"details": {},
"first_at": "2023-11-07T05:31:56Z",
"last_at": "2023-11-07T05:31:56Z",
"occurrences": 1
}
],
"created_at": "2026-01-15T09:30:00Z",
"updated_at": "2026-01-15T09:30:00Z",
"description": "Ubuntu 24.04 LTS (Noble Numbat)",
"os": "ubuntu",
"os_version": "24.04",
"is_current": true,
"eol_date": "2026-08-31",
"size_bytes": 2361393152,
"min_disk_gb": 10,
"min_ram_mb": 1024,
"withdrawal_reason": "end_of_life",
"deletion_retention": {
"reason": "in_use",
"instances": 1,
"instance_pools": 1
},
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "CONFLICT",
"message": "Resource with this name already exists",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "IDEMPOTENCY_KEY_REUSED",
"message": "This Idempotency-Key was already used with a different request payload",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Import an image from an object URL
Creating an image in the platform account requires a principal acting in
that account with compute:CreateImage.
Registers an image for import from a presigned object URL — no image
bytes flow through this API. Upload your disk to any bucket you control
(our object store, AWS S3, MinIO, …) using a robust multipart S3 client,
then pass a presigned GET URL as source_url.
The import runs in the background: the response is 202 with status=importing, and a worker fetches the URL, converts it to the raw base (qcow2 / raw / vmdk / vhd / vhdx / vdi are accepted), and imports it into regional storage. The row flips to active (or error, with active faults) once it finishes — poll GET /v1/images/ for the status.
A name behaves like a movable tag: by default the new image becomes the
“current” version for its (name, architecture), so future launches of
that name boot the new bits. Older versions stay bootable by id and by
name:version. Pass current: false to stage a version without
switching, then promote it later with PATCH /v1/images/
(current=true).
version identifies the build within the name and must be unique there;
omit it and the server stamps a UTC timestamp. Publishing twice under one
name with the same version is a 409, not a second anonymous build.
curl --request POST \
--url https://compute.{region}.basaltic.sh/v1/images \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "debian-13",
"source_url": "https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...",
"description": "Debian 13 (Trixie)",
"os": "debian",
"os_version": "13",
"architecture": "amd64",
"version": "20260807",
"current": true,
"eol_date": "2026-08-31",
"min_disk_gb": 10,
"min_ram_mb": 1024,
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
'import requests
url = "https://compute.{region}.basaltic.sh/v1/images"
payload = {
"name": "debian-13",
"source_url": "https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...",
"description": "Debian 13 (Trixie)",
"os": "debian",
"os_version": "13",
"architecture": "amd64",
"version": "20260807",
"current": True,
"eol_date": "2026-08-31",
"min_disk_gb": 10,
"min_ram_mb": 1024,
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
name: 'debian-13',
source_url: 'https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...',
description: 'Debian 13 (Trixie)',
os: 'debian',
os_version: '13',
architecture: 'amd64',
version: '20260807',
current: true,
eol_date: '2026-08-31',
min_disk_gb: 10,
min_ram_mb: 1024,
tags: {environment: 'production', team: 'backend'},
attributes: {}
})
};
fetch('https://compute.{region}.basaltic.sh/v1/images', 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://compute.{region}.basaltic.sh/v1/images",
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([
'name' => 'debian-13',
'source_url' => 'https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...',
'description' => 'Debian 13 (Trixie)',
'os' => 'debian',
'os_version' => '13',
'architecture' => 'amd64',
'version' => '20260807',
'current' => true,
'eol_date' => '2026-08-31',
'min_disk_gb' => 10,
'min_ram_mb' => 1024,
'tags' => [
'environment' => 'production',
'team' => 'backend'
],
'attributes' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$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://compute.{region}.basaltic.sh/v1/images"
payload := strings.NewReader("{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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://compute.{region}.basaltic.sh/v1/images")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://compute.{region}.basaltic.sh/v1/images")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"name\": \"debian-13\",\n \"source_url\": \"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=...\",\n \"description\": \"Debian 13 (Trixie)\",\n \"os\": \"debian\",\n \"os_version\": \"13\",\n \"architecture\": \"amd64\",\n \"version\": \"20260807\",\n \"current\": true,\n \"eol_date\": \"2026-08-31\",\n \"min_disk_gb\": 10,\n \"min_ram_mb\": 1024,\n \"tags\": {\n \"environment\": \"production\",\n \"team\": \"backend\"\n },\n \"attributes\": {}\n}"
response = http.request(request)
puts response.read_body{
"image": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"crn": "crn:compute:sa-saopaulo-1:my-account:image/ubuntu-24.04/architecture/amd64/version/20260901",
"name": "ubuntu-24.04",
"architecture": "amd64",
"version": "20260807",
"status": "active",
"faults": [
{
"code": "BACKUP_FAILED",
"severity": "error",
"message": "Backup upload failed.",
"details": {},
"first_at": "2023-11-07T05:31:56Z",
"last_at": "2023-11-07T05:31:56Z",
"occurrences": 1
}
],
"created_at": "2026-01-15T09:30:00Z",
"updated_at": "2026-01-15T09:30:00Z",
"description": "Ubuntu 24.04 LTS (Noble Numbat)",
"os": "ubuntu",
"os_version": "24.04",
"is_current": true,
"eol_date": "2026-08-31",
"size_bytes": 2361393152,
"min_disk_gb": 10,
"min_ram_mb": 1024,
"withdrawal_reason": "end_of_life",
"deletion_retention": {
"reason": "in_use",
"instances": 1,
"instance_pools": 1
},
"tags": {
"environment": "production",
"team": "backend"
},
"attributes": {}
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "CONFLICT",
"message": "Resource with this name already exists",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "IDEMPOTENCY_KEY_REUSED",
"message": "This Idempotency-Key was already used with a different request payload",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}compute:CreateImage.
Creating an image in the platform account requires a principal acting in
that account with compute:CreateImage.
See COMPUTE permissions for policy examples.Authorizations
An OAuth 2.0 bearer token, sent as Authorization: Bearer <token>.
This is the recommended way to authenticate.
Get one by exchanging a service account's access key pair at
POST /v1/oauth/token with grant_type=client_credentials. It is the
standard client-credentials grant, so any OAuth-aware library will
obtain and refresh it for you.
curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
https://iam.basaltic.sh/v1/oauth/token
Tokens last an hour by default. The same access key pair is separately your AWS SigV4 credential for the S3-compatible object endpoint, which speaks nothing else.
Headers
Optional client-generated key that makes a create replay-safe. Retrying a request with the same key returns the original outcome verbatim instead of creating a duplicate resource. Reusing a key with a different request body is rejected (422); a request whose key is still being processed returns 409. Records are honored for 24 hours. Use a UUID or similarly unique token.
255Body
Immutable image name (e.g. debian-13) whose current-version pointer can move; the new image becomes its current version. Names are shared across a tag's builds — one build is identified by owner, name, architecture and version. Resource names must not start with the literal crn: prefix or be UUIDs (canonical, compact, braced, or urn:uuid: forms, in either case).
"debian-13"
Presigned https GET URL to the disk in an object store you control. Fetched once by the import worker (which rejects private/link-local targets). The worker detects qcow2, raw, vmdk, vhd, vhdx or vdi and converts it to raw storage. Unreadable or unsupported sources and images declaring backing files fail asynchronously with status error and an active conversion fault. Not retained after import.
"https://bucket.s3.example.com/debian-13.qcow2?X-Amz-Signature=..."
"Debian 13 (Trixie)"
Operating system distribution. Use linux for another or generic Linux distribution; os_version specifies the release separately.
almalinux, alpine, arch, centos, debian, fedora, opensuse, rhel, rocky, ubuntu, linux "debian"
"13"
CPU architecture of the source image. Only amd64 (x86-64) is supported.
amd64 "amd64"
Identifies this build within name, and must be unique there —
re-publishing a version that a tag already carries is a 409. Omit
it and the server stamps a UTC timestamp, so every build is
addressable as name:version whether or not you labelled it.
"20260807"
Make this the current version for its (name, architecture) once active.
true
The day this release stops receiving free security updates. Omit it and the image inherits the date the name's current version carries, so re-publishing a tag can't quietly stop tracking its release.
"2026-08-31"
0 <= x <= 1638410
x >= 01024
Show child attributes
Show child attributes
{
"environment": "production",
"team": "backend"
}
Show child attributes
Show child attributes
Response
Image registered for import
Show child attributes
Show child attributes

