# HTTP API reference Base URL: `https://www.security.run`. Requests and responses use JSON. Authenticate private routes with `Authorization: Bearer YOUR_SECURITY_RUN_CREDENTIAL`. See [Authentication](/docs/authentication/) before using the API. ## Catalog and account | Method | Path | Result | | --- | --- | --- | | GET | `/healthz` | Public service health. | | GET | `/v1/images` | Public image catalog under `images`, with credit rates. | | GET | `/v1/billing/config` | Public billing availability and trial settings. | | GET | `/auth/me` | Authenticated owner identity. | | GET | `/v1/billing/account` | Remaining, promotional, paid and spent credits; account limits. | | GET | `/v1/billing/history` | Recent credit activity under `entries`; each entry has `amount_credits`, `kind`, and Unix `at` time. | | GET | `/v1/billing/statements` | Stripe balance expressed in credits, plus invoices and hosted statement URLs. | ```bash curl --fail-with-body https://www.security.run/v1/billing/account \ -H "Authorization: Bearer $SECURITY_RUN_API_KEY" ``` Read `hourly_credits` and `egress_gib_credits` from each image's `pricing`. Use the current catalog IDs rather than guessing image names. Older USD fields remain compatibility aliases; new clients should use credit fields. Security desktop images have `desktop: true` and `access: "rdp"`. Parrot, SIFT and REMnux also support SSH. Their `sizes` array contains Standard only; the gallery and SDKs use the same catalog. ## Quote a session `POST /v1/sessions/quote` accepts the same session input as launch. It returns rates, `max_credits`, `egress_budget_credits`, `ttl_seconds`, and the concurrency limit. These are informational upper limits. It does not create a session or spend credits, and launch does not require the full quoted amount. ```bash curl --fail-with-body https://www.security.run/v1/sessions/quote \ -H "Authorization: Bearer $SECURITY_RUN_API_KEY" \ -H 'Content-Type: application/json' \ --data '{"image":"ubuntu-24.04","ttl_seconds":1800,"egress_budget_credits":10}' ``` ## Create a session `POST /v1/sessions` requires an **Idempotency-Key** header and returns **202 Accepted** with a session object. | Input | Type | Constraints | | --- | --- | --- | | `image` | string, required | Exact catalog ID, such as `ubuntu-24.04`. | | `ttl_seconds` | integer | 300–14,400; trial accounts are limited to 1,800. The raw HTTP default is 3,600, so explicitly send 1,800 for trial sessions. | | `egress_budget_credits` | integer | 10–500; default 50. | | `Idempotency-Key` header | string, required | 1–128 characters; unique per logical launch and reused for identical retries. | ```bash curl --fail-with-body https://www.security.run/v1/sessions \ -H "Authorization: Bearer $SECURITY_RUN_API_KEY" \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: case-482-linux' \ --data '{"image":"ubuntu-24.04","ttl_seconds":1800,"egress_budget_credits":10}' ``` The response includes `id`, `image`, `state`, `ip`, `browser_url`, `created_at`, `expires_at`, `cleanup_status`, and billing information. IP can be null until ready. Native credentials are retrieved separately. Timestamps are Unix seconds. Use the exact same idempotency key and body after an uncertain response. A changed request body under a used key conflicts. A key does not create another VM when the original session has ended; use a new key for a new session. ## Read, connect and destroy | Method | Path | Result | | --- | --- | --- | | GET | `/v1/sessions` | Owner-scoped `sessions` array and `next_cursor`. | | GET | `/v1/sessions/{id}` | Current session without native credentials. | | GET | `/v1/sessions/{id}/connection` | Ready session plus native connection details. | | POST | `/v1/sessions/{id}/browser` | Short-lived, owner-authorized browser-gateway handoff URL. Normally handled by the web app. | | DELETE | `/v1/sessions/{id}` | Request teardown; 202 does not mean cleanup is already complete. | For listing, send the returned `next_cursor` as the URL-encoded `cursor` query parameter until it is null. Both SDKs follow these pages automatically. A cursor belongs to its authenticated owner. Poll a session with a delay of a few seconds while it starts. Once `state` is `ready`, retrieve `/connection`. It returns `ip`, `port`, `protocol`, `browser_url`, and a `credentials` object. Open the regular `browser_url` in the web app; it still requires the owner's sign-in. For Linux security desktops, `protocol` is `rdp`, `port` is `3389`, and `ssh_port` is `22`. The same response contains both a desktop `password` and an SSH `private_key`, along with their shared `username`. Always use the returned username: SIFT uses `sansforensics`, REMnux uses `remnux`, and Parrot uses `runner`. Windows/FLARE credentials contain a password and have no SSH port. ```bash curl --fail-with-body https://www.security.run/v1/sessions/ses_YOUR_SESSION_ID \ -H "Authorization: Bearer $SECURITY_RUN_API_KEY" \ -X DELETE ``` Poll until the terminal state and inspect `cleanup_status`. Repeat DELETE safely if the response was lost. There is no session extension, pause/resume, snapshot, in-place size-change, or remote command execution endpoint in this release. ## Checkout `POST /v1/billing/checkout` requires an Idempotency-Key and one of these JSON bodies: ```json {"kind":"trial","amount_usd":0} ``` ```json {"kind":"topup","amount_usd":10} ``` Supported top-up amounts are 10, 25, 50 and 100 USD. These are purchase prices, not usage balances. The result contains an `id` and a Stripe-hosted `url`. Open that URL to complete card verification or payment; do not collect raw card details yourself. `GET /v1/billing/checkouts/{id}` returns checkout fulfillment state. `fulfilled` means credits were granted; `failed` or `rejected` includes a reason. Any other state can still be pending. A successful browser redirect alone does not grant credits: verified Stripe webhook processing does. ## Error responses Errors normally include a human-readable `detail`. Billing errors also have a machine-readable `code`; request validation can return a structured detail array. | Status | Typical meaning | Action | | --- | --- | --- | | 400 | Invalid amount or cursor | Correct the request. | | 401 | Missing, expired or invalid credential | Sign in again or check the supplied credential. | | 402 | Not enough credits for the compute minimum | Add credits or activate an eligible trial. | | 403 | Email confirmation, trial limit, or account hold | Follow the reason in the response. | | 404 | Session/image unavailable to this owner | Check the ID, catalog and identity. | | 409 | Not ready or conflicting request | Wait for readiness, or fix idempotency-key reuse. | | 422 | Invalid request fields | Check names, types and limits. | | 429 | Rate, concurrency or capacity limit | Back off; finish an existing session when applicable. | | 503 | Temporary service or billing unavailability | Retry with backoff and preserve the launch key. | The SDKs retry transient network failures and HTTP 429/502/503/504 up to three attempts. They do not turn a timeout into cancellation. See [Troubleshooting](/docs/troubleshooting/) for recovery steps. ## Size and inactivity options `POST /v1/sessions` and `/v1/sessions/quote` accept `size: "small" | "standard"`. Omit it for Small on basic Linux terminals or Standard on desktops. Unsupported combinations fail before allocation. `GET /v1/images` includes the default size, resource specifications, pricing, and a `sizes` array. Existing sessions keep their launch size and rate. Session creation also accepts `idle_timeout_seconds: 0 | 900` (default `0` for API clients). The browser sends `900`. The idle timer begins when the guest becomes ready. An authenticated `POST /v1/sessions/{id}/activity` records activity using server time. `PATCH /v1/sessions/{id}/idle` with `{"enabled": false}` disables idle cleanup; `true` re-enables it and resets the 15-minute timer. These operations are owner-scoped and never extend `expires_at`. Metadata includes `idle_timeout_seconds` and, when enabled, `idle_expires_at`.