# sandbox

OpenAPI spec: [https://api.payweave.app/app/app_a2a0ivb5s4sbfspozeodd87e/openapi.json](https://api.payweave.app/app/app_a2a0ivb5s4sbfspozeodd87e/openapi.json)

## Networks

| Name | Mode | CAIP-2 | Chain ID / Cluster |
|---|---|---|---|
| Tempo Mainnet | live | `eip155:4217` | 4217 |
| Solana Mainnet | live | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | mainnet-beta |

## Accepted Currencies

| Symbol | Name | Decimals | Network | Address |
|---|---|---|---|---|
| USDC.e | Bridged USDC (Stargate) | 6 | `eip155:4217` | `0x20c000000000000000000000b9537d11c60e8b50` |
| USDC | USD Coin (Solana) | 6 | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |

## Endpoints (2)

### Sandbox: Exec Command

Run a shell command in a fresh isolated sandbox (Linux container with python3, node, git, and common CLI tools) and get stdout, stderr, and the exit code. $0.01 flat per command. Each call runs in its own single-use container, so installed packages and files do not persist between calls; chain steps inside one command with && when needed. Execution is capped at 60 seconds (timeout_ms, default 30000). The body is validated before charging and infrastructure failures are refunded automatically; a non-zero exit code is a successful execution and is returned, not refunded.

- Method: POST
- Path: `/exec`
- Price: $0.01000000

**Input Schema**

```json
{
  "type": "object",
  "properties": {
    "command": {
      "type": "string",
      "minLength": 1,
      "maxLength": 10000,
      "description": "Shell command to execute, e.g. \"python3 --version\" or \"pip install requests\""
    },
    "cwd": {
      "type": "string",
      "description": "Working directory. Defaults to /workspace."
    },
    "env": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "Environment variables visible to this execution only"
    },
    "timeout_ms": {
      "type": "integer",
      "minimum": 1000,
      "maximum": 60000,
      "default": 30000,
      "description": "Execution wall-clock limit in milliseconds (1000 to 60000, default 30000). Executions that exceed it are killed."
    }
  },
  "required": [
    "command"
  ],
  "additionalProperties": false
}
```

**Output Schema**

```json
{
  "type": "object",
  "properties": {
    "success": {
      "type": "boolean",
      "description": "True when the command exited 0"
    },
    "exitCode": {
      "type": "integer"
    },
    "stdout": {
      "type": "string"
    },
    "stderr": {
      "type": "string"
    }
  },
  "required": [
    "success",
    "exitCode",
    "stdout",
    "stderr"
  ],
  "additionalProperties": true
}
```

## How to invoke

Payment is handled automatically — the client signs the 402 challenge and retries.

### TypeScript — Tempo (mppx + fetch) ([docs](https://mpp.dev/sdk/typescript/client))

```ts
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'

Mppx.create({
  methods: [tempo({ account: privateKeyToAccount('0x...') })],
})

const res = await fetch('https://sandbox.payweave.services/exec', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "command": "",
    "cwd": "",
    "env": {}
  }),
})
const data = await res.json()
```

### TypeScript — Solana (@solana/mpp + fetch) ([docs](https://github.com/solana-foundation/mpp-sdk))

```ts
import { createKeyPairSignerFromBytes } from '@solana/kit'
import { Mppx } from 'mppx/client'
import { solana } from '@solana/mpp/client'

const signer = await createKeyPairSignerFromBytes(/* 64-byte secret key */)
Mppx.create({ methods: [solana({ signer })] })

const res = await fetch('https://sandbox.payweave.services/exec', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "command": "",
    "cwd": "",
    "env": {}
  }),
})
const data = await res.json()
```

### mppx CLI ([docs](https://mpp.dev/sdk/typescript/cli))

```sh
npx mppx "https://sandbox.payweave.services/exec" -X POST -H 'Content-Type: application/json' -d '{"command":"","cwd":"","env":{}}'
```

### Tempo Wallet ([docs](https://docs.tempo.xyz/cli/wallet))

```sh
tempo request "https://sandbox.payweave.services/exec" -X POST --json '{"command":"","cwd":"","env":{}}'
```

### pay.sh — Solana Foundation ([docs](https://pay.sh))

```sh
pay --mainnet curl "https://sandbox.payweave.services/exec" -X POST -H 'Content-Type: application/json' -d '{"command":"","cwd":"","env":{}}'
```

### Sandbox: Run Code

Execute Python, JavaScript, or TypeScript in a fresh isolated sandbox and get stdout, stderr, rich results (including base64 PNG for charts), and any error with traceback. $0.01 flat per execution. Each call runs in its own single-use container: no state persists between calls and callers never share an environment. Execution is capped at 60 seconds (timeout_ms, default 30000). The body is validated before charging and infrastructure failures are refunded automatically; your own code raising an error is a successful execution and is returned, not refunded.

- Method: POST
- Path: `/run`
- Price: $0.01000000

**Input Schema**

```json
{
  "type": "object",
  "properties": {
    "code": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100000,
      "description": "Source code to execute"
    },
    "language": {
      "type": "string",
      "enum": [
        "python",
        "javascript",
        "typescript"
      ],
      "default": "python",
      "description": "Interpreter to run the code with. Defaults to python."
    },
    "env": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "Environment variables visible to this execution only"
    },
    "timeout_ms": {
      "type": "integer",
      "minimum": 1000,
      "maximum": 60000,
      "default": 30000,
      "description": "Execution wall-clock limit in milliseconds (1000 to 60000, default 30000). Executions that exceed it are killed."
    }
  },
  "required": [
    "code"
  ],
  "additionalProperties": false
}
```

**Output Schema**

```json
{
  "type": "object",
  "properties": {
    "success": {
      "type": "boolean",
      "description": "True when the code ran without raising an error"
    },
    "language": {
      "type": "string"
    },
    "logs": {
      "type": "object",
      "properties": {
        "stdout": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Captured stdout chunks, in order"
        },
        "stderr": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Captured stderr chunks, in order"
        }
      },
      "required": [
        "stdout",
        "stderr"
      ],
      "additionalProperties": false
    },
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "png": {
            "type": "string",
            "description": "Base64 PNG when the code produced an image, e.g. a matplotlib chart"
          }
        },
        "additionalProperties": true
      },
      "description": "Rich outputs from the final expression, Jupyter-style"
    },
    "error": {
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "name": {
              "type": "string"
            },
            "message": {
              "type": "string"
            },
            "traceback": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "required": [
            "name",
            "message",
            "traceback"
          ],
          "additionalProperties": true
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "success",
    "language",
    "logs",
    "results",
    "error"
  ],
  "additionalProperties": true
}
```

## How to invoke

Payment is handled automatically — the client signs the 402 challenge and retries.

### TypeScript — Tempo (mppx + fetch) ([docs](https://mpp.dev/sdk/typescript/client))

```ts
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'

Mppx.create({
  methods: [tempo({ account: privateKeyToAccount('0x...') })],
})

const res = await fetch('https://sandbox.payweave.services/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "code": "",
    "language": "python",
    "env": {}
  }),
})
const data = await res.json()
```

### TypeScript — Solana (@solana/mpp + fetch) ([docs](https://github.com/solana-foundation/mpp-sdk))

```ts
import { createKeyPairSignerFromBytes } from '@solana/kit'
import { Mppx } from 'mppx/client'
import { solana } from '@solana/mpp/client'

const signer = await createKeyPairSignerFromBytes(/* 64-byte secret key */)
Mppx.create({ methods: [solana({ signer })] })

const res = await fetch('https://sandbox.payweave.services/run', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    "code": "",
    "language": "python",
    "env": {}
  }),
})
const data = await res.json()
```

### mppx CLI ([docs](https://mpp.dev/sdk/typescript/cli))

```sh
npx mppx "https://sandbox.payweave.services/run" -X POST -H 'Content-Type: application/json' -d '{"code":"","language":"python","env":{}}'
```

### Tempo Wallet ([docs](https://docs.tempo.xyz/cli/wallet))

```sh
tempo request "https://sandbox.payweave.services/run" -X POST --json '{"code":"","language":"python","env":{}}'
```

### pay.sh — Solana Foundation ([docs](https://pay.sh))

```sh
pay --mainnet curl "https://sandbox.payweave.services/run" -X POST -H 'Content-Type: application/json' -d '{"code":"","language":"python","env":{}}'
```
