One-Time Execution
Run a script once against your account — no standing process.
An execution is the other half of the runtime: code that runs once and exits. Place or close a position, rebalance across markets, sweep a balance, run a portfolio check — anything that's an action, not a strategy. Same sandbox isolation, same BYOK credential model as deployments; no standing process, no lifecycle to manage.
Deployments are for watching the market and reacting until stopped; executions are for doing one thing now. If your code has a loop waiting for signals, it's a deployment.
POST/runtime/executions
Request
curl -X POST https://api.superior.trade/runtime/executions \
-H "x-api-key: st_live_…" \
-H "content-type: application/json" \
-H "Idempotency-Key: 2c9e1b47-…" \
-d @execution.json
{
"venue": "hyperliquid",
"name": "close-btc-position",
"code": "from hyperliquid.exchange import Exchange\nfrom superior_runtime import venue_client\n\nex = venue_client() # authenticated with the injected credentials\nex.market_close(\"BTC\")\nprint(\"closed\")",
"credentials": {
"type": "byok",
"venue": "hyperliquid",
"wallet_address": "0xOperatorMainWallet…",
"private_key": "0xAgentWalletKey…"
},
"timeout_seconds": 120
}
| Field | Required | Notes |
|---|---|---|
venue | yes | The venue whose SDK and credentials the script gets |
name | no | For your listing; not unique |
code | yes | A Python script. The image ships the venue's official SDK; superior_runtime.venue_client() returns it pre-authenticated |
credentials | when the script trades or reads private account state | Same discriminated union as deployments: {"type": "managed"} | {"type": "byok", …}; used for this run only, destroyed at completion. Omitted = no credentials (read-only market scripts) — unlike deployments, omission does not default to managed, because credential-less executions are legitimate |
timeout_seconds | no | Default 120, max 900. The sandbox is killed at the limit |
Sandbox contract
Execution code runs in a short-lived, non-root Python sandbox:
| Limit | Contract |
|---|---|
| CPU / memory | 1 vCPU burst, 512 MiB memory. Exceeding memory kills the run with execution_resource_exceeded |
| Runtime | timeout_seconds defaults to 120 and cannot exceed 900 |
| Packages | Standard library plus the selected venue SDK, superior_runtime, pandas, numpy, requests, httpx, and pydantic. No pip install during execution |
| Filesystem | Writable /tmp only, capped at 64 MiB. Nothing persists after the run |
| Network | HTTPS egress to the selected venue API and Superior APIs only. Arbitrary third-party HTTP calls are blocked unless the endpoint is later added to an explicit allowlist |
| Logs | stdout and stderr are captured together, redacted for known secret fields, capped at 256 KiB total, and retained 7 days |
| Secrets | Credentials are mounted outside the source tree, exposed only through superior_runtime.venue_client(), redacted before persistence, and destroyed when the sandbox exits |
These limits are part of the API contract: backend implementations should reject code or inputs that require broader imports, persistence, or egress instead of silently running a different environment.
Response — 202
{ "id": "exec_01j8xz…", "status": "queued" }
Executions are asynchronous like backtests: queue → poll → read. Idempotency-Key (kept 24h) makes retries safe — critical here, since replaying a "close position" script is not free.
GET/runtime/executions
List: ?venue=, ?status=, limit/cursor — the standard { "executions": [...], "next_cursor": null } envelope.
GET/runtime/executions/:id
{
"id": "exec_01j8xz…",
"name": "close-btc-position",
"venue": "hyperliquid",
"status": "succeeded",
"exit_code": 0,
"output_tail": "closed\n",
"started_at": "2026-07-30T09:14:02Z",
"finished_at": "2026-07-30T09:14:11Z"
}
status: queued → running → succeeded | failed | timed_out. output_tail is the last 4KB of stdout; the full log is at /logs.
GET/runtime/executions/:id/logs
Full stdout/stderr, plain text. Retained 7 days, like deployment logs.
Sandbox contract
What your script actually gets — so backend implementers and client agents share one set of assumptions:
| Limit | |
|---|---|
| CPU / memory | 1 vCPU · 1 GiB |
| Wall clock | timeout_seconds (default 120, max 900) — sandbox killed at the limit |
| Filesystem | 512 MiB ephemeral scratch at /tmp; wiped at exit; nothing persists between executions |
| Packages | superior_runtime (the pre-authenticated venue_client() helper), the venue's official SDK, numpy, pandas, requests; no pip install at runtime — an unavailable import fails at validation |
| Network | Kernel-isolated (gVisor); cluster-internal and private networks blocked; venue endpoints reachable; general outbound HTTPS currently permitted but unsupported (same posture as deployments) |
| stdout/stderr | 1 MiB captured (logs); last 4 KB in output_tail; beyond the cap, oldest output is dropped |
| Secrets | Credential values are injected into the venue client only, never as readable env dumps, and are scrubbed from captured logs — printing a key gets you [redacted] |
Credential handling
Execution credentials are the BYOK model at its shortest-lived: injected for the run, destroyed when the sandbox exits — nothing persists between executions, and there is nothing to rotate. The toxic-material rules apply unchanged, and scoped_key verification runs on every submission.
What executions are for (and not)
- For: the operational gaps a strategy shouldn't own — closing positions before a deployment delete (
positions_open), rebalancing between markets, one-off entries an agent decided on, balance sweeps, account checks. - Not for: anything long-running (15-minute hard cap), anything scheduled (call the API on your own cadence, or use a deployment), or high-frequency loops.
Errors follow the standard taxonomy. Because executions are async, failures surface on the resource, not as HTTP errors: status: "timed_out" with error.code: "execution_timeout", or status: "failed" with error.code: "script_error" (exit_code + stderr tail in details).