curl --request POST \
--url https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Outerlayer-App-Id: <api-key>' \
--data '
{
"idleMinutes": 123,
"metadata": {},
"timeLimitMinutes": 123,
"waits": true
}
'import requests
url = "https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox"
payload = {
"idleMinutes": 123,
"metadata": {},
"timeLimitMinutes": 123,
"waits": True
}
headers = {
"X-Outerlayer-App-Id": "<api-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Outerlayer-App-Id': '<api-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({idleMinutes: 123, metadata: {}, timeLimitMinutes: 123, waits: true})
};
fetch('https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox', 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.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox",
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([
'idleMinutes' => 123,
'metadata' => [
],
'timeLimitMinutes' => 123,
'waits' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Outerlayer-App-Id: <api-key>"
],
]);
$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.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox"
payload := strings.NewReader("{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Outerlayer-App-Id", "<api-key>")
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://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox")
.header("X-Outerlayer-App-Id", "<api-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Outerlayer-App-Id"] = '<api-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"dataPlaneUrl": "<string>",
"id": "<string>",
"machine": "small",
"metadata": {},
"name": "<string>",
"secret": "<string>",
"state": "<string>",
"tokenHeader": "<string>",
"urlToken": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Create the managed sandbox of a claim a self-hosted runner holds
Creates a sandbox on OuterLayer’s account at the sandbox provider for the claim the caller holds, and answers with the sandbox’s address and secret. The gateway chooses the snapshot. The sandbox gets the processors and memory of the machine size, a disk no smaller than the snapshot’s, and no direct network access. A claim has one sandbox at a time: a claim that has a sandbox gets that sandbox again. The claim counts as a managed build from this call on, and its time is billed as managed build-hours from the moment its sandbox has started, not from this call. The provider can take minutes to start a sandbox. With waits: true, the gateway keeps a sandbox that is slow to start and answers with it in the state starting, with an empty secret and urlToken. The gateway ends the sandbox when the claim is released or its lease expires, unless the runner keeps it (keep-managed-sandbox). A claim whose sandbox is kept gets a new sandbox, and the kept one ends. Refusals: claim_expired (410), claim_not_held (403), managed_sandboxes_off (403), managed_sandboxes_unavailable (403), managed_build_held (409, with reason: trial_hours_used, spending_cap_reached, at_limit or unavailable) and sandbox_provider_refused (502). A refused call binds no sandbox to the claim. The response is sent with Cache-Control: no-store.
curl --request POST \
--url https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Outerlayer-App-Id: <api-key>' \
--data '
{
"idleMinutes": 123,
"metadata": {},
"timeLimitMinutes": 123,
"waits": true
}
'import requests
url = "https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox"
payload = {
"idleMinutes": 123,
"metadata": {},
"timeLimitMinutes": 123,
"waits": True
}
headers = {
"X-Outerlayer-App-Id": "<api-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Outerlayer-App-Id': '<api-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({idleMinutes: 123, metadata: {}, timeLimitMinutes: 123, waits: true})
};
fetch('https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox', 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.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox",
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([
'idleMinutes' => 123,
'metadata' => [
],
'timeLimitMinutes' => 123,
'waits' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Outerlayer-App-Id: <api-key>"
],
]);
$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.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox"
payload := strings.NewReader("{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Outerlayer-App-Id", "<api-key>")
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://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox")
.header("X-Outerlayer-App-Id", "<api-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.outerlayer.ai/v1/work-items/{workItemId}/claim/sandbox")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Outerlayer-App-Id"] = '<api-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"idleMinutes\": 123,\n \"metadata\": {},\n \"timeLimitMinutes\": 123,\n \"waits\": true\n}"
response = http.request(request)
puts response.read_body{
"data": {
"dataPlaneUrl": "<string>",
"id": "<string>",
"machine": "small",
"metadata": {},
"name": "<string>",
"secret": "<string>",
"state": "<string>",
"tokenHeader": "<string>",
"urlToken": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}{
"error": {
"code": "<string>",
"message": "<string>"
}
}Authorizations
Headers
Body
Set true when the runner can wait for a sandbox that is still starting. The gateway then answers 200 with the sandbox in the state starting, and the runner reads it until it has started. Absent, the gateway answers only with a sandbox that has started, and a sandbox that is still starting gets sandbox_provider_refused (502).