---
title: "Add an SSH key to a server"
method: POST
path: "/api/v1/vms/{id}/ssh-keys"
tags: ["Virtual Machines"]
---

# Add an SSH key to a server

`POST /api/v1/vms/{id}/ssh-keys`

## Request

- Base URL: `https://api.rafftechnologies.com`
- URL: `https://api.rafftechnologies.com/api/v1/vms/{id}/ssh-keys`
- Auth: API key in header `X-API-Key`

Add a key to root's `authorized_keys` on a running Linux server, at once and without a restart. `ssh_key` is the ID of a saved key or a public key (the same rule as saved keys); with `save_as`, a public key is also saved to your account under that name. A key the server already has changes nothing (`changed: 0`). The key also goes into the server's settings, so a factory reset keeps it. Every change is emailed to the account owner and written to the audit log. Needs `vm.ssh_keys`; in the dashboard it also asks for a two-factor code.

## Path parameters

- `id` string, uuid, required

## Request body

- AddServerSSHKeyRequest
  - `ssh_key` string, required: A saved key's ID, or one public key (the whole line of a `.pub` file)
  - `save_as` string: Also save a public key to your account under this name (ignored for a key you already saved)

## Response `200`

The server's keys after the add

- ServerSSHKeysResponse
  - `success` boolean
  - `data` ServerSSHKeys: A server's keys after a read, add or remove
    - `keys` ServerSSHKey[]
      - `fingerprint` string
      - `type` string
      - `comment` string
      - `has_options` boolean: The line starts with `authorized_keys` options (`command="..."`, `from="..."`)
      - `saved_key_id` string: Your saved key with this fingerprint; empty when it is not saved
      - `saved_key_name` string
      - `public_key` string: The key without its options, as a `.pub` file holds it
    - `read_at` string, date-time
    - `changed` integer: Lines added or removed (0 when the key was already there, or not there)
    - `saved_key_id` string: The saved key `save_as` created

## Other responses

- `400`: The server's keys could not be read or changed. `reason` says why: `not_linux`, `invalid_key` (400); `not_on_server` (404); `not_running`, `no_guest_agent`, `agent_blocked`, `selinux_blocked`, `last_key`, `refused` (409); `host_unavailable`, `context_failed` (503); `no_answer` (504). `error` is the sentence to show.
- `401`: Authentication required
- `403`: Missing `vm.ssh_keys`, or (dashboard sessions) `mfa_required`
- `404`: Resource not found
- `409`: The server's keys could not be read or changed. `reason` says why: `not_linux`, `invalid_key` (400); `not_on_server` (404); `not_running`, `no_guest_agent`, `agent_blocked`, `selinux_blocked`, `last_key`, `refused` (409); `host_unavailable`, `context_failed` (503); `no_answer` (504). `error` is the sentence to show.
- `503`: The server's keys could not be read or changed. `reason` says why: `not_linux`, `invalid_key` (400); `not_on_server` (404); `not_running`, `no_guest_agent`, `agent_blocked`, `selinux_blocked`, `last_key`, `refused` (409); `host_unavailable`, `context_failed` (503); `no_answer` (504). `error` is the sentence to show.
- `504`: The server's keys could not be read or changed. `reason` says why: `not_linux`, `invalid_key` (400); `not_on_server` (404); `not_running`, `no_guest_agent`, `agent_blocked`, `selinux_blocked`, `last_key`, `refused` (409); `host_unavailable`, `context_failed` (503); `no_answer` (504). `error` is the sentence to show.

## Changes

- **2026-10-21** `25a12e36b279`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/rafftechnologies/apis/raff-api/changes/api/v1/vms/:id/ssh-keys/post.md)

---

[API](https://skmtc.dev/rafftechnologies/apis/raff-api.md) - [All operations](https://skmtc.dev/rafftechnologies/apis/raff-api/llms.txt) - [OpenAPI document](https://skmtc.dev/rafftechnologies/apis/raff-api/revisions/3d30cde0acb4?raw)
