# Copy a sandbox

> Start a new sandbox with a copy of this one's disk. The source keeps running. The copy is billed like a create: $0.01, then machine time, with the same plan, balance and limit checks, and keeps the source's size, timeout, name and metadata.

`POST https://api.zavu.dev/v1/sandboxes/{sandboxId}/fork`

Start a new sandbox with a copy of this one's disk. The source keeps running. The copy is billed like a create: $0.01, then machine time, with the same plan, balance and limit checks, and keeps the source's size, timeout, name and metadata.

The source must be running or stopped, and not ephemeral. Not available with test-mode keys.

## Parameters

- `sandboxId` (path, string, required): Sandbox ID.

## Responses

### 202

Accepted. The copy is starting.

- `sandbox` (object, required): An isolated Linux machine. It is billed per second while `starting` or `running` (with a one-minute minimum per run), plus $0.01 each time it is created or resumed. A stopped sandbox costs nothing.
  - `id` (string, required)
  - `name` (string, nullable): Your label for it, set with `name` on create. Copies keep their source's name.
  - `status` (string, required): - `starting`: accepted, the machine is being prepared. Commands and file calls wait for it. - `running`: the machine is up. Machine time is billed. - `stopping`: a stop was requested; billing already ended. - `stopped`: the disk is kept until `expiresAt`, and `POST /resume` starts it again. Not billed. - `failed`: the machine could not start or failed on its host. See `failureReason`. A sandbox that fails before it ever runs gets its start fee back. One of: `starting`, `running`, `stopping`, `stopped`, `failed`.
  - `size` (string, required): Machine size, and its price per hour of machine time: - `small`: 2 vCPU, 4 GB RAM. $0.0225/h. - `default`: 4 vCPU, 8 GB RAM. $0.045/h. - `large`: 8 vCPU, 16 GB RAM. $0.09/h. One of: `small`, `default`, `large`.
  - `timeoutSeconds` (integer, required, nullable): The sandbox is stopped automatically this many seconds after it started (or was last resumed). Checked every minute. `null` when auto-stop is off: it runs until you stop it, or until the balance, the spend cap or leaving the paid plan stops it.
  - `ephemeral` (boolean, required): Created with `ephemeral: true`. Its disk is never saved: a stop erases it, `expiresAt` is the moment it stopped, and resume answers `409 sandbox_expired`.
  - `metadata` (object, required): What you attached when creating it. Kept by Zavu only; never visible inside the machine.
    - `{key}` (string)
  - `startedAt` (string<date-time>, nullable): When the current or last run was accepted.
  - `stoppedAt` (string<date-time>, nullable): When the last run ended. Null while starting or running.
  - `expiresAt` (string<date-time>, nullable): Present while `stopped`: when the disk is deleted, 14 days after the stop, or the stop itself for an ephemeral sandbox. After it, resume answers `409 sandbox_expired`.
  - `stopReason` (string, required, nullable): Why the last run ended, while `stopping` or `stopped`; null otherwise. `requested`: you stopped it, from the API or the dashboard. `timeout`: its `timeoutSeconds` passed. `insufficient_balance` and `spend_cap_reached`: the balance or the monthly spend cap no longer covered 15 more minutes. `plan`: the team left its paid plan. `provider`: it ended on its host. The `sandbox.stopped` project webhook carries the same value. One of: `requested`, `timeout`, `insufficient_balance`, `spend_cap_reached`, `plan`, `provider`, `null`.
  - `costTotal` (number, required): USD charged for this sandbox so far: start fees plus machine time. Machine time of a running sandbox is settled every five minutes, so this lags by up to five minutes until it stops.
  - `failureReason` (string, nullable): Why it failed. Present only when `status` is `failed`.
  - `forkedFromSandboxId` (string, nullable): The sandbox this one is a copy of, when it was made with `POST /v1/sandboxes/{sandboxId}/fork`.
  - `fromSnapshotId` (string, nullable): The project's saved snapshot it started from. Null when it started blank, as a copy, or from another team's shared snapshot.
  - `createdAt` (string<date-time>, required)
  - `updatedAt` (string<date-time>, required)

### 400

A test-mode key.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 401

Unauthorized.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 402

`paid_plan_required`, `insufficient_balance` or `spend_cap_reached`, as on create.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 403

`plan_limit_reached`: 10 sandboxes are already starting or running.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 404

Sandbox not found, or it belongs to another project.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 409

`sandbox_not_ready`: the source is not running or stopped. `sandbox_ephemeral`: an ephemeral sandbox's disk is never saved, so it cannot be copied.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 429

`daily_limit_exceeded`: 200 starts today.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

### 503

`sandbox_unavailable`: no capacity right now. The start fee is returned.

- `code` (string, required)
- `message` (string, required)
- `details` (object)

## Example

```bash
curl -X POST "https://api.zavu.dev/v1/sandboxes/sandbox_abc123/fork" \
  -H "Authorization: Bearer $ZAVUDEV_API_KEY"
```

```typescript
import Zavudev from "@zavudev/sdk";

const zavu = new Zavudev({ apiKey: process.env.ZAVUDEV_API_KEY });

const result = await zavu.sandboxes.fork("sandbox_abc123");

console.log(result);
```
