curl --request PUT \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"volume_id": "<string>",
"mount_path": "/mnt/shared",
"read_only": false,
"cache_seconds": 0
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts"
payload = {
"volume_id": "<string>",
"mount_path": "/mnt/shared",
"read_only": False,
"cache_seconds": 0
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
volume_id: '<string>',
mount_path: '/mnt/shared',
read_only: false,
cache_seconds: 0
})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts', 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}/volume-mounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'volume_id' => '<string>',
'mount_path' => '/mnt/shared',
'read_only' => false,
'cache_seconds' => 0
]),
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}/volume-mounts"
payload := strings.NewReader("{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}")
req, _ := http.NewRequest("PUT", 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.put("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}"
response = http.request(request)
puts response.read_body{}{
"error": {
"message": "memory_limit_gib for size m must be between 8 and 128",
"type": "invalid_request_error",
"param": null,
"code": null
}
}{
"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": "mount_path overlaps an existing mount",
"type": "conflict_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
}
}Mount a volume on a running Sailbox
Add a volume at an empty absolute path without restarting the Sailbox. Return after the mount is applied. Identical retries are safe. A timeout can leave a recorded attachment; retry the same request. Existing mounts cannot be removed or replaced. Older Sailboxes require an explicit upgrade. Existing containers need mount propagation to see this new mount.
curl --request PUT \
--url https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"volume_id": "<string>",
"mount_path": "/mnt/shared",
"read_only": false,
"cache_seconds": 0
}
'import requests
url = "https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts"
payload = {
"volume_id": "<string>",
"mount_path": "/mnt/shared",
"read_only": False,
"cache_seconds": 0
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
volume_id: '<string>',
mount_path: '/mnt/shared',
read_only: false,
cache_seconds: 0
})
};
fetch('https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts', 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}/volume-mounts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'volume_id' => '<string>',
'mount_path' => '/mnt/shared',
'read_only' => false,
'cache_seconds' => 0
]),
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}/volume-mounts"
payload := strings.NewReader("{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}")
req, _ := http.NewRequest("PUT", 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.put("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://sailbox-api.sailresearch.com/v1/sailboxes/{sailbox_id}/volume-mounts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"volume_id\": \"<string>\",\n \"mount_path\": \"/mnt/shared\",\n \"read_only\": false,\n \"cache_seconds\": 0\n}"
response = http.request(request)
puts response.read_body{}{
"error": {
"message": "memory_limit_gib for size m must be between 8 and 128",
"type": "invalid_request_error",
"param": null,
"code": null
}
}{
"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": "mount_path overlaps an existing mount",
"type": "conflict_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
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Id of the Sailbox, as returned by create. It is sb_ followed by a UUID.
Body
Id of a volume you created earlier.
1\SAbsolute path inside the Sailbox where the volume appears. Repeated slashes and ./.. segments are resolved first, and the result cannot be /. Two mounts in one request cannot nest inside each other. A new mount requires an absent or empty directory, including in the image. See the volume guide.
^\s*/."/mnt/shared"
How long, in seconds, this mount may reuse what it has already read about the volume before checking for changes. Files and their contents on this mount can lag changes made through other mounts by up to about twice this value. Only time the Sailbox is running counts, so after it resumes from being paused or asleep the mount can show older files for as long as was left when it stopped. After more than a day paused or asleep, reading a file that changed in the meantime can fail for that same remaining time. Longer values make repeated reads faster. Requires read_only: true. The default, 0, picks up changes within about a second.
0 <= x <= 3600Response
The volume is mounted.
The response is of type object.