# create api-key Source: https://docs.vast.ai/api-reference/accounts/create-api-key /api-reference/openapi.yaml post /api/v0/auth/apikeys Creates a new API key with specified permissions for the authenticated user. CLI Usage: `vastai create api-key --name --permission_file [--key_params ]` # create env-var Source: https://docs.vast.ai/api-reference/accounts/create-env-var /api-reference/openapi.yaml post /api/v0/secrets Creates a new encrypted environment variable for the authenticated user. Keys are automatically converted to uppercase. Values are encrypted before storage. There is a limit on the total number of environment variables per user. CLI Usage: `vastai create env-var ` # create ssh-key Source: https://docs.vast.ai/api-reference/accounts/create-ssh-key /api-reference/openapi.yaml post /api/v0/ssh Creates a new SSH key and associates it with your account. The key will be automatically added to all your current instances. CLI Usage: `vastai create ssh-key ` # create subaccount Source: https://docs.vast.ai/api-reference/accounts/create-subaccount /api-reference/openapi.yaml post /api/v0/users Creates either a standalone user account or a subaccount under a parent account. Subaccounts can be restricted to host-only functionality. CLI Usage: `vastai create subaccount --email --username --password [--type host]` # delete api key Source: https://docs.vast.ai/api-reference/accounts/delete-api-key /api-reference/openapi.yaml delete /api/v0/auth/apikeys/{id} Deletes an existing API key belonging to the authenticated user. The API key is soft-deleted by setting a deleted_at timestamp. CLI Usage: `vastai delete api-key ` # delete env var Source: https://docs.vast.ai/api-reference/accounts/delete-env-var /api-reference/openapi.yaml delete /api/v0/secrets Deletes an environment variable associated with the authenticated user. The variable must exist and belong to the requesting user. CLI Usage: `vastai delete env-var ` # delete ssh key Source: https://docs.vast.ai/api-reference/accounts/delete-ssh-key /api-reference/openapi.yaml delete /api/v0/ssh/{id} Removes an SSH key from the authenticated user's account CLI Usage: `vastai delete ssh-key ` # set user Source: https://docs.vast.ai/api-reference/accounts/set-user /api-reference/openapi.yaml put /api/v0/users Updates the user data for the authenticated user. CLI Usage: `vastai set user --file ` # show api keys Source: https://docs.vast.ai/api-reference/accounts/show-api-keys /api-reference/openapi.yaml get /api/v0/auth/apikeys Retrieves all API keys associated with the authenticated user. CLI Usage: `vastai show api-keys` # show connections Source: https://docs.vast.ai/api-reference/accounts/show-connections /api-reference/openapi.yaml get /api/v0/users/cloud_integrations Retrieves the list of cloud connections associated with the authenticated user. CLI Usage: `vastai show connections` # show env vars Source: https://docs.vast.ai/api-reference/accounts/show-env-vars /api-reference/openapi.yaml get /api/v0/secrets Retrieve a list of environment variables (secrets) for the authenticated user. CLI Usage: `vastai show env-vars [-s]` # show ipaddrs Source: https://docs.vast.ai/api-reference/accounts/show-ipaddrs /api-reference/openapi.yaml get /api/v0/users/{user_id}/ipaddrs This endpoint retrieves the history of IP address accesses for the authenticated user. CLI Usage: `vastai show ipaddrs` # show ssh keys Source: https://docs.vast.ai/api-reference/accounts/show-ssh-keys /api-reference/openapi.yaml get /api/v0/ssh Retrieve a list of SSH keys associated with the authenticated user's account. CLI Usage: `vastai show ssh-keys` # show subaccounts Source: https://docs.vast.ai/api-reference/accounts/show-subaccounts /api-reference/openapi.yaml get /api/v0/subaccounts Retrieve a list of subaccounts associated with the authenticated user's account. CLI Usage: `vastai show subaccounts` # show user Source: https://docs.vast.ai/api-reference/accounts/show-user /api-reference/openapi.yaml get /api/v0/users/current Retrieve information about the current authenticated user, excluding the API key. CLI Usage: `vastai show user` # transfer credit Source: https://docs.vast.ai/api-reference/accounts/transfer-credit /api-reference/openapi.yaml put /api/v0/commands/transfer_credit Transfers specified amount of credits from the authenticated user's account to another user's account. The recipient can be specified by either email address or user ID. CLI Usage: `vastai transfer credit ` # update env var Source: https://docs.vast.ai/api-reference/accounts/update-env-var /api-reference/openapi.yaml put /api/v0/secrets Updates the value of an existing environment variable for the authenticated user. CLI Usage: `vastai update env-var ` # update ssh key Source: https://docs.vast.ai/api-reference/accounts/update-ssh-key /api-reference/openapi.yaml put /api/v0/ssh/{id} Updates the specified SSH key with the provided value. CLI Usage: `vastai update ssh-key ` # Authentication Source: https://docs.vast.ai/api-reference/authentication Every request to the Vast.ai API must include an API key. This page covers how to create keys, how to include them in requests, and key lifecycle details. ## Create an API Key Generate a key from the [Keys page](https://cloud.vast.ai/manage-keys/) in the web console: 1. Click **+New**. 2. Give the key a name (optional but recommended, e.g. "CI pipeline" or "notebook"). 3. Copy the key immediately, you'll only see it once. You can also create keys programmatically via the API ([Create API Key](/api-reference/accounts/create-api-key)), CLI ([`vastai create api-key`](/cli/reference/create-api-key)), or SDK ([`vast.create_api_key()`](/sdk/python/reference/create-api-key)). ## Use an API Key Include your key as a Bearer token in the `Authorization` header: ```bash cURL theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ "https://console.vast.ai/api/v0/users/current/" ``` ```python Python theme={null} import os import requests headers = {"Authorization": f"Bearer {os.environ['VAST_API_KEY']}"} resp = requests.get("https://console.vast.ai/api/v0/users/current/", headers=headers) print(resp.json()) ``` A common pattern is to store your key in an environment variable: ```bash theme={null} export VAST_API_KEY="your-api-key-here" ``` This keeps the key out of your code and makes it easy to rotate. If you get a `401 Unauthorized` or `403 Forbidden` response, double-check your API key. The most common causes are a typo, an expired key, or a scoped key that lacks the required permission for the endpoint you're calling. ## Verify Your Key A quick way to confirm your key works is to fetch your account info: ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ "https://console.vast.ai/api/v0/users/current/" ``` A successful response includes your user ID, email, balance, and SSH key: ```json theme={null} { "id": 123456, "email": "you@example.com", "credit": 25.00, "ssh_key": "ssh-rsa AAAAB3..." } ``` ## Scoped Keys and Permissions By default, the web console creates a **full-access** key. For CI/CD pipelines, shared tooling, or team environments, you should create **scoped keys** that restrict access to only the permissions you need. For example, a key that can only read and manage instances (but cannot access billing): ```json theme={null} { "api": { "misc": {}, "user_read": {}, "instance_read": {}, "instance_write": {} } } ``` See the [Permissions](/api-reference/permissions) page for the full list of permission categories, endpoint mappings, constraint syntax, and advanced examples. ## Key Expiration API keys do not expire by default. You can revoke a key at any time from the [Keys page](https://cloud.vast.ai/manage-keys/) or by calling the [Delete API Key](/api-reference/accounts/delete-api-key) endpoint. Treat your API key like a password. Do not commit keys to version control or share them in plaintext. If a key is compromised, revoke it immediately and create a new one. # show charges Source: https://docs.vast.ai/api-reference/billing/show-charges /api-reference/openapi.yaml get /api/v0/charges Shows charges per instance, including GPU, storage, and bandwidth. For invoice/payment records (Stripe top-ups, transfers, payouts), use [show invoices](/api-reference/billing/show-invoices) instead. CLI: `vastai show invoices-v1 --charges` # show deposit Source: https://docs.vast.ai/api-reference/billing/show-deposit /api-reference/openapi.yaml get /api/v0/instances/balance/{id} Retrieves the deposit details for a specified instance. CLI Usage: `vastai show deposit ` # show earnings Source: https://docs.vast.ai/api-reference/billing/show-earnings /api-reference/openapi.yaml get /api/v0/users/{user_id}/machine-earnings Retrieves the earnings history for a specified time range and optionally per machine. CLI Usage: `vastai show earnings [options]` # show invoices Source: https://docs.vast.ai/api-reference/billing/show-invoices /api-reference/openapi.yaml get /api/v1/invoices Returns Stripe top-ups, transfers, payouts, coinbase payments, and other billing transactions. For per-instance cost breakdowns, use [show charges](/api-reference/billing/show-charges) instead. CLI: `vastai show invoices-v1 --invoices` # Creating and Using Templates with API Source: https://docs.vast.ai/api-reference/creating-and-using-templates-with-api ## Introduction A **template** in the Vast.ai API is a configuration bundle that stores default settings for instance creation. Instead of specifying every parameter each time you create an instance, you can reference a template by its `hash_id` and optionally override specific values. Templates are useful for: * **Standardization**: Ensure all team members launch instances with consistent configurations * **Convenience**: Avoid repeating the same parameters across multiple API calls * **Sharing**: Share configurations via template hash ID For information about managing templates in the web interface, see [Templates Introduction](/guides/templates/introduction). ## Template Fields Reference When creating a template, the following fields can be configured: | Field | Type | Description | | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------- | | `name` | string | **Required**. Human-readable name for the template | | `image` | string | **Required**. Docker image path (e.g., `vastai/pytorch`) | | `tag` | string | Docker image tag. Defaults to `latest` | | `desc` | string | Description of the template | | `readme` | string | Longer documentation/readme content | | `env` | string | Environment variables and port mappings in Docker flag format (e.g., `"-e VAR=val -p 8000:8000"`) | | `onstart` | string | Shell commands to run when instance starts | | `runtype` | string | Launch mode: `ssh`, `jupyter`, or `args`. Defaults to `args` | | `args_str` | string | Replaces the image's Docker `CMD`. If the image defines an `ENTRYPOINT`, this is passed as arguments to it | | `ssh_direct` | boolean | Enable direct SSH connection (recommended with `runtype: "ssh"`) | | `use_ssh` | boolean | Enable SSH access | | `jup_direct` | boolean | Enable direct Jupyter connection | | `jupyter_dir` | string | Directory to launch Jupyter from | | `use_jupyter_lab` | boolean | Use JupyterLab instead of Jupyter Notebook | | `docker_login_repo` | string | **Required** (use `""` if not needed). Private Docker registry URL | | `docker_login_user` | string | **Required** (use `""` if not needed). Username for private registry | | `docker_login_pass` | string | **Required** (use `""` if not needed). Access token for private registry | | `href` | string | Link to Docker Hub or image documentation | | `repo` | string | Repository identifier (e.g., `library/ubuntu`) | | `extra_filters` | object | Default machine search filters (e.g., `{"cuda_max_good": {"gte": 12.6}}`) | | `recommended_disk_space` | number | Recommended disk space in GB (default: 8) | | `private` | boolean | Whether the template is private | | `volume_info` | object | UI hint for volume configuration (not used for actual instance creation) | ## Template Identifiers Templates have two primary identifiers: | Identifier | Type | Description | | ---------- | ------- | --------------------------------------------------------------------- | | `id` | integer | Numeric identifier. Used for deleting templates | | `hash_id` | string | Content-based hash. Used for creating instances and editing templates | **Usage by operation:** * **Create instance**: Use `template_hash_id` * **Edit template**: Use `hash_id` (via PUT) * **Delete template**: Use numeric `id` ## Precedence Rules When you create an instance with both a template and additional parameters, the following precedence rules apply: | Field Type | Behavior | | ---------------------------------------------- | ---------------------------------------------------------------------------------------------- | | **Scalar fields** (image, disk, runtype, etc.) | Request value **overrides** template value | | **`env`** (dict) | **Merged**. Template values retained, request values added. Conflicting keys use request value | | **`extra_filters`** (dict) | **Merged** by key. Request values win on conflicts | ### Example: Environment Variables When creating an instance, the `env` field is passed as a JSON object (dict). When you provide `env` in your request, it is merged with the template's `env`, existing values are retained and new values are added. Templates store `env` as a Docker flag string (e.g., `"-e VAR=val -p 8000:8000"`), but instance creation uses a dict format. The API handles the conversion automatically when merging. **Template configuration** (string format): ```json theme={null} { "env": "-e MODEL_ID=deepseek-ai/DeepSeek-R1-Distill-Llama-8B -e MAX_TOKENS=4096" } ``` **Instance creation request** (dict format): ```json theme={null} { "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "env": { "MODEL_ID": "mistralai/Mistral-7B-v0.1", "HF_TOKEN": "hf_xxx" } } ``` **Resulting instance environment:** * `MODEL_ID=mistralai/Mistral-7B-v0.1` (request overrides template) * `MAX_TOKENS=4096` (retained from template) * `HF_TOKEN=hf_xxx` (added from request) ## Cookbook Examples ### Search for Templates Search for templates using `select_filters` with comparison operators. **Query Syntax:** ``` select_filters = { "field": { "op": value } } ``` **Operators:** `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`, `notin` **Available Fields:** | Field | Type | Description | | ------------------------ | ------ | --------------------------------------------- | | `creator_id` | int | ID of creator | | `created_at` | float | Time of initial template creation (UTC epoch) | | `count_created` | int | Number of instances created (popularity) | | `default_tag` | string | Image default tag | | `docker_login_repo` | string | Image docker repository | | `id` | int | Template unique ID | | `image` | string | Image used for template | | `jup_direct` | bool | Supports jupyter direct | | `hash_id` | string | Unique hash ID of template | | `name` | string | Displayable name | | `recent_create_date` | float | Last time of instance creation (UTC epoch) | | `recommended_disk_space` | float | Min disk space required | | `recommended` | bool | Is template on recommended list | | `ssh_direct` | bool | Supports SSH direct | | `tag` | string | Image tag | | `use_ssh` | bool | Supports SSH (direct or proxy) | ```bash curl theme={null} # Search for recommended templates with SSH support curl -G "https://console.vast.ai/api/v0/template/" \ -H "Authorization: Bearer $VAST_API_KEY" \ --data-urlencode 'select_filters={"use_ssh":{"eq":true},"recommended":{"eq":true}}' # Search for popular templates (more than 100 instances created) curl -G "https://console.vast.ai/api/v0/template/" \ -H "Authorization: Bearer $VAST_API_KEY" \ --data-urlencode 'select_filters={"count_created":{"gt":100}}' ``` ```python Python theme={null} import requests import json api_key = "your_api_key" # Search for recommended templates with SSH support select_filters = { "use_ssh": {"eq": True}, "recommended": {"eq": True} } response = requests.get( "https://console.vast.ai/api/v0/template/", headers={"Authorization": f"Bearer {api_key}"}, params={"select_filters": json.dumps(select_filters)} ) result = response.json() for template in result.get("templates", []): print(f"Hash ID: {template['hash_id']}, Name: {template['name']}") # Search for popular templates by specific creators select_filters = { "count_created": {"gt": 100}, "creator_id": {"in": [38382, 48982]} } response = requests.get( "https://console.vast.ai/api/v0/template/", headers={"Authorization": f"Bearer {api_key}"}, params={"select_filters": json.dumps(select_filters)} ) ``` ### Create a New Template Create a reusable template. This example shows a recommended configuration with SSH direct access. ```bash curl theme={null} curl -X POST "https://console.vast.ai/api/v0/template/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Example Template", "desc": "Template for running vLLM inference server", "image": "vllm/vllm-openai", "tag": "latest", "env": "-e MODEL_ID=deepseek-ai/DeepSeek-R1-Distill-Llama-8B -p 8000:8000", "onstart": "echo \"Starting vLLM server\"; vllm serve $MODEL_ID", "runtype": "ssh", "ssh_direct": true, "use_ssh": true, "docker_login_repo": "", "docker_login_user": "", "docker_login_pass": "", "recommended_disk_space": 50, "private": true }' ``` ```python Python theme={null} import requests api_key = "your_api_key" response = requests.post( "https://console.vast.ai/api/v0/template/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "name": "Example Template", "desc": "Template for running vLLM inference server", "image": "vllm/vllm-openai", "tag": "latest", "env": "-e MODEL_ID=deepseek-ai/DeepSeek-R1-Distill-Llama-8B -p 8000:8000", "onstart": 'echo "Starting vLLM server"; vllm serve $MODEL_ID', "runtype": "ssh", "ssh_direct": True, "use_ssh": True, "docker_login_repo": "", "docker_login_user": "", "docker_login_pass": "", "recommended_disk_space": 50, "private": True } ) result = response.json() print(f"Template ID: {result['template']['id']}") print(f"Hash ID: {result['template']['hash_id']}") ``` ### Full Template Example Here's a complete template creation request with all common fields: ```json theme={null} { "name": "Example Template", "desc": "Description of what this template does", "readme": "Longer documentation\nwith multiple lines", "image": "library/ubuntu", "tag": "22.04", "repo": "library/ubuntu", "href": "https://hub.docker.com/r/library/ubuntu/", "env": "-e ENV1=val1 -p 8000:8000", "onstart": "echo \"hello\"", "args_str": "", "runtype": "ssh", "ssh_direct": true, "use_ssh": true, "jup_direct": true, "jupyter_dir": null, "use_jupyter_lab": false, "docker_login_repo": "", "docker_login_user": "", "docker_login_pass": "", "extra_filters": {"cuda_max_good": {"gte": 12.6}}, "recommended_disk_space": 8, "private": true, "volume_info": null } ``` ### Edit a Template Edit an existing template using its `hash_id`. You only need to include the fields you want to change - unchanged fields retain their existing values. ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/template/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "hash_id": "5915f1dc1ce881defb572015eb9d8178", "desc": "Updated description", "recommended_disk_space": 16 }' ``` ```python Python theme={null} import requests api_key = "your_api_key" # Edit template - only include fields you want to change response = requests.put( "https://console.vast.ai/api/v0/template/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "hash_id": "5915f1dc1ce881defb572015eb9d8178", "desc": "Updated description", "recommended_disk_space": 16 } ) result = response.json() print(f"Updated template: {result['template']['hash_id']}") ``` The `hash_id` will change after editing since it is derived from the template content. ### Delete a Template Delete a template by passing its numeric `id` (not `hash_id`) in the request body. ```bash curl theme={null} curl -X DELETE "https://console.vast.ai/api/v0/template/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{"template_id": 334548}' ``` ```python Python theme={null} import requests api_key = "your_api_key" response = requests.delete( "https://console.vast.ai/api/v0/template/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={"template_id": 334548} # Numeric ID, not hash_id ) result = response.json() print(f"Deleted: {result.get('success')}") ``` ### Create Instance from Template Launch an instance using a template. No need to specify `image` as the template provides it. ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f" } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ### Create Instance with Image Override Use a template but specify a different Docker image. ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "image": "library/ubuntu:22.04" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "image": "nvidia/cuda:12.1-devel-ubuntu22.04" } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ### Override Environment Variables Override template environment variables with new values. Instance creation uses the dict format for `env`. ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "env": {"MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.2", "HF_TOKEN": "hf_xxxYourTokenHere", "-p 8000:8000": "1"} }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "env": { "MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.2", "HF_TOKEN": "hf_xxxYourTokenHere", "-p 8000:8000": "1" } } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ### Create Instance with Volume Attach a volume when creating an instance. You can either link an existing volume or create a new one. The `volume_info` field stored in templates is a UI hint only. To actually attach a volume, you must include `volume_info` in the instance creation request. **Link an existing volume:** ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "volume_info": { "create_new": false, "volume_id": 12345, "mount_path": "/workspace" } }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 # Link an existing volume (get volume_id from "vastai show volumes") response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "volume_info": { "create_new": False, "volume_id": 12345, # Existing volume ID "mount_path": "/workspace" } } ) ``` **Create a new volume:** ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "volume_info": { "create_new": true, "volume_id": 28908979, "size": 10, "mount_path": "/workspace" } }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 # Create a new volume (get volume_id from "vastai search volumes") response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "volume_info": { "create_new": True, "volume_id": 28908979, # Volume offer ID from search "size": 10, # Size in GB "mount_path": "/workspace" } } ) ``` **CLI equivalent:** ```bash theme={null} # Link existing volume vastai create instance 12345678 --template_hash abc123 --link-volume 12345 --mount-path /workspace # Create new volume vastai create instance 12345678 --template_hash abc123 --create-volume 28908979 --volume-size 10 --mount-path /workspace ``` ## CLI Reference The Vast.ai CLI provides commands for template management: | Command | Description | | ---------------------------------------------------------------- | ------------------------------------- | | `vastai create template --name --image [options]` | Create a new template | | `vastai search templates [filters]` | Search for templates | | `vastai update template [options]` | Update a template (uses `hash_id`) | | `vastai delete template --template-id ` | Delete a template (uses numeric `id`) | **Create template options:** * `--name NAME` - Template name * `--image IMAGE` - Docker image * `--image_tag TAG` - Image tag * `--env ENV` - Docker options (env vars and ports) * `--ssh` - Launch as SSH instance * `--jupyter` - Launch as Jupyter instance * `--direct` - Use direct connections * `--onstart-cmd CMD` - Onstart script * `--disk_space GB` - Disk space in GB * `--desc DESC` - Description * `--readme README` - Readme content * `--public` - Make template public The CLI `update template` command takes `hash_id` as its argument, while `delete template` uses the numeric `id`. ## Runtype and Connection Options The `runtype` field controls the launch mode of your instance: | Runtype | Description | | --------- | -------------------------------------------------------------------------------------------------- | | `args` | Default. `args_str` replaces the image's `CMD` and is passed to its `ENTRYPOINT` if one is defined | | `ssh` | SSH access enabled. **Recommended** with `ssh_direct: true` | | `jupyter` | Jupyter notebook/lab access | **Recommendation**: Use `runtype: "ssh"` with `ssh_direct: true` and `use_ssh: true` for reliable SSH access to your instances. The `args_str` field is used when `runtype` is `args`. It replaces the image's Docker `CMD`, if the image defines an `ENTRYPOINT`, `args_str` is passed as arguments to it. If the image has no `ENTRYPOINT` (only `CMD`), `args_str` replaces the command entirely. ```json theme={null} { "runtype": "args", "args_str": "--model deepseek-ai/DeepSeek-R1-Distill-Llama-8B --port 8000" } ``` ## Common Pitfalls Instance creation requires `template_hash_id`, not `template_id`. The numeric `id` is only used for deleting templates. Use the `hash_id` returned when you create or search for templates: ```json theme={null} { "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f" } ``` When you specify both `template_hash_id` and `image`, the **request's image overrides** the template's image. If you want to use the template's image, omit the `image` field from your request. Template creation and instance creation use **different formats** for the `env` field: * **Templates**: Docker flag string format, `"-e VAR1=value1 -e VAR2=value2 -p 8000:8000"` * **Instance creation**: Dict format, `{"VAR1": "value1", "VAR2": "value2", "-p 8000:8000": "1"}` When creating an instance with a template, the request `env` (dict) is merged with the template `env`, existing keys are overwritten, new keys are added. When creating instances, port mappings are specified in the `env` dict using the `-p` syntax as keys: ```json theme={null} { "env": { "-p 8000:8000": "1", "-p 8080:8080": "1" } } ``` For SSH access, use `runtype: "ssh"` with `ssh_direct: true`. Volume mounting uses the `volume_info` structure in the instance creation request. Note that `volume_info` in templates is just a UI hint and doesn't affect instance creation. **To link an existing volume:** ```json theme={null} { "volume_info": { "create_new": false, "volume_id": 12345, "mount_path": "/workspace" } } ``` **To create a new volume:** ```json theme={null} { "volume_info": { "create_new": true, "volume_id": 28908979, "size": 10, "mount_path": "/workspace" } } ``` Where: * `volume_id` is either an existing volume ID (from `show volumes`) or a volume offer ID (from `search volumes`) * `size` is only used when `create_new` is true * `mount_path` is where the volume mounts inside the container Template search uses `select_filters` with comparison operators, not free-text search: * Use the correct filter syntax: `{"field": {"op": value}}` * Valid operators: `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`, `notin` * Verify your API key has `user_read` permissions * Check available fields in the search documentation above ## Related Resources Web interface guide for templates Full API reference for instance creation Command-line interface for templates Find available machines to rent # Creating Instances with the API Source: https://docs.vast.ai/api-reference/creating-instances-with-api ## Introduction Instance creation on Vast.ai follows a two-step process: first **find an offer** (an available machine), then **accept that offer** to create an instance. You can configure instances in two ways: * **Directly**: Pass all configuration (image, environment variables, launch mode, etc.) in the instance creation request * **From a template**: Reference a pre-configured template by its `hash_id`, optionally overriding specific values Both approaches use the same endpoint: `PUT /api/v0/asks/{offer_id}/`. For information about creating and managing templates, see [Creating and Using Templates with API](/api-reference/creating-and-using-templates-with-api). ## Instance Creation Fields Reference When creating an instance, the following fields can be configured: | Field | Type | Required | Description | | ------------------ | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `image` | string | Yes\* | Docker image path (e.g., `vllm/vllm-openai`). \*Optional when using a template | | `template_hash_id` | string | No | Template hash ID to use as base configuration | | `label` | string | No | Custom name for the instance | | `disk` | number | No | Local disk partition size in GB (default: 8) | | `runtype` | string | No | Launch mode. SSH/Jupyter runtypes replace the image entrypoint with Vast's entrypoint; `args` preserves it. See [Runtype and Connection Options](#runtype-and-connection-options) | | `target_state` | string | No | Initial state: `running` (default) or `stopped` | | `price` | number | No | Bid price in \$/hour (for interruptible instances only) | | `env` | object | No | Environment variables and port mappings as a JSON object (e.g., `{"VAR": "val", "-p 8000:8000": "1"}`) | | `onstart` | string | No | Shell commands to run after Vast's entrypoint initializes. Used with SSH/Jupyter runtypes to start your application | | `args_str` | string | No | Replaces the image's Docker `CMD`. If the image defines an `ENTRYPOINT`, `args_str` is passed as arguments to it. Only used with `runtype: "args"` | | `use_jupyter_lab` | boolean | No | Use JupyterLab instead of Jupyter Notebook | | `jupyter_dir` | string | No | Directory to launch Jupyter from | | `python_utf8` | boolean | No | Set Python locale to C.UTF-8 | | `lang_utf8` | boolean | No | Set locale to C.UTF-8 | | `image_login` | string | No | Docker registry credentials for private images (eg., `-u username -p access_token docker.io`) | | `cancel_unavail` | boolean | No | Cancel if instance cannot start immediately | | `vm` | boolean | No | Create a VM instance instead of a container | | `volume_info` | object | No | Volume creation or linking configuration | ## Step 1: Find an Offer Before creating an instance, search for available machines that match your requirements. ```bash curl theme={null} # Search for machines with at least 1 RTX 4090, reliability > 99% curl -X POST "https://console.vast.ai/api/v0/bundles/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "reliability": {"gte": 0.99}, "verified": {"eq": true}, "rentable": {"eq": true}, "type": "ondemand", "limit": 5 }' ``` ```python Python theme={null} import requests api_key = "your_api_key" response = requests.post( "https://console.vast.ai/api/v0/bundles/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "reliability": {"gte": 0.99}, "verified": {"eq": True}, "rentable": {"eq": True}, "type": "ondemand", "limit": 5 } ) offers = response.json().get("offers", []) for offer in offers: print(f"ID: {offer['id']}, GPUs: {offer['num_gpus']}x {offer['gpu_name']}, " f"${offer['dph_total']:.3f}/hr") ``` The offer `id` returned from search is the value you pass as `{offer_id}` in the instance creation endpoint. ## Step 2: Create the Instance ### Option A: Create Instance Directly (No Template) Pass all configuration parameters directly in the request. At minimum, you must provide the `image` field. **Simple example**, create an SSH instance with Ubuntu: ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct" } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` **Full example**, SSH instance running a vLLM inference server: ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "vllm/vllm-openai:latest", "label": "vllm-inference-server", "disk": 50, "runtype": "ssh_direct", "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "HF_TOKEN": "hf_xxxYourTokenHere", "-p 8000:8000": "1"}, "onstart": "vllm serve $MODEL_ID --port 8000" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "image": "vllm/vllm-openai:latest", "label": "vllm-inference-server", "disk": 50, "runtype": "ssh_direct", "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "HF_TOKEN": "hf_xxxYourTokenHere", "-p 8000:8000": "1"}, "onstart": "vllm serve $MODEL_ID --port 8000" } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ### Option B: Create Instance from a Template Reference a template by its `hash_id`. The template provides default values for all configuration fields, so you don't need to specify `image` or other parameters unless you want to override them. **Basic template usage**, all configuration comes from the template: ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f" } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` **Template with overrides**, use a template but customize specific values: ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "label": "custom-inference-server", "disk": 100, "env": {"MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.2", "HF_TOKEN": "hf_xxxYourTokenHere"} }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "template_hash_id": "4e17788f74f075dd9aab7d0d4427968f", "label": "custom-inference-server", "disk": 100, "env": {"MODEL_ID": "mistralai/Mistral-7B-Instruct-v0.2", "HF_TOKEN": "hf_xxxYourTokenHere"} } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ## Runtype and Connection Options The `runtype` field controls how you connect to your instance: | Runtype | Auto-provisioned Ports | Description | | ---------------- | ------------------------- | ------------------------------------------------------------------------------------------------- | | `ssh_direct` | 22 (SSH) | Direct SSH connection. Port 22 is provisioned on the instance | | `ssh_proxy` | None | SSH via Vast.ai proxy. No ports provisioned on the instance | | `ssh` | None | Alias for `ssh_proxy` | | `jupyter_direct` | 8080 (Jupyter) + 22 (SSH) | **Recommended**. Direct Jupyter and SSH access. Ports 8080 and 22 are provisioned on the instance | | `jupyter_proxy` | None | Jupyter and SSH via Vast.ai proxy. No ports provisioned on the instance | | `jupyter` | None | Alias for `jupyter_proxy` | | `args` | None | Container runs with the original entrypoint and `args_str` appended. No SSH/Jupyter | All Jupyter runtypes **implicitly include SSH access**. Only the `_direct` runtypes provision ports on the instance itself, `jupyter_direct` provisions ports 8080 and 22, while `ssh_direct` provisions port 22. Proxy runtypes route connections through Vast.ai's infrastructure without opening ports on the instance. **Recommendation**: Use `runtype: "jupyter_direct"` for the most flexibility, you get both direct Jupyter and direct SSH access with ports provisioned on the instance. Use `runtype: "ssh_direct"` if you only need SSH. ### Entrypoint Behavior How the container starts depends on the runtype: * **SSH and Jupyter runtypes**: The image's original entrypoint is **replaced** by Vast's own entrypoint, which sets up SSH/Jupyter access. Use the `onstart` field to run your own startup commands (e.g., launching a server). Your `onstart` script runs after the Vast entrypoint has initialized. * **`args` runtype**: The image's **original `ENTRYPOINT` is preserved**. The `args_str` value replaces the image's Docker `CMD`, if the image defines an `ENTRYPOINT`, `args_str` is passed as arguments to it. If the image has no `ENTRYPOINT` (only `CMD`), `args_str` replaces the command entirely. No SSH or Jupyter access is provisioned. If you use an SSH or Jupyter runtype without an `onstart` command, the container will start with only SSH/Jupyter access, your application won't run automatically. Use `onstart` to start your services. ### Runtype Examples **Jupyter Lab with SSH** (recommended), use `onstart` to start your application: ```json theme={null} { "image": "ubuntu:22.04", "disk": 16, "runtype": "jupyter_direct", "use_jupyter_lab": true, "jupyter_dir": "/workspace", "onstart": "echo 'Instance is ready'" } ``` **SSH with a vLLM server**, the server is started via `onstart`: ```json theme={null} { "image": "vllm/vllm-openai:latest", "disk": 50, "runtype": "ssh_direct", "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "-p 8000:8000": "1"}, "onstart": "vllm serve $MODEL_ID --port 8000" } ``` **Entrypoint arguments (headless)**, `args_str` replaces the image's `CMD` and is passed to its `ENTRYPOINT`: ```json theme={null} { "image": "vllm/vllm-openai:latest", "disk": 50, "runtype": "args", "args_str": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B --port 8000" } ``` ## Environment Variables and Ports When creating instances, the `env` field is a JSON object (dict). Environment variables are key-value pairs, and port mappings use the Docker `-p` syntax as keys with `"1"` as the value. ```json theme={null} { "env": { "HF_TOKEN": "hf_xxx123", "MODEL_ID": "meta-llama/Llama-3-8B", "-p 8000:8000": "1", "-p 8080:8080": "1" } } ``` When using a template, the `env` dict from your request is **merged** with the template's `env`: * Existing keys from the template are retained * New keys from the request are added * Conflicting keys use the request value See [Precedence Rules](/api-reference/creating-and-using-templates-with-api#precedence-rules) in the templates guide for full details. ## Instance Pricing ### On-Demand Instances On-demand instances use fixed pricing. Simply omit the `price` field: ```json theme={null} { "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct" } ``` ### Interruptible (Bid) Instances For lower-cost interruptible instances, set a bid price. Search with `type: "bid"` to find interruptible offers, then provide the `price` field: ```bash curl theme={null} # Search for interruptible offers curl -X POST "https://console.vast.ai/api/v0/bundles/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "verified": {"eq": true}, "rentable": {"eq": true}, "type": "bid" }' # Create interruptible instance with bid price curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct", "price": 0.20 }' ``` ```python Python theme={null} import requests api_key = "your_api_key" # Search for interruptible offers response = requests.post( "https://console.vast.ai/api/v0/bundles/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "verified": {"eq": True}, "rentable": {"eq": True}, "type": "bid" } ) offers = response.json().get("offers", []) offer_id = offers[0]["id"] # Create interruptible instance with bid price response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct", "price": 0.20 # Bid price in $/hour } ) result = response.json() print(f"Instance ID: {result.get('new_contract')}") ``` ## Attaching Volumes Attach persistent storage to your instance using the `volume_info` field. The volume must already exist, you can create volumes separately via the API or CLI before attaching them to an instance. You can list your existing volumes with `vastai show volumes` or the equivalent API call to find the `volume_id` to use. ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct", "volume_info": { "volume_id": 12345, "mount_path": "/workspace" } }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "image": "ubuntu:22.04", "disk": 16, "runtype": "ssh_direct", "volume_info": { "volume_id": 12345, # Existing volume ID from "vastai show volumes" "mount_path": "/workspace" } } ) ``` ## Using Private Docker Images If your Docker image is hosted in a private registry, provide credentials via the `image_login` field: ```bash curl theme={null} curl -X PUT "https://console.vast.ai/api/v0/asks/12345678/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "registry.example.com/my-org/my-image:latest", "image_login": "-u username -p access_token docker.io", "runtype": "ssh_direct" }' ``` ```python Python theme={null} import requests api_key = "your_api_key" offer_id = 12345678 response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "image": "registry.example.com/my-org/my-image:latest", "image_login": "-u username -p access_token docker.io", "runtype": "ssh_direct" } ) ``` When using a template with private registry credentials (`docker_login_repo`, `docker_login_user`, `docker_login_pass`), those credentials carry over to the instance automatically. ## End-to-End Example This example shows the complete workflow: searching for a machine, creating an instance, and checking its status. ```bash curl theme={null} # Step 1: Search for offers OFFERS=$(curl -s -X POST "https://console.vast.ai/api/v0/bundles/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "gpu_ram": {"gte": 24000}, "reliability": {"gte": 0.99}, "verified": {"eq": true}, "rentable": {"eq": true}, "type": "ondemand", "limit": 3 }') echo "Available offers:" echo "$OFFERS" | jq '.offers[] | {id, gpu_name, num_gpus, dph_total}' # Step 2: Create instance using the first offer OFFER_ID=$(echo "$OFFERS" | jq '.offers[0].id') RESULT=$(curl -s -X PUT "https://console.vast.ai/api/v0/asks/$OFFER_ID/" \ -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "image": "vllm/vllm-openai:latest", "label": "my-vllm-server", "disk": 50, "runtype": "ssh_direct", "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "-p 8000:8000": "1"}, "onstart": "vllm serve $MODEL_ID --port 8000" }') INSTANCE_ID=$(echo "$RESULT" | jq '.new_contract') echo "Created instance: $INSTANCE_ID" # Step 3: Check instance status curl -s "https://console.vast.ai/api/v0/instances/$INSTANCE_ID/" \ -H "Authorization: Bearer $VAST_API_KEY" | jq '{id: .instances.id, status: .instances.actual_status, label: .instances.label}' ``` ```python Python theme={null} import requests import time api_key = "your_api_key" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } # Step 1: Search for offers response = requests.post( "https://console.vast.ai/api/v0/bundles/", headers=headers, json={ "gpu_name": {"in": ["RTX 4090"]}, "num_gpus": {"gte": 1}, "gpu_ram": {"gte": 24000}, "reliability": {"gte": 0.99}, "verified": {"eq": True}, "rentable": {"eq": True}, "type": "ondemand", "limit": 3 } ) offers = response.json().get("offers", []) for offer in offers: print(f"Offer {offer['id']}: {offer['num_gpus']}x {offer['gpu_name']} " f"- ${offer['dph_total']:.3f}/hr") # Step 2: Create instance using the first offer offer_id = offers[0]["id"] response = requests.put( f"https://console.vast.ai/api/v0/asks/{offer_id}/", headers=headers, json={ "image": "vllm/vllm-openai:latest", "label": "my-vllm-server", "disk": 50, "runtype": "ssh_direct", "env": {"MODEL_ID": "deepseek-ai/DeepSeek-R1-Distill-Llama-8B", "-p 8000:8000": "1"}, "onstart": "vllm serve $MODEL_ID --port 8000" } ) result = response.json() instance_id = result.get("new_contract") print(f"\nCreated instance: {instance_id}") # Step 3: Wait and check instance status time.sleep(5) response = requests.get( f"https://console.vast.ai/api/v0/instances/{instance_id}/", headers=headers ) instance = response.json().get("instances", {}) print(f"Status: {instance.get('actual_status')}") print(f"Label: {instance.get('label')}") ``` ## CLI Reference The Vast.ai CLI provides equivalent commands for instance creation: | Command | Description | | ---------------------------------------------------------- | ---------------------------------- | | `vastai search offers ''` | Search for available machines | | `vastai create instance [options]` | Create an instance directly | | `vastai create instance --template_hash ` | Create an instance from a template | **Common create instance options:** * `--image IMAGE` - Docker image * `--template_hash HASH` - Template hash ID * `--disk GB` - Disk space in GB * `--ssh` - Launch as SSH instance * `--direct` - Use direct connections * `--jupyter` - Launch as Jupyter instance * `--jupyter-lab` - Use JupyterLab * `--env ENV` - Docker options (env vars and ports) * `--onstart-cmd CMD` - Onstart script * `--label LABEL` - Instance name * `--price PRICE` - Bid price for interruptible instances * `--link-volume ID` - Attach an existing volume * `--mount-path PATH` - Volume mount path **Example CLI commands:** ```bash theme={null} # Direct instance creation vastai create instance 12345678 vllm/vllm-openai:latest \ --disk 50 --ssh --direct \ --env "-e MODEL_ID=deepseek-ai/DeepSeek-R1-Distill-Llama-8B -p 8000:8000" \ --onstart-cmd "vllm serve \$MODEL_ID --port 8000" # Instance from template vastai create instance 12345678 --template_hash 4e17788f74f075dd9aab7d0d4427968f # Instance from template with overrides vastai create instance 12345678 --template_hash 4e17788f74f075dd9aab7d0d4427968f \ --disk 100 \ --env "-e HF_TOKEN=hf_xxxYourTokenHere" ``` ## Common Pitfalls Ensure you set the correct `runtype`. For SSH access, use `runtype: "ssh_direct"` for best results. Also verify that: * You have an SSH key registered with Vast.ai (`vastai create ssh-key`) * The machine supports direct connections (most verified machines do) * The instance has finished loading (check `actual_status` is `running`) For instance creation, the `env` field must be a JSON object (dict), not a Docker flag string: * Correct: `{"VAR1": "value1", "VAR2": "value2"}` * Wrong: `"-e VAR1=value1 -e VAR2=value2"` Port mappings use the `-p` syntax as keys with `"1"` as the value: `{"-p 8000:8000": "1"}` Note: Template creation still uses the Docker flag string format. Also note that environment variables set via `env` are **not automatically visible in SSH sessions**. To make them available when you SSH in, add the following to your `onstart` script: ``` env >> /etc/environment ``` This exports all environment variables so they persist across SSH logins. Offers are dynamic, machines can be rented by others between your search and creation request. Handle this by: * Searching for multiple offers and trying the next one if creation fails * Using `cancel_unavail: true` to fail fast if the offer is no longer available * Retrying the search to find fresh offers Interruptible instances can be stopped when someone outbids you. To reduce interruptions: * Increase your bid `price` * Choose machines with lower demand * Consider on-demand instances for critical workloads (omit `price` field) The `volume_info` field must be included in the **instance creation request**, not just the template. Template `volume_info` is a UI hint only. The volume must already exist before you can attach it. Ensure you provide the correct structure: ```json theme={null} { "volume_info": { "volume_id": 12345, "mount_path": "/workspace" } } ``` Where `volume_id` is the ID of an existing volume from `vastai show volumes`. ## Related Resources Create and manage templates for instance configuration Full API reference for the instance creation endpoint Find available machines to rent On-demand vs interruptible vs reserved instances # API Hello World Source: https://docs.vast.ai/api-reference/hello-world The raw REST API is intended for advanced users only. These endpoints offer maximum flexibility but require you to manage all aspects of integration yourself. Most users will have a significantly better experience using the [CLI](/cli/hello-world) or the [SDK](/sdk/python/quickstart), which handle these details for you. If you are not sure whether you need direct API access, you almost certainly don't, start with the CLI or SDK instead. The Vast.ai REST API gives you programmatic control over GPU instances, useful for automation, CI/CD pipelines, or building your own tooling on top of Vast. This guide walks through the complete instance lifecycle: authenticate, search for a GPU, rent it, wait for it to boot, connect to it, and clean up. By the end you'll understand the core API calls needed to manage instances without touching the web console. ## Prerequisites * A Vast.ai account with credit (\~\$0.01-0.05, depending on test instance run time) * `curl` installed ## 1. Get Your API Key Generate an API key from the [Keys page](https://cloud.vast.ai/manage-keys/) by clicking **+New**. Copy the key, you'll need it for your API calls, and you'll only see it once. Export it as an environment variable: ```bash theme={null} export VAST_API_KEY="your-api-key-here" ``` ## 2. Verify Authentication Confirm your key works by listing your current instances. If you have none, this returns an empty list. ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ "https://console.vast.ai/api/v0/instances/" ``` ```json theme={null} { "instances_found": 0, "instances": [] } ``` If you get a `401` or `403`, double-check your API key. If you already have instances, you'll see them listed here. ## 3. Search for GPUs Find available machines using the bundles endpoint. This query returns the top 5 on-demand RTX 4090s sorted by deep learning performance benchmarked per dollar: ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "verified": {"eq": true}, "rentable": {"eq": true}, "gpu_name": {"eq": "RTX 4090"}, "num_gpus": {"eq": 1}, "direct_port_count": {"gte": 1}, "order": [["dlperf_per_dphtotal", "desc"]], "type": "on-demand", "limit": 5 }' \ "https://console.vast.ai/api/v0/bundles/" ``` Each parameter in the query above controls a different filter: | Parameter | Value | Meaning | | ------------------- | ----------------------------------- | -------------------------------------------------------------- | | `verified` | `{"eq": true}` | Only machines verified by Vast.ai (identity-checked hosts) | | `rentable` | `{"eq": true}` | Only machines currently available to rent | | `gpu_name` | `{"eq": "RTX 4090"}` | Filter to a specific GPU model | | `num_gpus` | `{"eq": 1}` | Exactly 1 GPU per instance | | `direct_port_count` | `{"gte": 1}` | At least 1 directly accessible port (needed for SSH) | | `order` | `[["dlperf_per_dphtotal", "desc"]]` | Sort by deep learning performance per dollar, best value first | | `type` | `"on-demand"` | On-demand pricing (vs. interruptible spot/bid) | | `limit` | `5` | Return at most 5 results | The response contains an `offers` array. Note the `id` of the offer you want, you'll use it in the next step. If no offers are returned, try relaxing your filters (e.g. a different GPU model or removing `direct_port_count`). See the [Search Offers](/api-reference/search/search-offers) reference for the full list of filter parameters and operators. ## 4. Create an Instance Rent the machine by sending a PUT request with your Docker image and disk size. Replace `OFFER_ID` with the `id` from step 3. `disk` is in GB and specifies the size of the disk on your new instance. ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -X PUT \ -d '{ "image": "pytorch/pytorch:2.4.0-cuda12.4-cudnn9-runtime", "disk": 20, "onstart": "echo hello && nvidia-smi" }' \ "https://console.vast.ai/api/v0/asks/OFFER_ID/" ``` ```json theme={null} { "success": true, "new_contract": 12345678, "instance_api_key": "d15a..." } ``` Save the `new_contract` value, this is your instance ID. The `instance_api_key` is a restricted key injected into the container as `CONTAINER_API_KEY`, it can only start, stop, or destroy that specific instance. ## 5. Wait Until Ready The instance needs time to pull the Docker image and boot. Poll the status endpoint until `actual_status` is `"running"`. Replace `INSTANCE_ID` with the `new_contract` value from step 4. ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ "https://console.vast.ai/api/v0/instances/INSTANCE_ID/" ``` Example response: ```json theme={null} { "instances": { "actual_status": "loading", "ssh_host": "...", "ssh_port": 12345 } } ``` The `actual_status` field progresses through these states: | `actual_status` | Meaning | | --------------- | ----------------------------- | | `null` | Instance is being provisioned | | `"loading"` | Docker image is downloading | | `"running"` | Ready to use | Poll every 10 seconds. Boot time is typically 1-5 minutes depending on the Docker image size. You can also use the `onstart` script to send a callback when the instance is ready, instead of polling. Always handle non-happy-path statuses in your poll loop. If `actual_status` becomes `"exited"` (container crashed), `"unknown"` (no heartbeat from host), or `"offline"` (host disconnected), it will never reach `"running"`. Without a timeout or error check, your script will loop forever while the instance continues accruing disk charges. Destroy the instance and retry with a different offer if you see these states. Once `actual_status` is `"running"`, you're ready to connect. ## 6. Connect via SSH Use the `ssh_host` and `ssh_port` from the status response to connect directly to your new instance: ```bash theme={null} ssh root@SSH_HOST -p SSH_PORT ``` ## 7. Clean Up When you're done, destroy the instance to stop all billing. Alternatively, to pause an instance temporarily instead of destroying it, you can **stop** it. Stopping halts compute billing but disk storage charges continue. **Destroy** (removes everything): ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ -X DELETE \ "https://console.vast.ai/api/v0/instances/INSTANCE_ID/" ``` **Stop** (pauses compute, disk charges continue): ```bash theme={null} curl -s -H "Authorization: Bearer $VAST_API_KEY" \ -H "Content-Type: application/json" \ -X PUT \ -d '{"state": "stopped"}' \ "https://console.vast.ai/api/v0/instances/INSTANCE_ID/" ``` Both return `{"success": true}`. ## Next Steps You've now completed the full instance lifecycle through the API: authentication, search, creation, polling, and teardown. From here: * **Full endpoint reference**, Every REST endpoint is documented in the [API reference](/api-reference/authentication), organized under the Reference tab. * **Authentication & permissions**, Create scoped API keys for CI/CD or shared tooling. See [API authentication](/api-reference/authentication) and [permissions](/api-reference/permissions). * **SSH setup**, See the [SSH guide](/guides/instances/connect/ssh) for key configuration and advanced connection options. * **Use templates**, Avoid repeating image and config parameters on every create call. The [Templates API guide](/api-reference/creating-and-using-templates-with-api) covers creating, sharing, and launching from templates. # attach ssh-key Source: https://docs.vast.ai/api-reference/instances/attach-ssh-key /api-reference/openapi.yaml post /api/v0/instances/{id}/ssh Attaches an SSH key to the specified instance, allowing SSH access using the provided key. CLI Usage: `vastai attach ssh ` # cancel copy Source: https://docs.vast.ai/api-reference/instances/cancel-copy /api-reference/openapi.yaml delete /api/v0/commands/copy_direct Cancel a remote copy operation specified by the destination ID (dst_id). CLI Usage: `vastai cancel copy --dst_id ` # cancel sync Source: https://docs.vast.ai/api-reference/instances/cancel-sync /api-reference/openapi.yaml delete /api/v0/commands/rclone Cancels an in-progress remote sync operation identified by the destination instance ID. This operation cannot be resumed once canceled and must be restarted if needed. CLI Usage: `vastai cancel sync --dst_id ` # change bid Source: https://docs.vast.ai/api-reference/instances/change-bid /api-reference/openapi.yaml put /api/v0/instances/bid_price/{id} Change the current bid price of an instance to a specified price. CLI Usage: `vastai change bid --price ` # cloud copy Source: https://docs.vast.ai/api-reference/instances/cloud-copy /api-reference/openapi.yaml post /api/v0/commands/rclone Starts a cloud copy operation by sending a command to the remote server. The operation can transfer data between an instance and a cloud service. CLI Usage: `vastai cloud copy [options]` # copy Source: https://docs.vast.ai/api-reference/instances/copy /api-reference/openapi.yaml put /api/v0/commands/copy_direct Initiate a remote copy operation to transfer data from one instance to another or between an instance and the local machine. CLI Usage: `vastai copy ` # create instance Source: https://docs.vast.ai/api-reference/instances/create-instance /api-reference/openapi.yaml put /api/v0/asks/{id} Creates a new instance by accepting an "ask" contract from a provider. - Use the search offers endpoint to discover available machines. - If `template_id` is provided, those template defaults are either merged or overridden by parameters specified in the request body. **Template Precedence Rules:** - **Scalar fields** (image, disk, runtype, etc.): Request value overrides template value - **`env`**: Merged by key. Request values win on key conflicts - **`extra_filters`**: Merged by key. Request values win on key conflicts For detailed template usage, see [Creating and Using Templates with API](/api-reference/creating-and-using-templates-with-api). CLI Usage: `vastai create instance [options]` # destroy instance Source: https://docs.vast.ai/api-reference/instances/destroy-instance /api-reference/openapi.yaml delete /api/v0/instances/{id} Destroys/deletes an instance permanently. This is irreversible and will delete all data. CLI Usage: `vastai destroy instance ` # detach ssh-key Source: https://docs.vast.ai/api-reference/instances/detach-ssh-key /api-reference/openapi.yaml delete /api/v0/instances/{id}/ssh/{ssh_key_id} Detaches an SSH key from a specified instance, removing SSH access for that key. CLI Usage: `vastai detach ` # execute Source: https://docs.vast.ai/api-reference/instances/execute /api-reference/openapi.yaml put /api/v0/instances/command/{id} Executes a constrained remote command on a specified instance. The command output can be retrieved from the returned result URL. CLI Usage: `vastai execute ` # manage instance Source: https://docs.vast.ai/api-reference/instances/manage-instance /api-reference/openapi.yaml put /api/v0/instances/{id} Manage instance state and labels. The operation is determined by the request body parameters. CLI Usage: - To stop: `vastai stop instance ` - To start: `vastai start instance ` - To label: `vastai label instance