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

# Deploy Instances

> Deploy new Ubuntu VPS instances via the API

## Deploy a New Instance

> [!NOTE]
>
> The API deploys **Ubuntu VPS instances only**: plain Ubuntu servers with no application installed. To have Coolify, Dokploy, OpenClaw, Hermes Agent, or another GitHub project installed for you, use [AI Deploy](https://repocloud.io/docs/deployment/ai-deploy.md), which is not part of the API.

```
POST /api/v1/instances
```

### Request Body

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `project_name` | string | Yes | A name for your instance, 1 to 64 characters. Spaces around it are trimmed, there is no rule about the characters, and the name is kept as typed |
| `flavor` | string | Yes | The server size flavor ID: the exact lower-case text from [Available Flavors](https://repocloud.io/docs/api/deploy.md#available-flavors). Capital letters are refused |
| `ssh_public_key` | string | No | Your SSH public key. If omitted (an empty or blank value counts as omitted), a key pair is generated and the private key is returned in the response. Any other text is stored as given, with no format check, so check the key before sending |

### Example Request

```bash
curl -X POST https://repocloud.io/api/v1/instances \
  -H "Authorization: Bearer rcmcp_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "my-dev-server",
    "flavor": "s-2vcpu-4gb",
    "ssh_public_key": "ssh-ed25519 AAAA... user@host"
  }'
```

### Response (202 Accepted)

The instance is created asynchronously. The response includes connection credentials and a `status` field that starts as `pending`. The first hour is charged when the 202 arrives (your balance drops by one hour of the tier), and it is refunded if the deployment fails.

```json
{
  "instance_id": 456,
  "vps_id": "vps-a1b2c3",
  "status": "pending",
  "ipv4": "203.0.113.42",
  "domain": "vps-a1b2c3.vps.rcld.dev",
  "custom_domain": null,
  "root_user": "root",
  "root_password": "generated-password-here",
  "ssh_port": 22,
  "ssh_key": {
    "name": "api-my-dev-server",
    "fingerprint": "SHA256:xxxx...",
    "public_key": "ssh-ed25519 AAAA...",
    "private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n..."
  },
  "plan": {
    "flavor": "s-2vcpu-4gb",
    "vcpu": 2,
    "ram_mb": 4096,
    "disk_gb": 40,
    "hourly_price": 0.0167
  },
  "created_at": "2026-07-15T10:30:00"
}
```

The `created_at` time is UTC with no zone suffix and may carry fractional seconds.

> [!NOTE]
>
> The `ssh_key.private_key` field is only included when RepoCloud generated the key, that is, when you do **not** provide your own `ssh_public_key`; a key you supplied gives the other three fields only. Store the private key securely: no later API call returns it. A readiness email, "Your Ubuntu VPS Instance is Ready!", also goes to your account address when the server comes Online.

### Polling for Readiness

After deploying, poll the [instance detail endpoint](https://repocloud.io/docs/api/instances.md#get-instance-detail) until `status` is `active`. Before that it reads `pending`, then `provisioning`:

```bash
curl https://repocloud.io/api/v1/instances/456 \
  -H "Authorization: Bearer rcmcp_your_key_here"
```

Provisioning usually takes a few minutes. Once `status` is `active` and `ipv4` is populated, the server is ready for SSH connections. The list shows RepoCloud's own words instead, `Deploying` and then `Online`, and the detail answer uses them only when the control plane cannot be read.

Stop polling on `failed` or on a 404. A server that fails to deploy is removed from your account within a couple of minutes: the first hour is refunded, an email says so, and the instance id then answers 404 `Instance not found` on every API route.

## Available Flavors

| Flavor ID | vCPU | RAM | SSD | Hourly | Per month (720 hours) |
|-----------|------|-----|-----|--------|-----------------------|
| `s-1vcpu-2gb` | 1 | 2 GB | 30 GB | $0.0083 | $6.00 |
| `s-2vcpu-2gb` | 2 | 2 GB | 40 GB | $0.0125 | $9.00 |
| `s-2vcpu-4gb` | 2 | 4 GB | 40 GB | $0.0167 | $12.00 |
| `s-4vcpu-8gb` | 4 | 8 GB | 80 GB | $0.0333 | $24.00 |
| `s-8vcpu-16gb` | 8 | 16 GB | 160 GB | $0.0667 | $48.00 |
| `s-16vcpu-32gb` | 16 | 32 GB | 320 GB | $0.1333 | $96.00 |

> [!WARNING]
>
> The `s-1vcpu-1gb` flavor ($3/month) is **not available** for VPS instances. The smallest VPS tier is Tier 2 (`s-1vcpu-2gb`, $6 a month); the $3 tier is the Container Apps starter tier.

## Error Responses

| Status | Error | Cause |
|--------|-------|-------|
| 400 | `project_name is required` | Missing or empty `project_name` |
| 400 | `project_name must be 64 characters or fewer` | Name exceeds 64 characters |
| 400 | `flavor is required` | Missing or empty `flavor` |
| 400 | `Invalid flavor: xxx` | Unrecognized flavor ID (capital letters are refused too), or an elastic or premium flavor |
| 400 | `Flavor xxx is permanently unavailable for Ubuntu VPS` | The `s-1vcpu-1gb` flavor cannot be used for VPS |
| 400 | `Bad request` | The VPS control plane refused the request; `detail` holds its text |
| 402 | `Insufficient balance` | Account balance is $3 or less. The answer also carries `detail` and your current `balance`. Deposit at [/billing](https://repocloud.io/billing) |
| 404 | `Not found` | The VPS control plane could not find something the request needs; `detail` holds its text |
| 409 | `Conflict` | The VPS control plane reports a conflict; `detail` holds its text |
| 500 | `Internal server error` | An unexpected fault |
| 502 | `Upstream error` | The VPS control plane answered with any other error — retry after a few seconds |
| 503 | `VPS capacity exhausted` | No IPv4 addresses are currently available |
| 503 | `Tier capacity exhausted` | The selected flavor has no available capacity; `detail` holds the reason |

Authentication errors (401 and 403) and rate limit errors (429) are described on the [Authentication](https://repocloud.io/docs/api/authentication.md) page.

## Connecting to Your Instance

Once `status` is `active` (`Online` in the list), connect with the `ipv4` of the answer. The address below is a documentation address, not a real one:

```bash
ssh root@203.0.113.42
```

Use the root password from the deploy response, or the SSH key you provided or received. The detail answer always carries the current root password, so read it again if the password was reset; the list serves the stored copy.
