Skip to content

Endpoint: Prompt Management ​

Create, read, update, and delete prompts in VeriPrompt.

Authentication ​

Prompt list and create operations support three authentication methods:

1. Session Auth (Browser/Dashboard) ​

Standard NextAuth session cookies — used automatically by the VeriPrompt UI.

Use a FULL_ACCESS or OPENAI_COMPAT Gateway API key created in Admin > API Management.

bash
curl -X POST https://app.veriprompt.tech/api/v1/prompts \
  -H "Authorization: Bearer vp-gw_sk_your-key-here" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Prompt", "userPrompt": "Summarize: {{text}}"}'
Gateway Key TypeCreate PromptsList Prompts
FULL_ACCESSYesYes
OPENAI_COMPATYesYes
EXECUTE_ONLYNoNo
READ_ONLYNoNo

3. External API Key (Chains/Objects system) ​

For integration with the chains/objects system. Requires specific permission scopes in routingOverrides.permissions:

  • create:prompts — for creating prompts
  • read:prompts — for listing all company prompts
  • read:own-prompts — for listing only own prompts

Create a Prompt ​

POST /api/v1/prompts
Auth: Session, Gateway Key (FULL_ACCESS/OPENAI_COMPAT), or External API Key (create:prompts)

Request Body ​

json
{
  "name": "Customer Follow-up",
  "userPrompt": "Write a follow-up email for {{customerName}} regarding {{topic}}.",
  "systemPrompt": "You are a professional customer support agent.",
  "description": "Generates follow-up emails for support tickets",
  "temperature": 0.7,
  "maxTokens": 500,
  "category": "support",
  "tags": ["email", "follow-up"],
  "visibility": "PRIVATE"
}

Required Fields ​

FieldTypeConstraints
namestring1-100 characters, must be unique within your company
userPromptstringMinimum 1 character. Must be unique (content hash is checked).

Optional Fields ​

FieldTypeDefaultConstraints
systemPromptstring-System instruction for the AI
descriptionstring-Human-readable description
temperaturenumber0.7Range: 0.0 - 2.0
maxTokensnumber1000Range: 1 - 8000
categorystring-Free-text category label
tagsstring[][]Array of tag strings
visibilityenumPRIVATEPRIVATE, SHARED, or PUBLIC
repositoryIdstring-Assign to a specific repository
branchstringmainRepository branch

Note: Each prompt's userPrompt content is hashed (SHA-256). Two prompts with identical userPrompt text cannot coexist. Add unique identifiers or variables to differentiate similar prompts.

Response (201 Created) ​

json
{
  "success": true,
  "prompt": {
    "id": "clxyz123...",
    "promptId": "prompt_1706000000_abc123",
    "name": "Customer Follow-up",
    "userPrompt": "Write a follow-up email for {{customerName}}...",
    "temperature": 0.7,
    "maxTokens": 500,
    "visibility": "PRIVATE",
    "isActive": true,
    "createdAt": "2026-01-15T10:00:00Z"
  }
}

List Prompts ​

GET /api/v1/prompts
Auth: Session, Gateway Key (FULL_ACCESS/OPENAI_COMPAT), or External API Key (read:prompts/read:own-prompts)

Which prompts are listed ​

The list only contains prompts the caller is allowed to see:

CallerSees
Session userOwn prompts, PUBLIC prompts, SHARED prompts with no share list, and SHARED prompts shared with them or one of their teams. Account owners and admins of that company see every prompt in it.
Gateway API keyExactly what the key's owner would see in a session. A key cannot list a colleague's PRIVATE prompt — the same rule applies when the key executes prompts (gateway, MCP).
External API keyread:prompts: all company prompts. read:own-prompts: only prompts created by that key.

Admin access is per company. What counts is the role you hold in the company the prompts belong to — the role set under that company's user management — not your role in another company. If you are an admin in your own company and a regular member in a partner company, a key for the partner company sees only what a member sees there. An admin role in a company you were deactivated in grants nothing. This applies everywhere prompt visibility applies: the list, prompt execution, the gateway, MCP tools and chains, and test suites.

Example: Ana and Ben work in the same company. Ben has a PRIVATE prompt "Salary review". Ana's gateway key lists Ana's prompts and the company's PUBLIC/shared ones, but not "Salary review". If Ben shares it with Ana (or with a team Ana is in), it appears in her key's list too.

Query Parameters ​

