Prompt Management
Prompt management lets you write, version, test, and ship your prompts outside your application code. A prompt is a named, reusable template with its own model settings; your app calls it by a short slug and always gets the version you’ve published. Tune wording, swap models, and roll back a bad change from the dashboard — without a redeploy.
- Iterate without shipping code. Product or prompt engineers refine prompts in the dashboard; the app keeps calling the same slug.
- Safe rollouts & instant rollback. Every change is a new version. Publish when ready; if it misbehaves, roll back in one click.
- Test before you ship. Run a prompt version against a suite of test cases and see pass/fail before it ever reaches a user.
- One template, many environments. Point a @production label at a tested version while @staging points somewhere newer.
A prompt is a container; the real content lives in versions. Every save creates a new, immutable version — you never overwrite history. Versions move through three states:
| State | What it means |
|---|---|
| DRAFT | A work-in-progress version. Editable history; not served to your app unless you reference it explicitly. |
| PUBLISHED | The live version your app gets by default. Publishing a version automatically archives the previously published one. |
| ARCHIVED | A version that was published before. Kept for history and one-click rollback. |
A version bundles the messages and the model settings to run them with, so the prompt — not the app — owns how the model behaves.
| Field | What it does | Accepted values | Default |
|---|---|---|---|
| messages * | The chat messages that make up the prompt, with {{variables}} for the parts filled in per request. | a list of system / user / assistant / tool messages | — |
| model | The model this prompt runs on. The caller can override it per request. | a model id | the request’s model |
| temperature | Creativity vs. focus. | 0.0 to 2.0 | unset |
| max_tokens | Cap on response length. | a whole number ≥ 1 | unset |
| top_p | Alternative to temperature for limiting word choice. | 0.0 to 1.0 | unset |
| stop | Sequences that end the response when produced. | a list of short strings | unset |
| variables | Declares the placeholders the prompt expects (see below). | a list of variable definitions | none |
| tools | Tool/function definitions the model may call. | a list of tool specs | none |
Put {{variable_name}} placeholders anywhere in your messages; the caller supplies their values at request time. Declaring each variable lets the editor validate inputs and supply defaults.
| Field | What it does | Accepted values | Default |
|---|---|---|---|
| name * | The placeholder name as it appears in {{ }}. | an identifier | — |
| description | A human note about what the value should be. | any text | empty |
| required | Whether the caller must supply it. | true / false | false |
| default | A value used when the caller omits it. | any text | none |
To preview the filled-in messages without calling a model, post the variables to POST /v1/prompts/{slug}/render — useful for debugging a template.
A label is a movable pointer to a version — e.g. @production, @staging, @dev. Promote a tested version to production by moving the label, with no code change. When calling a prompt you choose which version with version_ref:
| version_ref | Resolves to |
|---|---|
| (omitted) | The current published version. |
| latest | The newest version, including a draft. |
| @production | Whatever version that label currently points to. |
| 3 | A specific version number. |
Run a prompt at POST /v1/prompts/{slug}/completions, authenticated like any inference call — a virtual key or a routing config. Pass the variable values (and optionally a version_ref); VectorAxis fills the template and runs it with the version’s model settings.
POST /v1/prompts/summariser-9a1b2c3d/completions
Authorization: Bearer vk-1a2b3c4d5e6f7a8b
{
"variables": {
"tone": "concise and professional",
"document": "..."
},
"version_ref": "@production" // optional; defaults to the published version
}A test case pairs a set of variable values with an expected-output pattern. Run the whole suite against any version to catch regressions before publishing.
| Field | What it does | Accepted values | Default |
|---|---|---|---|
| name * | A label for the case. | any text | — |
| variables_json | The variable values to fill the prompt with for this case. | key→value pairs | none |
| expected_pattern | A regular expression the output must match for the case to pass. | a regex | none (any output passes) |
Run the suite at POST /v1/prompts/{slug}/test-cases/run. The result reports per-case pass/fail, the actual response, latency, tokens, and cost, plus an overall pass/fail count — shown in the dashboard so you can compare versions at a glance.
- Per-prompt analytics — total requests, cost, average and p95 latency, and cache-hit rate over a time window, broken down by version, so you can see whether a new version is cheaper, faster, or more cacheable. Every prompt completion is also tagged with prompt_slug and prompt_version in your request logs.
- Audit log — every create, publish, rollback, and label change is recorded with who did it and when, for a full change history.
Creating, editing, publishing, and rolling back prompts takes a workspace admin; workspace members can view, render, run test suites, and call prompts. The full breakdown is on the Access Control page.
Developer API reference
Authenticate management calls with Authorization: Bearer va_…; the completions endpoint takes a virtual key or routing config like any inference call.
| Method | Path | Who can call it |
|---|---|---|
| POST | /v1/prompts | Workspace admin |
| GET | /v1/prompts | Workspace member |
| GET / PUT / DELETE | /v1/prompts/{slug} | member (GET) / admin (PUT, DELETE) |
| POST | /v1/prompts/{slug}/versions | Workspace admin |
| GET | /v1/prompts/{slug}/versions | Workspace member |
| POST | /v1/prompts/{slug}/versions/{n}/publish | Workspace admin |
| POST | /v1/prompts/{slug}/versions/{n}/rollback | Workspace admin |
| GET | /v1/prompts/{slug}/labels | Workspace member |
| PUT / DELETE | /v1/prompts/{slug}/labels/{label} | Workspace admin |
| GET / POST | /v1/prompts/{slug}/test-cases | member (GET) / admin (POST) |
| POST | /v1/prompts/{slug}/test-cases/run | Workspace member |
| POST | /v1/prompts/{slug}/render | Workspace member |
| GET | /v1/prompts/{slug}/analytics | Workspace member |
| GET | /v1/prompts/{slug}/audit-log | Workspace member |
| POST | /v1/prompts/{slug}/completions | Virtual key / routing config |
Create a prompt, then add a version (* = required):
// POST /v1/prompts
{ "name": "Summarize Article", // *
"description": "Summarizes an article",
"organization": "acme", // *
"workspace_id": "<workspace-uuid>" }
// POST /v1/prompts/{slug}/versions -> creates an immutable DRAFT (version 1, 2, ...)
{ "messages": [ // *
{ "role": "system", "content": "You are a {{tone}} assistant." },
{ "role": "user", "content": "Summarise: {{document}}" }
],
"model": "gpt-4o-mini",
"temperature": 0.3,
"variables": [
{ "name": "tone", "required": true, "default": "concise" },
{ "name": "document", "required": true }
] }
// POST /v1/prompts/{slug}/versions/2/publish -> makes v2 live, archives the old one
{ "labels": ["production"] }