Files

Put code and data into a sandbox, and get results back out, without building shell commands by hand. Four operations on one endpoint: write, read, list, delete.

You can always move files with exec and a heredoc, and for a three-line script that is fine. It stops being fine as soon as the content contains a quote, a backtick, a dollar sign or a byte that is not text — at that point you are writing an escaping routine, and the shell is going to win. These endpoints transfer content out of band so nothing is ever interpreted.

Writing a file

PUT https://sandbox-as-a-service.com/v1/sandboxes/{id}/files
curl -sS -X PUT https://sandbox-as-a-service.com/v1/sandboxes/$SBX/files \
  -H "Authorization: Bearer $AAS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"path":"analyse.py","content":"import pandas as pd\nprint(pd.__version__)\n"}'
import requests

requests.put(
    f"{API}/sandboxes/{sandbox_id}/files",
    headers=headers,
    json={"path": "analyse.py", "content": script_source},
).raise_for_status()
await fetch(`${API}/sandboxes/${sandboxId}/files`, {
  method: "PUT",
  headers,
  body: JSON.stringify({ path: "analyse.py", content: scriptSource }),
});

The response confirms the resolved path and the number of bytes written:

{
  "object": "file",
  "path": "/workspace/analyse.py",
  "bytes": 42
}

Binary content

Set encoding to base64 and send the encoded bytes. Use this for anything that is not UTF-8 text — images, archives, compiled artefacts, model weights.

{"path": "input.png", "content": "iVBORw0KGgoAAA...", "encoding": "base64"}

Reading a file

GET https://sandbox-as-a-service.com/v1/sandboxes/{id}/files?path=out/report.json

Returns the content as UTF-8 text by default. Add &encoding=base64 to get the raw bytes back, which is what you want for anything your code produced that is not text.

curl -sS "https://sandbox-as-a-service.com/v1/sandboxes/$SBX/files?path=out/report.json" \
  -H "Authorization: Bearer $AAS_API_KEY"

Listing a directory

GET https://sandbox-as-a-service.com/v1/sandboxes/{id}/files?path=/workspace&list=true

Returns every entry beneath the path, recursively, with its type and size. This is the call an agent makes after running something, to find out what the run produced:

{
  "object": "list",
  "path": "/workspace",
  "entries": [
    { "name": "analyse.py", "type": "file", "size_bytes": 42 },
    { "name": "out",        "type": "dir",  "size_bytes": 4096 },
    { "name": "out/report.json", "type": "file", "size_bytes": 2214 }
  ],
  "truncated": false
}

Listings recurse up to 12 levels and 2,000 entries. If a tree is larger than that — you listed a directory containing node_modules — the response carries "truncated": true rather than quietly handing back a short list. Pass &recursive=false for one level only.

Deleting

DELETE https://sandbox-as-a-service.com/v1/sandboxes/{id}/files?path=out/report.json

Removes a file or a directory and its contents. Deleting /workspace itself is refused — destroy the sandbox instead, or delete its contents. In practice you rarely need this: the sandbox is thrown away shortly afterwards regardless.

Where paths resolve

You writeIt resolves to
analyse.py/workspace/analyse.py
out/report.json/workspace/out/report.json
/workspace/analyse.py/workspace/analyse.py
/tmp/scratch/tmp/scratch

Relative paths resolve under /workspace, the working directory exec uses by default, so the common case needs no prefix. Absolute paths are honoured as given. Parent-directory segments are rejected outright rather than normalised, so a path assembled from user input cannot walk out of where you meant it to go. Intermediate directories are created for you on write.

Files are written as the unprivileged sandbox user, the same user your commands run as. Paths that user cannot write are an error, not a silent failure.

Limits

LimitValue
Maximum file size, read or write8 MiB
Maximum path length4096 characters
Requests per minute120, shared with the rest of the API

For anything larger than 8 MiB, have the sandbox fetch it directly — it has outbound network access, so curl from object storage is faster than a round trip through this API and is not subject to the cap.

A complete round trip

Write a script, run it, read back what it produced:

SBX=$(curl -sS -X POST https://sandbox-as-a-service.com/v1/sandboxes \
  -H "Authorization: Bearer $AAS_API_KEY" -H "Content-Type: application/json" \
  -d '{"size":"small"}' | jq -r .id)

curl -sS -X PUT https://sandbox-as-a-service.com/v1/sandboxes/$SBX/files \
  -H "Authorization: Bearer $AAS_API_KEY" -H "Content-Type: application/json" \
  -d '{"path":"run.py","content":"import json\njson.dump({\"answer\": 42}, open(\"out.json\",\"w\"))\n"}'

curl -sS -X POST https://sandbox-as-a-service.com/v1/sandboxes/$SBX/exec \
  -H "Authorization: Bearer $AAS_API_KEY" -H "Content-Type: application/json" \
  -d '{"command":"python3 run.py"}'

curl -sS "https://sandbox-as-a-service.com/v1/sandboxes/$SBX/files?path=out.json" \
  -H "Authorization: Bearer $AAS_API_KEY" | jq -r .content

curl -sS -X DELETE https://sandbox-as-a-service.com/v1/sandboxes/$SBX -H "Authorization: Bearer $AAS_API_KEY"

From an agent

The MCP server exposes the same operations as write_file, read_file and list_files tools, so an agent can put a script somewhere, run it, and go looking for what it produced without any of this being written as HTTP calls.

Why not just use exec with a heredoc?

You can, and for short plain-text scripts it is perfectly reasonable. The failure mode is content you did not write yourself: a quote, a backtick or a $ in generated code changes what the shell does, and binary content cannot survive at all. These endpoints move the content out of band, so the sandbox never parses it.

Do files survive after the sandbox is destroyed?

No. Nothing in a sandbox is persistent — the machine and its disk are destroyed on expiry or on delete. Read anything you want to keep before that happens, or have the sandbox upload it somewhere while it is running.

Can I read files outside /workspace?

Yes, with an absolute path, subject to what the unprivileged sandbox user is allowed to read. What you cannot do is escape a relative path with .. — those are rejected rather than normalised.

Is there a directory upload or an archive endpoint?

Not yet. For a tree, either write the files individually or write one archive and unpack it with exec — tar and unzip are in the image.