ParamTypeDescription
querystringSearch by name or description
categorystringFilter by category
tagsstringComma-separated tag filter
repositoryIdstringFilter by repository
visibilityenumPRIVATE, COMPANY, or PUBLIC
limitnumberResults per page (1-100, default: 20)
offsetnumberPagination offset (default: 0)
sortByenumcreatedAt, updatedAt, name, totalExecutions
sortOrderenumasc or desc (default: desc)

Response ​

json
{
  "prompts": [ ... ],
  "pagination": {
    "total": 42,
    "limit": 20,
    "offset": 0,
    "hasMore": true
  }
}

Get a Prompt ​

GET /api/v1/prompts/{id}
Auth: Session or Gateway Key

Returns the full prompt object including latest version content.

Update a Prompt ​

PUT /api/v1/prompts/{id}
Auth: Session

All fields are optional - only include fields you want to change:

json
{
  "name": "Updated Name",
  "userPrompt": "Updated prompt text",
  "temperature": 0.5,
  "isActive": false
}

Delete a Prompt ​

DELETE /api/v1/prompts/{id}
Auth: Session

Note: Active prompts must be deactivated before deletion. Set isActive: false via the update endpoint first, then delete.

What deactivating does. A deactivated prompt no longer runs anywhere it is used by reference:

  • MCP execute_stored_prompt and custom MCP tools answer as if the prompt did not exist.
  • An MCP chain tool with a deactivated step is refused and no longer listed in tools/list.
  • A Studio chain with a deactivated step runs no step at all and reports "Stored prompt … is deactivated" for that step. Reactivate the prompt, or replace the step, to run the chain again.
  • A test suite that targets a deactivated prompt can still be created and edited, but running it is refused (409) until you reactivate the prompt.
  • A gateway request (POST /api/gateway/execute) that names it in metadata.promptId is refused with 409 ("This prompt is deactivated. Reactivate it to run it."). This includes the prompt's own Execute page and the Gateway mode of its Test panel, so reactivate a prompt before trying it out. The Test panel's API Agent mode sends the prompt's text rather than a reference to it, so it still runs, but as plain text without the prompt's own settings.

For example, if step 3 of a five-step Studio chain uses a deactivated prompt, steps 1 and 2 do not run either, so you are not charged for a run that cannot finish.

The same applies to a Studio chain step whose prompt is missing, not visible to you, or has no production version, when that step would stop the chain (stop on error is on and the step does not continue on error): the run is refused before any step runs, with that step's usual error. If the chain is set to continue past a failing step, the other steps still run and that step fails at its turn. A Studio chain run uses each prompt as it was when the run started: deactivating a prompt, or publishing a new production version, takes effect from the next run.

Clone a Prompt ​

POST /api/v1/prompts/clone
Auth: Session
json
{
  "sourcePromptId": "clxyz123..."
}

Creates a copy of the prompt with a new name and ID.

Version History ​

GET /api/v1/prompts/{id}/versions
Auth: Session or Gateway Key

Returns the version history for a prompt, ordered by creation date.

Execute a Stored Prompt ​

Use the MCP endpoint with a gateway key:

bash
curl -X POST https://app.veriprompt.tech/api/mcp \
  -H "Authorization: Bearer sk-vp-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "tools/call",
    "params": {
      "name": "execute_stored_prompt",
      "arguments": {
        "promptId": "prompt_123_abc",
        "variables": {
          "customerName": "Jane Smith",
          "topic": "order #4567"
        }
      }
    },
    "id": 1
  }'

Test in Chat ​

Turn one version into protected Markdown files for a vendor chat (Claude, ChatGPT or Gemini), then bring the chat's answer back onto the version. These routes never call a model or the gateway. Hands-on guide: Test a Prompt in a Chat.

  • Auth: session only (the browser UI); gateway and external API keys are not accepted.
  • Who: people who can edit the prompt, in a company whose plan includes Shield data protection (403 FEATURE_NOT_IN_PACKAGE otherwise; a suspended company gets 403 COMPANY_SUSPENDED).
  • Caching: every answer carries Cache-Control: no-store.
  • Errors are { "code": "…", "error": "…" }.
MethodPathPurpose
GET/api/v1/prompts/{id}/chat-test?versionId=…Can this version be tested? Test sets, vendors, naked rule
POST/api/v1/prompts/{id}/chat-testCreate one protected file per test set (up to 20)
GET/api/v1/prompts/{id}/chat-test/runs?versionId=…Your own last 50 runs on this prompt
POST/api/v1/prompts/{id}/chat-test/importBring the returned answer back: restore, verdict, checks, encrypted response on the version

Create the files ​

