API
The JSON API is served under /api/v1. An interactive OpenAPI browser is available at
/api, and the schema itself at /api/openapi.json; both can be turned off with
VAULTR_DOCS_ENABLED=false.
Authentication
If VAULTR_API_TOKENS is set, every request needs a
bearer token:
Without a valid token the API answers 401.
List projects
{
"projects": [
{"name": "prod-myproject", "description": "Production", "vault_id": null},
{"name": "test-myproject", "description": "Staging", "vault_id": null}
]
}
Passphrases are never part of the response.
Encrypt a secret
| Field | Type | Required | Description |
|---|---|---|---|
project |
string | yes | Name of a configured project. |
secret |
string | yes | The plaintext, encrypted verbatim. |
variable_name |
string | no | Ansible variable name; adds yaml_snippet to the reply. |
curl -s localhost:8000/api/v1/encrypt \
-H 'Content-Type: application/json' \
-d '{"project": "prod-myproject", "secret": "s3cr3t", "variable_name": "db_password"}'
{
"project": "prod-myproject",
"vault_id": null,
"vault_text": "$ANSIBLE_VAULT;1.1;AES256\n6430...\n6161",
"yaml_snippet": "db_password: !vault |\n $ANSIBLE_VAULT;1.1;AES256\n 6430..."
}
yaml_snippet is null unless variable_name was given.
The plaintext is encrypted byte for byte
Unlike the web UI, the API adds and removes nothing. A trailing \n in secret
ends up inside the encrypted value, which matters for things like SSH keys and API
tokens. Strip it yourself if you do not want it.
Errors
| Status | Meaning |
|---|---|
401 |
Missing or invalid bearer token. |
404 |
Unknown project. |
413 |
Secret larger than VAULTR_MAX_SECRET_LENGTH. |
422 |
Malformed body, empty secret or invalid variable_name. |
Errors carry a detail string:
Examples
vaultr_encrypt() {
curl -sf "$VAULTR_URL/api/v1/encrypt" \
-H "Authorization: Bearer $VAULTR_TOKEN" \
-H 'Content-Type: application/json' \
-d "$(jq -n --arg p "$1" --arg s "$2" --arg n "$3" \
'{project: $p, secret: $s, variable_name: $n}')" \
| jq -r .yaml_snippet
}
vaultr_encrypt prod-myproject "$(printf %s "$SECRET")" db_password
Re-encrypt a secret
Moves an already encrypted secret from one project's passphrase to another's. Vaultr decrypts it with the source project's passphrase and immediately re-encrypts it with the target's; the plaintext is never returned.
| Field | Type | Required | Description |
|---|---|---|---|
source_project |
string | yes | The project the secret is currently encrypted for. |
target_project |
string | yes | The project to encrypt it for instead. |
vault_text |
string | yes | The $ANSIBLE_VAULT string, or a whole key: !vault \| block. |
variable_name |
string | no | Ansible variable name; adds yaml_snippet to the reply. |
curl -s localhost:8000/api/v1/reencrypt \
-H 'Content-Type: application/json' \
-d @- <<'JSON'
{
"source_project": "test-myproject",
"target_project": "prod-myproject",
"vault_text": "$ANSIBLE_VAULT;1.1;AES256\n64303339...",
"variable_name": "db_password"
}
JSON
{
"source_project": "test-myproject",
"target_project": "prod-myproject",
"vault_id": null,
"vault_text": "$ANSIBLE_VAULT;1.1;AES256\n3861...",
"yaml_snippet": "db_password: !vault |\n $ANSIBLE_VAULT;1.1;AES256\n 3861..."
}
Paste the snippet as it is
vault_text accepts the whole key: !vault | block that Vaultr and
ansible-vault encrypt_string produce. The ten space indentation, which Ansible
itself rejects, is stripped for you, as are blank lines and \r\n line endings.
The content is re-encrypted byte for byte, so a value that is not valid UTF-8, such as a binary key, survives unchanged.
Errors
| Status | Meaning |
|---|---|
401 |
Missing or invalid bearer token. |
403 |
Re-encryption is disabled, or the configuration forbids this pair. |
404 |
Unknown source or target project. |
413 |
Input larger than VAULTR_MAX_SECRET_LENGTH. |
422 |
Not a vault string, or it does not belong to source_project. |
Re-encryption is a privileged operation
Anyone who can re-encrypt out of a project and knows the target project's passphrase can read that project's secrets. See Security before enabling it broadly.
No decrypt endpoint
There is none, by design. Vaultr exists so that people who must not know a vault
passphrase can still produce encrypted values; giving them decryption back would undo
exactly that. Decrypt with ansible-vault where the passphrase legitimately lives.
Re-encryption decrypts internally, but the plaintext never leaves the process: it exists only between the decrypt and the re-encrypt call.