---
title: "Stop a sandbox"
method: POST
path: "/sandboxes/{sandbox_id}/stop"
tags: ["Sandboxes"]
---

# Stop a sandbox

`POST /sandboxes/{sandbox_id}/stop`

## Request

- Base URL: `https://api.hedra.com/v3`
- URL: `https://api.hedra.com/v3/sandboxes/{sandbox_id}/stop`
- Auth: one of:
  - API key in header `Authorization`
  - HTTP bearer

Stop every instance. Answers the sandbox, also when it is already
stopping, ended or failed; settlement refunds the unused part of its
lease once every instance has stopped.

## Path parameters

- `sandbox_id` string, required: The sandbox's id (`sandbox_<uuid>`).

## Response `200`

Successful Response

- Sandbox: One GPU sandbox.
  - `id` string, required: The sandbox's id (`sandbox_<uuid>`).
  - `name` string, required: The sandbox's name, as created.
  - `accelerator` string, required: The request's `accelerator`.
  - `gpu_model` string, required: The `accelerator`'s GPU model.
  - `replicas` integer, required: How many instances.
  - `status` 'creating' | 'active' | 'stopping' | 'ended' | 'failed', required: Where a sandbox is in its life; stored in ``sandbox_billings.status``.
  - `end_reason` 'caller_stopped' | 'ttl_ended' | 'exited' | 'instance_failed' | 'unpaid' | 'lease_lapsed' | 'access_removed' | 'idle_ttl_ended', required: Why a sandbox ended, or, on an `active` one, that its last lease was refused.
  - `created_at` string, date-time, required
  - `started_at` string, date-time, nullable, required: The earliest `started_at` of its instances; null on the list and before any instance starts.
  - `ended_at` string, date-time, nullable, required: When the last instance stopped; null until then.
  - `ttl_ends_at` string, date-time, nullable, required: When the sandbox's lifetime ends: `created_at` plus `ttl_seconds`; null for a sandbox created without `ttl_seconds`.
  - `env_keys` string[], required: The keys of `env`, never its values.
  - `image` string, nullable: The image the sandbox runs, as created. Set wherever `instances` is and the sandbox has an instance; null on the list, on the create answer, and while it has none.
  - `command` string[], nullable: The `command` the sandbox runs, as created and returned as given, so a secret belongs in `env` rather than here; null when `image` is, when the image's own `ENTRYPOINT`/`CMD` runs, and for an `idle` sandbox.
  - `instances` SandboxInstance[], nullable, required: One entry per replica; null on the list.
    - `replica` integer, required: The replica's number, from 0.
    - `status` 'starting' | 'running' | 'stopped' | 'failed', required: One instance's state, derived from its hedra-compute charge times.
    - `started_at` string, date-time, nullable, required: When the instance started running; null while it starts.
    - `stopped_at` string, date-time, nullable, required: When the instance stopped; null while it runs.
    - `failure_reason` 'quota_exceeded' | 'no_capacity' | 'image_pull_failed' | 'start_failed' | 'process_exited' | 'oom_killed' | 'gpu_error' | 'platform_error' | 'other', required: The instance failures v3 publishes; `platform_error` means the platform lost the instance or could not stage it, so creating the sandbox again may succeed, and `other` covers reasons hedra-compute adds later.
  - `url` string, nullable: The address of the port in `ports`, the same for every replica; call it with a token from `POST /sandboxes/{sandbox_id}/endpoint-token`. Set wherever `instances` is; null on the list, for a sandbox created without `ports`, and while its pool serves no address.
  - `billing` SandboxBillingSummary, required: What a sandbox costs, has paid and was charged.
    - `usd_per_hour` number, required: The sandbox's rate per hour for all its instances, after your workspace's discount.
    - `paid_usd` number, required: What the sandbox has paid from the API wallet, net of refunds.
    - `charged_usd` number, nullable, required: The charge once settled. Before that, on `GET /sandboxes/{sandbox_id}` only, the charge so far; null on the list.
    - `settled` boolean, required: Whether the charge is final and the difference from `paid_usd` has been refunded or debited.

## Other responses

- `400`: Invalid or failed-validation request.
- `401`: Authentication failed: missing, malformed, or invalid credentials.
- `403`: Insufficient scope or plan.
- `404`: Resource not found.
- `409`: `ALREADY_IN_PROGRESS`: the sandbox is still being created; retry after `Retry-After`.
- `429`: Rate limit exceeded.
- `500`: Internal error.

## Changes

- **2026-11-04** `6ef35a11cefe`: 1 warning, 2 info
  - added the new `idle_ttl_ended` enum value to the `end_reason/anyOf[subschema #1: SandboxEndReason]/` response property for the response status `200`
  - added the optional property `command` to the response with the `200` status
  - added the optional property `image` to the response with the `200` status
- **2026-10-28** `c482e691c208`: 1 breaking
  - response property `ttl_ends_at` list-of-types was widened by adding types `null` to media type `application/json` of response `200`
- **2026-10-24** `9e0b37b16bb7`: 1 warning
  - added the new `platform_error` enum value to the `instances/anyOf[subschema #1]/items/failure_reason/anyOf[subschema #1: SandboxFailureReason]/` response property for the response status `200`
- **2026-10-23** `e733493214f4`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/hedra-labs/apis/hedra-api/changes/sandboxes/:sandbox_id/stop/post.md)

---

[API](https://skmtc.dev/hedra-labs/apis/hedra-api.md) - [All operations](https://skmtc.dev/hedra-labs/apis/hedra-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hedra-labs/apis/hedra-api/revisions/6ef35a11cefe?raw)