bash
curl -X POST https://app.veriprompt.tech/api/v1/prompts/cm9sup0rt0001/chat-test \
  -H "Cookie: next-auth.session-token=…" \
  -H "Content-Type: application/json" \
  -d '{ "versionId": "cm9ver0002", "testSetIds": ["cm9ts0001"], "vendor": "claude", "naked": false }'

The 201 answer lists one entry per file in runs (ref such as vp-run-k7qm2xw4ad, fileName, markdown, handoffId) and, per test set that failed, an entry in errors. The file holds stand-ins only and asks the assistant to answer as vp-run-<ref>.md.

Import the answer ​

bash
curl -X POST https://app.veriprompt.tech/api/v1/prompts/cm9sup0rt0001/chat-test/import \
  -H "Cookie: next-auth.session-token=…" \
  -H "Content-Type: application/json" \
  -d '{
    "fileName": "vp-run-k7qm2xw4ad.md",
    "text": "VERIPROMPT CHECK: CLEAN\n\nDear Jon Doe-665gf1, we have refunded order 4711 …",
    "rating": 4
  }'
FieldRequiredRule
textyesthe returned file or the pasted answer, at most 2,000,000 characters
fileNamenoa vp-run-<ref> in it picks the run
runIdnothe run's ref, when neither fileName nor text carries one
ratingno1 to 5
json
{
  "run": { "ref": "vp-run-k7qm2xw4ad", "versionId": "cm9ver0002", "testSetId": "cm9ts0001", "vendor": "claude", "status": "IMPORTED" },
  "verdict": { "status": "clean", "reason": null, "lineCount": 1, "firstLine": true },
  "checks": {
    "results": [
      { "kind": "contains", "expected": "Anna Schmidt", "passed": true },
      { "kind": "contains", "expected": "within 5 working days", "passed": false },
      { "kind": "pattern", "expected": "order\\s+4711", "passed": true }
    ],
    "passed": 2,
    "total": 3
  },
  "responseId": "cm9resp0007",
  "restored": { "text": "Dear Anna Schmidt, we have refunded order 4711 …", "highlights": [], "replaced": 1, "expiredOrDeleted": 0, "unrecognised": 0 }
}
  • Only the person who created the run can import it: the restore puts back your stand-ins. Any other run answers 404 RUN_NOT_FOUND with the same sentence.
  • The restored answer is stored encrypted as a response of the run's version (company retention and storage limits apply) and appears on the prompt's responses and compare pages.
  • A run is imported once. A second import answers 409 RUN_ALREADY_IMPORTED. A withheld answer is the exception: it comes back as 201 with imported: false and responseId: null, nothing is stored and the run stays open, so a corrected answer can be imported for the same run.
  • The restore counts toward your Shield quota like any handoff restore.
StatuscodeWhen
400BAD_CHAT_IMPORT_REQUESTtext missing, or a field has the wrong shape
404RUN_NOT_FOUNDno run of yours on this prompt matches
409RUN_ALREADY_IMPORTEDthe run was already imported
409RESPONSE_STORAGE_DISABLED / STORAGE_LIMIT_REACHEDyour company keeps no responses (0 days), or its response storage is full
410HANDOFF_GONEthe run's handoff expired or was deleted, so the real values cannot come back
413TOO_LARGEtext is over 2,000,000 characters
422RUN_REF_MISSINGno vp-run- ref and no runId: pick the run from …/chat-test/runs
429QUOTA_EXCEEDEDyour Shield quota is used up

Test set expectations ​

The checks live on the test set. GET /api/v1/prompts/{promptId}/test-sets and GET …/test-sets/{testSetId}/values return two more fields; POST …/test-sets and PUT …/test-sets/{testSetId}/values accept them (on PUT, values may be left out). Test values and expectations hold real data, so all four routes answer only people who can open the prompt in its own company (another company's prompt is 404 PROMPT_NOT_FOUND, for reads too) and carry Cache-Control: no-store:

FieldRule
expectedContainsup to 20 phrases of 1 to 500 characters; matched ignoring case and extra whitespace
expectedPatternone regular expression of at most 300 characters, matched ignoring case. Backreferences, lookarounds, nested repetition such as (a+)+, (a?b?)+ or (a|b)* and counts above 1000 are refused with 400 BAD_EXPECTED_PATTERN
bash
curl -X PUT https://app.veriprompt.tech/api/v1/prompts/support-reply/test-sets/cm9ts0001/values \
  -H "Cookie: next-auth.session-token=…" \
  -H "Content-Type: application/json" \
  -d '{ "expectedContains": ["Anna Schmidt", "within 5 working days"], "expectedPattern": "order\\s+4711" }'