> ## Documentation Index
> Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Fork Sandbox

> Create a new sandbox from an existing sandbox's snapshot, inheriting its filesystem.

Forks a sandbox: the new sandbox boots from a snapshot of the origin, so it
starts with the origin's filesystem already in place. The two are independent
from that point on — writes in the fork are not visible to the origin, and the
origin keeps running.

Use this to branch an expensive setup (dependencies installed, dataset
downloaded, model warmed) into several parallel workers without repeating the
setup in each one.

<Note>
  A fork requires an existing snapshot. Take one with
  [Create Snapshot](/api-reference/sandbox/create-snapshot) first, or the request
  fails with `404 no snapshot to fork from`.
</Note>

<Warning>
  **Without `snapshot_id`, the newest snapshot is not necessarily chosen.**
  Resolution is by source first, then recency: **newest `pause` → newest
  `periodic` → newest `manual`**.

  So if the sandbox has ever been paused, a fork with no `snapshot_id` uses that
  pause snapshot — even when the manual snapshot you just took is newer. Pass
  `snapshot_id` explicitly whenever it matters which point in time you fork from.
</Warning>

The origin's **template and resources are inherited** (they must match the
snapshot, or Firecracker rejects the restore), so `template` is ignored in the
request body. `name` falls back to the origin's when omitted.

Everything else — `timeout`, `metadata`, `envs`, `network`, `lifecycle`,
`security` — is taken from *this request*, not copied from the origin. Fields
you can set at create time but which are not read here at all (`vault_refs`,
`volumes`, `secure`, `resources`) are simply ignored.

## Path Parameters

<ParamField path="sandbox_id" type="string" required>
  The sandbox to fork from. Format: `sbx-<hex>`.
</ParamField>

## Query Parameters

<ParamField query="snapshot_id" type="string">
  Fork from a specific snapshot instead of the most recent usable one. The
  snapshot must belong to this sandbox and to your account.
</ParamField>

## Body Parameters

<Warning>
  **Policy is not inherited.** Only the template, resources and `name` come from
  the origin. `security`, `network`, `envs`, `metadata`, `lifecycle` and
  `timeout` are taken from *this request* — omit them and the fork gets **none**,
  not the origin's.

  So forking a hardened sandbox without repeating its `security` and `network`
  policy produces an **unhardened** fork. Re-send the policy you want on every
  fork.
</Warning>

All fields are optional in the sense that the request succeeds without them —
but an omitted field means "unset on the fork", not "copy the origin".

<ParamField body="name" type="string">
  Name for the forked sandbox. Unlike Create — which derives the name from the
  template — Fork honours this field.
</ParamField>

<ParamField body="timeout" type="integer">
  Auto-kill timeout in seconds, applied independently of the origin. It runs from
  creation and is **not** extended by activity — running commands does not reset
  it. Pass `0` to disable auto-kill.
</ParamField>

<ParamField body="envs" type="object">
  Environment variables for the fork. Replaces the origin's, rather than merging.
</ParamField>

<ParamField body="network" type="object">
  Network policy for the fork. See [Network Policy](/security/network-policies).
</ParamField>

<ParamField body="security" type="object">
  Security policy for the fork. See [security policies](/security/overview).
</ParamField>

<ParamField body="metadata" type="object">
  Arbitrary string key/value pairs.
</ParamField>

<ParamField body="lifecycle" type="object">
  Lifecycle configuration for the fork, applied independently of the origin.
</ParamField>

## Response

Returns `201` with the full sandbox object for the **fork** — the same shape as
[Create Sandbox](/api-reference/sandbox/create). `sandbox_id` is new; the origin
is unchanged.

## Example

<CodeGroup>
  ```bash cURL theme={null}
  # 1. snapshot the origin
  curl -X POST https://api.declaw.ai/sandboxes/sbx-a1b2c3d4/snapshot \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "after-setup"}'

  # 2. fork from THAT snapshot explicitly -- see the warning above
  curl -X POST "https://api.declaw.ai/sandboxes/sbx-a1b2c3d4/fork?snapshot_id=snap-abc123" \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "worker-1", "timeout": 1800}'
  ```

  ```python Python theme={null}
  import requests

  H = {"X-API-Key": "YOUR_API_KEY"}
  BASE = "https://api.declaw.ai/sandboxes/sbx-a1b2c3d4"

  snap = requests.post(f"{BASE}/snapshot", headers=H, json={"name": "after-setup"}).json()

  # Pass snapshot_id explicitly: a default fork resolves pause > periodic > manual,
  # so a previous pause snapshot would win over the one just taken.
  forks = [
      requests.post(
          f"{BASE}/fork",
          headers=H,
          params={"snapshot_id": snap["snapshot_id"]},
          json={"name": f"worker-{i}"},
      ).json()
      for i in range(3)
  ]
  print([f["sandbox_id"] for f in forks])
  ```
</CodeGroup>

```json Response theme={null}
{
  "sandbox_id": "sbx-9f8e7d6c",
  "template_id": "tpl-base",
  "state": "live",
  "node_id": "node-declaw-worker-2"
}
```

## Error Responses

| Status | Cause                                                                                        |
| ------ | -------------------------------------------------------------------------------------------- |
| `400`  | Invalid body, or invalid `envs` / `security` / `custom_policy` rego                          |
| `401`  | Missing or invalid API key                                                                   |
| `402`  | Insufficient balance to run the fork                                                         |
| `404`  | Sandbox not found, snapshot not found, or **no snapshot to fork from**                       |
| `422`  | Snapshot predates overlay capture and cannot be forked, or the origin has no resource config |
| `429`  | Concurrent sandbox limit reached for your tier                                               |
| `502`  | Orchestrator unreachable or returned non-200                                                 |
| `503`  | No orchestrator available, reservation failed, or wallet service unavailable                 |
