PandaStack
Use cases

Data pipelines

Run untrusted data transformations in disposable sandboxes — perfect for ETL, scraping, and one-off batch jobs.

Use disposable sandboxes to isolate ETL steps, scrapers, and batch transforms. Put files through sandbox.filesystem and execute code with exec or run_code.

from pandastack import Sandbox

sandbox = Sandbox.create(
    template="code-interpreter",
    ttl_seconds=3600,
    metadata={"pipeline": "daily-import"},
)

sandbox.filesystem.upload("./input.csv", "/workspace/input.csv")

result = sandbox.exec(
    "python -c \"import pandas as pd; df=pd.read_csv('/workspace/input.csv'); df.to_json('/workspace/output.json')\"",
    timeout_seconds=300,
)

if result.exit_code != 0:
    print("\n".join(sandbox.logs(stream="both", follow=False)))
    raise RuntimeError(result.stderr)

sandbox.filesystem.download("/workspace/output.json", "./output.json")
sandbox.kill()
import { Sandbox } from "@pandastack/sdk";

const sandbox = await Sandbox.create({
  template: "code-interpreter",
  ttlSeconds: 3600,
  metadata: { pipeline: "daily-import" },
});

await sandbox.filesystem.upload("./input.csv", "/workspace/input.csv");

const result = await sandbox.exec(
  "python -c \"import pandas as pd; df=pd.read_csv('/workspace/input.csv'); df.to_json('/workspace/output.json')\"",
  { timeoutSeconds: 300 },
);

if (result.exitCode !== 0) {
  for await (const line of sandbox.logs({ stream: "both" })) console.log(line);
  throw new Error(result.stderr);
}

await sandbox.filesystem.download("/workspace/output.json", "./output.json");
await sandbox.kill();
pandastack sandbox create --template code-interpreter --ttl 3600 --metadata pipeline=daily-import
pandastack fs upload <id> --local ./input.csv --remote /workspace/input.csv
pandastack fs write <id> --path /workspace/transform.py \
  --content 'import pandas as pd; df=pd.read_csv("/workspace/input.csv"); df.to_json("/workspace/output.json")'
pandastack sandbox exec <id> --timeout 300 -- python /workspace/transform.py
pandastack fs download <id> --remote /workspace/output.json --local ./output.json
pandastack sandbox logs <id> --stream both   # on failure, inspect both streams
pandastack sandbox delete <id>
# Create the sandbox
curl -X POST https://api.pandastack.ai/v1/sandboxes \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template": "code-interpreter", "ttl_seconds": 3600, "metadata": {"pipeline": "daily-import"}}'

# Upload the input file and the transform script
curl -X PUT "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/input.csv" \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  --data-binary @./input.csv

printf 'import pandas as pd\ndf = pd.read_csv("/workspace/input.csv")\ndf.to_json("/workspace/output.json")\n' |
  curl -X PUT "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/transform.py" \
    -H "Authorization: Bearer $PANDASTACK_API_KEY" \
    --data-binary @-

# Run it (check exit_code in the response)
curl -X POST https://api.pandastack.ai/v1/sandboxes/<id>/exec \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"cmd": "python /workspace/transform.py", "timeout_seconds": 300}'

# Download the result, then clean up
curl "https://api.pandastack.ai/v1/sandboxes/<id>/fs?path=/workspace/output.json" \
  -H "Authorization: Bearer $PANDASTACK_API_KEY" \
  -o ./output.json

curl -X DELETE https://api.pandastack.ai/v1/sandboxes/<id> \
  -H "Authorization: Bearer $PANDASTACK_API_KEY"

Python batch job

Shown in the Python tab above.

TypeScript batch job

Shown in the TypeScript tab above.

CLI debugging

The step-by-step CLI equivalent is in the CLI tab above — handy for poking at a pipeline sandbox interactively.

On this page