curl --request POST \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"size": "l",
"memory_limit_gib": 48
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize"
payload = {
"size": "l",
"memory_limit_gib": 48
}
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({size: 'l', memory_limit_gib: 48})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize', 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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize",
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([
'size' => 'l',
'memory_limit_gib' => 48
]),
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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize"
payload := strings.NewReader("{\n \"size\": \"l\",\n \"memory_limit_gib\": 48\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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"size\": \"l\",\n \"memory_limit_gib\": 48\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize")
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 \"size\": \"l\",\n \"memory_limit_gib\": 48\n}"
response = http.request(request)
puts response.read_body{
"sailbox_id": "<string>",
"status": "<string>",
"applied": true,
"restarted": true,
"size": "<string>",
"vcpu_count": 123,
"memory_mib": 123,
"state_disk_size_gib": 123,
"memory_in_use_mib": 123
}{
"error": {
"message": "memory_limit_gib 96 is above the 64 GiB maximum for size s",
"type": "invalid_request_error",
"param": "memory_limit_gib",
"code": "invalid_argument"
}
}{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key"
}
}{
"error": {
"message": "Your API key has been disabled due to insufficient credits. Visit https://app.sailresearch.com/billing to add credits.",
"type": "billing_error",
"param": null,
"code": "credits_exhausted",
"billing_url": "https://app.sailresearch.com/billing"
}
}{
"error": {
"message": "sailboxes require an organization-scoped API key",
"type": "permission_error",
"param": null,
"code": null
}
}{
"error": {
"message": "sailbox \"sb_9c8f1e2a-3b4d-4f5a-8c7e-1d2f3a4b5c6d\" not found",
"type": "not_found_error",
"param": null,
"code": null
}
}{
"error": {
"message": "the Sailbox is using 140 GiB of memory and needs 141 GiB to keep running, above the 128 GiB maximum for the requested size; free memory first",
"type": "conflict_error",
"param": null,
"code": "failed_precondition"
}
}{
"error": {
"message": "request body too large",
"type": "invalid_request_error",
"param": null,
"code": null
}
}{
"error": {
"message": "Too many concurrent requests. Please retry after some of your organization's in-flight requests complete.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limited"
}
}{
"error": {
"message": "failed to fetch sailbox",
"type": "server_error",
"param": null,
"code": null
}
}{
"error": {
"message": "Authentication service unavailable",
"type": "server_error",
"param": null,
"code": null
}
}{
"error": {
"message": "idempotent request still in flight",
"type": "server_error",
"param": null,
"code": null
}
}Resize a Sailbox
Changes the Sailbox’s size or its memory and disk limits. Every field is optional, but at least one must be set; a field left out keeps its value.
A running Sailbox takes the change in place: memory moves both ways (a lowering stops one GiB above what is in use, and the response’s memory_mib is the limit that took effect), disk only grows, and a size change brings CPUs online or takes them offline. A Sailbox whose resize_restarts field is true restarts once on its first size increase, and the response then has restarted: true. A paused or sleeping Sailbox is not woken: the new shape is recorded, takes effect at its next wake, and the response has applied: false.
Limits are ceilings, not reservations: Sailboxes bill for what they use. The full rules, including what is refused and why, are in the resize guide.
curl --request POST \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"size": "l",
"memory_limit_gib": 48
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize"
payload = {
"size": "l",
"memory_limit_gib": 48
}
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({size: 'l', memory_limit_gib: 48})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize', 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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize",
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([
'size' => 'l',
'memory_limit_gib' => 48
]),
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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize"
payload := strings.NewReader("{\n \"size\": \"l\",\n \"memory_limit_gib\": 48\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://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"size\": \"l\",\n \"memory_limit_gib\": 48\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/resize")
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 \"size\": \"l\",\n \"memory_limit_gib\": 48\n}"
response = http.request(request)
puts response.read_body{
"sailbox_id": "<string>",
"status": "<string>",
"applied": true,
"restarted": true,
"size": "<string>",
"vcpu_count": 123,
"memory_mib": 123,
"state_disk_size_gib": 123,
"memory_in_use_mib": 123
}{
"error": {
"message": "memory_limit_gib 96 is above the 64 GiB maximum for size s",
"type": "invalid_request_error",
"param": "memory_limit_gib",
"code": "invalid_argument"
}
}{
"error": {
"message": "Invalid API key",
"type": "authentication_error",
"param": null,
"code": "invalid_api_key"
}
}{
"error": {
"message": "Your API key has been disabled due to insufficient credits. Visit https://app.sailresearch.com/billing to add credits.",
"type": "billing_error",
"param": null,
"code": "credits_exhausted",
"billing_url": "https://app.sailresearch.com/billing"
}
}{
"error": {
"message": "sailboxes require an organization-scoped API key",
"type": "permission_error",
"param": null,
"code": null
}
}{
"error": {
"message": "sailbox \"sb_9c8f1e2a-3b4d-4f5a-8c7e-1d2f3a4b5c6d\" not found",
"type": "not_found_error",
"param": null,
"code": null
}
}{
"error": {
"message": "the Sailbox is using 140 GiB of memory and needs 141 GiB to keep running, above the 128 GiB maximum for the requested size; free memory first",
"type": "conflict_error",
"param": null,
"code": "failed_precondition"
}
}{
"error": {
"message": "request body too large",
"type": "invalid_request_error",
"param": null,
"code": null
}
}{
"error": {
"message": "Too many concurrent requests. Please retry after some of your organization's in-flight requests complete.",
"type": "rate_limit_error",
"param": null,
"code": "rate_limited"
}
}{
"error": {
"message": "failed to fetch sailbox",
"type": "server_error",
"param": null,
"code": null
}
}{
"error": {
"message": "Authentication service unavailable",
"type": "server_error",
"param": null,
"code": null
}
}{
"error": {
"message": "idempotent request still in flight",
"type": "server_error",
"param": null,
"code": null
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
Makes the request retry-safe. Sail remembers the answer it sent under a key, including a 400 or a 409, and replays it with Idempotent-Replayed: true for a retry that repeats the key, the method, the path, and the body. Bodies are compared byte for byte. Reusing a key for a different request returns 409, so send a corrected request under a new key. A key that is blank or only spaces is ignored, and the request runs without idempotency.
Any string of up to 255 bytes works, and characters outside ASCII count for more than one. A UUID is a good default. Keys are remembered for at least 24 hours and scoped to the API key that sent them.
A server error, or a failure to record the answer, can leave a key unsettled, and creating a Sailbox is where that matters. See Retrying safely.
255Lets an organization admin operate a private Sailbox someone else created. Say why in plain text; the reason goes into your organization's audit log, and the operation is refused without it. Ignored on Sailboxes you could already operate.
Pause, resume, sleep, scheduled wake, upgrade, reboot, resize, and terminate accept an override, and so does deleting a checkpoint taken from the Sailbox. Setting an egress policy accepts one too. Running commands and moving files accept one through an SDK or the CLI. Publishing and unpublishing ports, adding and removing custom domains, checkpointing, and creating from a checkpoint stay with the creator.
^[ -~]*$Path Parameters
Id of the Sailbox, as returned by create. It is sb_ followed by a UUID.
Body
Every field is optional, but at least one must be set. A field left out (or null) keeps its current value, and a value equal to the current one is accepted and changes nothing. A field set to 0 or to an empty string is rejected.
The new size. Limits outside the new size's range are clamped into it. A smaller size is refused while the Sailbox uses more memory than that size allows, or while its disk limit is above that size's maximum.
s, m, l The new memory limit in whole GiB, within the size's range. Lowering it needs a running Sailbox. The limit cannot come within a GiB of what the Sailbox is using: it settles one GiB above that amount, rounded up to a whole GiB, when that is higher; the response reports the limit that took effect.
x >= 1The new disk limit in GiB, within the size's range. A disk only grows: a value below the current limit is refused.
x >= 1Response
The Sailbox's shape after the call.
Id of the Sailbox.
Current state of the Sailbox. Values in use today are creating, running, paused, sleeping, terminating, terminated, failed, create_failed, interrupted_restorable, and interrupted_unsafe_to_retry. New values can appear over time, so treat this as an open set.
true when the Sailbox has the new shape now. false when it was powered off: the shape is recorded and takes effect at the next wake. Also false when a restart the change needed could not complete; the Sailbox is then paused with the new shape recorded.
true when the change restarted the Sailbox. Files on its disk were kept; running processes and memory were not.
The size the Sailbox is now set to: s, m, or l. Empty when its vCPU count does not match a size, as for a Sailbox created with a raw cpu count whose resize changed only a limit.
Virtual CPUs the Sailbox has now.
The memory limit in MiB that took effect. On a lowering this can be above what you asked for, because the limit lands one GiB above what the Sailbox is using.
The disk limit in GiB now.
Memory the Sailbox was using when its memory limit was lowered while running, in MiB; the lowered limit lands one GiB above it. null for any other change.