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

# Deployments

A deployment turns contracts into machines: `gpus` of a BASIS contract paired with `gpus` of the GPU contract for the same GPU and month. While it is open both sets of contracts are **locked**: they can't be sold. Ops claims the request, and the machines are provisioned on Northflank, our hosting partner: a JupyterLab notebook on CUDA by default, or a public image you name, with the ports you ask to reach. Their addresses appear on the deployment once it is running. Where Northflank cannot run the configuration, ops provisions by hand and sends access by email.

Only the **current month** can be deployed. Later months trade but wait for their month.

## Request a deployment

`POST /api/v1/compute/deployments` · scope `trade`

| Field | Type | Description |
| - | - | - |
| `basis_symbol` | string | The provider's contract, e.g. `BBA-10-26`. |
| `gpu_symbol` | string | The GPU contract for the same GPU and month, e.g. `H100SXM-10-26`. |
| `gpus` | integer | How many GPUs. You need this many free contracts on **both** books. |
| `image` | string | Optional. A public container image to run instead of the default notebook. |
| `ports` | array | Optional. 1 to 8 of `{ "port", "protocol" }` (`http` or `tcp`) to reach; the notebook's port 8888 when absent. HTTP ports get a public address; TCP ports are reached through the Northflank CLI. |
| `env` | array | Optional. Up to 32 `{ "name", "value" }` environment variables for the image. They are passed to the machines and not stored. |

```bash REST theme={null}
curl -X POST "$CAPITALAI_API_URL/api/v1/compute/deployments" \
  -H "Authorization: Bearer $CAPITALAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"basis_symbol": "BBA-10-26", "gpu_symbol": "H100SXM-10-26", "gpus": 8}'
```

```ts TypeScript theme={null}
const res = await fetch(`${process.env.CAPITALAI_API_URL}/api/v1/compute/deployments`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CAPITALAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ basis_symbol: 'BBA-10-26', gpu_symbol: 'H100SXM-10-26', gpus: 8 }),
});
console.log(await res.json());
```

`200` with the deployment:

```json theme={null}
{
  "id": "dep_7f3a",
  "basis_symbol": "BBA-10-26",
  "gpu_symbol": "H100SXM-10-26",
  "gpus": 8,
  "status": "requested",
  "ends_at": "2026-11-01T00:00:00+00:00",
  "created_at": "2026-10-21T18:40:12+00:00",
  "activated_at": null,
  "ended_at": null,
  "ops_note": null,
  "parent_id": null,
  "url": null,
  "image": "quay.io/jupyter/pytorch-notebook:cuda12-latest",
  "ports": [{ "port": 8888, "protocol": "http" }],
  "northflank": null
}
```

`url` is the first HTTP port's address and each port gains its `url` once the deployment is `active`. `northflank` names the project and service for the Northflank CLI once you are a member of the project.

Refusals are `400` with a `code` and the `field` it concerns:

| `code` | Field | Meaning |
| - | - | - |
| `unknown_basis` | `basis_symbol` | No such BASIS contract. |
| `month_over` | `basis_symbol` | The month has ended. |
| `not_current_month` | `basis_symbol` | Only the current month deploys. |
| `unknown_gpu_contract` | `gpu_symbol` | No such GPU contract. |
| `gpu_mismatch` | `gpu_symbol` | Not the same GPU and month as the basis. |
| `invalid_gpus` | `gpus` | Fewer than one. |
| `not_whole_contracts` | `gpus` | The books do not deliver whole GPUs for that count. |
| `basis_not_free`, `gpu_not_free` | `gpus` | You don't hold that many free contracts on that book. Cancel a resting sell, or buy more. |

`503` when the exchange is unreachable.

## Status

| `status` | Meaning | Contracts |
| - | - | - |
| `requested` | You asked; ops hasn't claimed it. You can still cancel it. | locked |
| `provisioning` | Ops is setting up the machines. | locked |
| `active` | The GPUs are running and their addresses are set. `activated_at` is set. | locked |
| `ending` | You stopped it, or the month ended; ops is tearing it down. | locked until `ended` |
| `ended` | Done: cancelled before a claim, torn down, or the month ended unclaimed. `ended_at` is set. | released |

Ending a deployment releases its contracts; it does not consume them. They stay in your account and can be sold or deployed again while their month lasts. Deployments that are ending, or whose month is over, are torn down by a job that runs every ten minutes.

`ops_note` carries anything ops wrote for you, such as how access was sent.

## Stop a deployment

`POST /api/v1/compute/deployments/{id}/end` · scope `trade`

Stops all of the deployment's GPUs, or `gpus` of them.

| Field | Type | Description |
| - | - | - |
| `gpus` | integer | Optional. How many to stop, from 1 to all. Absent: all. |

```bash REST theme={null}
curl -X POST "$CAPITALAI_API_URL/api/v1/compute/deployments/dep_7f3a/end" \
  -H "Authorization: Bearer $CAPITALAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"gpus": 4}'
```

```ts TypeScript theme={null}
const res = await fetch(`${process.env.CAPITALAI_API_URL}/api/v1/compute/deployments/dep_7f3a/end`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.CAPITALAI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ gpus: 4 }),
});
console.log(await res.json());
```

`200` with **the deployment of the GPUs stopped**. Stopping some of them splits those GPUs into a deployment of their own, with `parent_id` pointing at the one that keeps the rest, so ops tears down exactly those machines.

* A `requested` deployment ends at once (`ended`): nothing was provisioned.
* A claimed one goes to `ending` until ops has torn it down.

| Status | Meaning |
| - | - |
| `400` `invalid_gpus` | Fewer than one, or more than the deployment has. |
| `404` | No such deployment on your account. |
| `409` | The deployment has already ended. |

## List your deployments

`GET /api/v1/compute/deployments` is what the Compute page's **Active Capacity** table reads. It is session-only today and is coming to the API.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.