curl --request POST \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"vcpu_count": 8,
"memory_limit_gib": 48
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits"
payload = {
"vcpu_count": 8,
"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({vcpu_count: 8, memory_limit_gib: 48})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits', 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}/set-limits",
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([
'vcpu_count' => 8,
'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}/set-limits"
payload := strings.NewReader("{\n \"vcpu_count\": 8,\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}/set-limits")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"vcpu_count\": 8,\n \"memory_limit_gib\": 48\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits")
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 \"vcpu_count\": 8,\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 4 is below the 16 GiB minimum for 8 vCPUs",
"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": "lower the memory limit while the Sailbox is running; Sail cannot see what a sleeping Sailbox is using",
"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
}
}Set a Sailbox's limits
Set this Sailbox’s vCPU count, memory limit, or disk limit. Regardless of configured limits, you are only charged for the resources the Sailbox workload actually consumes at runtime. Limits are for finer grained control over a Sailbox’s allowable resource consumption, and most users keep the defaults of 8 vCPUs, a 256 GiB memory limit, and a 1024 GiB disk limit. 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 vCPU change brings CPUs online or takes them offline. A paused or sleeping Sailbox is not woken: the new limits are recorded, take effect at its next wake, and the response has applied: false.
The full rules, including what is refused and why, are in the set limits guide.
curl --request POST \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"vcpu_count": 8,
"memory_limit_gib": 48
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits"
payload = {
"vcpu_count": 8,
"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({vcpu_count: 8, memory_limit_gib: 48})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits', 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}/set-limits",
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([
'vcpu_count' => 8,
'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}/set-limits"
payload := strings.NewReader("{\n \"vcpu_count\": 8,\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}/set-limits")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"vcpu_count\": 8,\n \"memory_limit_gib\": 48\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/set-limits")
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 \"vcpu_count\": 8,\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 4 is below the 16 GiB minimum for 8 vCPUs",
"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": "lower the memory limit while the Sailbox is running; Sail cannot see what a sleeping Sailbox is using",
"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, set limits, 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
The limits to set on a Sailbox: its vCPU count, memory limit, and disk limit. Regardless of configured limits, you are only charged for the resources the Sailbox workload actually consumes at runtime. Limits are for finer grained control over a Sailbox's allowable resource consumption. 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 vCPU count, 1 to 8. A memory limit below the new count's minimum is raised to it.
1 <= x <= 8Deprecated; set vcpu_count instead. Stands for the vCPU count of the retired size: s is 1, m is 4, l is 8. Sizes will be unsupported in future SDK versions.
s, m, l The new memory limit in whole GiB, within the range for the Sailbox's vCPU count after the call: 2 to 256 with 1 vCPU, 8 to 256 with 2 to 4, and 16 to 256 with 5 to 8. 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, 8 to 1024. A disk only grows: a value below the current limit is refused.
x >= 1Response
The Sailbox's limits 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 limits now. false when it was powered off: the limits are recorded and take effect at the next wake. Also false when a restart the change needed could not complete; the Sailbox is then paused with the new limits recorded.
true when the change restarted the Sailbox. Files on its disk were kept; running processes and memory were not.
Deprecated; read vcpu_count instead. The retired size label whose vCPU count matches the Sailbox now: s for 1, m for 4, l for 8. Empty for any other count.
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.