REST API Reference¶
MaestroVault includes a REST API server that listens on a Unix domain socket. This allows other tools, scripts, and services on the same machine to interact with secrets programmatically.
Starting the Server¶
Default socket: ~/.maestrovault/maestrovault.sock
Custom socket:
The server runs in the foreground and shuts down gracefully on Ctrl+C (SIGINT/SIGTERM). The socket file is cleaned up on exit.
Authentication¶
All endpoints except /v1/health require a Bearer token in the Authorization header:
Create tokens with:
Scopes¶
| Scope | Grants |
|---|---|
read |
Get, list, search, info |
write |
Set, edit, delete |
generate |
Password generation |
admin |
Token management (implicitly grants all other scopes) |
Endpoints¶
Health Check¶
No authentication required.
Response:
List Secrets¶
Scope: read
Query Parameters:
| Parameter | Description |
|---|---|
env |
Filter by environment |
metadata_key |
Filter by metadata key |
metadata_value |
Filter by metadata value (requires metadata_key) |
Response:
[
{
"name": "db-password",
"environment": "prod",
"metadata": {"service": "postgres"},
"created_at": "2026-03-13T10:00:00Z",
"updated_at": "2026-03-13T10:00:00Z"
}
]
Note
List does not decrypt values. Use GET by name to retrieve the plaintext.
Get Secret¶
Scope: read
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Response:
{
"name": "db-password",
"environment": "prod",
"value": "s3cret",
"metadata": {"service": "postgres"},
"fields": {
"host": "db.example.com",
"port": "5432",
"username": "admin"
},
"field_count": 3,
"created_at": "2026-03-13T10:00:00Z",
"updated_at": "2026-03-13T10:00:00Z"
}
The value field is omitted if the secret has no main value (fields-only entry). fields and field_count are omitted when there are no fields.
Set Secret¶
Scope: write
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Request Body:
Response (201):
Edit Secret¶
Scope: write
Partial update -- omitted fields are preserved.
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Request Body:
Response:
Delete Secret¶
Scope: write
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Response:
Secret Fields¶
Secrets can have an optional set of individually encrypted key-value fields in addition to (or instead of) the main value. Field keys are plaintext; field values are encrypted with per-field envelope encryption.
Set a Single Field¶
Scope: write
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Request Body:
If the parent secret does not exist, it is created automatically (with no main value).
Response (201):
Get a Single Field¶
Scope: read
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Response:
Get All Fields¶
Scope: read
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Response:
Returns a JSON object mapping field keys to their decrypted values. Returns an empty object {} if no fields exist.
**Scope:** `write`
**Query Parameters:**
| Parameter | Description |
|-----------|-------------|
| `env` | Environment (default: empty string) |
**Request Body:**
```json
{
"fields": {
"host": "db.example.com",
"port": "5432",
"username": "admin"
}
}
Creates or updates multiple fields at once. If the parent secret does not exist, it is created automatically.
Response (201):
Delete a Field¶
Scope: write
Query Parameters:
| Parameter | Description |
|---|---|
env |
Environment (default: empty string) |
Response:
Search¶
Scope: read
Searches secret names, environments, and metadata.
Response: Same format as List Secrets.
Generate Password¶
Scope: generate
Request Body:
{
"name": "wifi-password",
"environment": "home",
"length": 24,
"uppercase": true,
"lowercase": true,
"digits": true,
"symbols": false,
"metadata": {"type": "wifi"}
}
All fields are optional. Defaults: length 32, all character sets enabled. If name is provided, the password is stored as a secret. Include environment to scope the stored secret.
Response:
Vault Info¶
Scope: read
Response:
{
"dir": "/Users/you/.maestrovault",
"db_path": "/Users/you/.maestrovault/vault.db",
"db_size_bytes": 32768,
"secret_count": 42
}
List Tokens¶
Scope: admin
Response:
[
{
"id": "a1b2c3d4e5f6a7b8",
"name": "ci-read",
"scopes": ["read"],
"created_at": "2026-03-13T10:00:00Z",
"expires_at": null,
"last_used_at": "2026-03-13T11:30:00Z"
}
]
Create Token¶
Scope: admin
Request Body:
expires_in is optional. Use Go duration format (24h, 720h, etc.) or omit for no expiry.
Response (201):
{
"token": "mvt_abc123...",
"id": "a1b2c3d4e5f6a7b8",
"name": "deploy-token",
"scopes": ["read", "write"],
"expires_at": "2026-04-12T10:00:00Z"
}
Warning
The plaintext token is only returned once. Store it securely.
Revoke Token¶
Scope: admin
Response:
Error Responses¶
All errors return JSON:
| Status | Meaning |
|---|---|
| 400 | Bad request (missing/invalid parameters) |
| 401 | Unauthorized (missing/invalid token) |
| 403 | Forbidden (insufficient scope) |
| 404 | Not found |
| 500 | Internal server error |
Using with curl¶
Since the API uses a Unix socket, use curl's --unix-socket flag:
# Health check
curl --unix-socket ~/.maestrovault/maestrovault.sock \
http://localhost/v1/health
# Get a secret (with environment)
curl --unix-socket ~/.maestrovault/maestrovault.sock \
-H "Authorization: Bearer mvt_your_token_here" \
http://localhost/v1/secrets/db-password?env=prod
# Store a secret
curl --unix-socket ~/.maestrovault/maestrovault.sock \
-H "Authorization: Bearer mvt_your_token_here" \
-X PUT \
-d '{"value": "s3cret", "metadata": {"service": "db"}}' \
http://localhost/v1/secrets/my-key?env=dev
Socket Security¶
The Unix socket is created with 0600 permissions (owner read/write only). Only the user who started the server can connect. This provides OS-level access control without network exposure.