{{variables}}, saved on a preset. Your application sends the preset reference and the variable values. Phaseo checks the values, fills in the messages and sends the request to the preset’s model.
This keeps prompt text out of application code. You can change the prompt in the dashboard without a deploy, and every caller uses the same wording, tools and response format.
Templates work on POST /v1/chat/completions, POST /v1/responses and POST /v1/messages.
Quick start
1
Write the template
Open Settings -> Presets, create or open a preset, choose its model and open the Prompt template tab. Add messages and write variables in double braces:The editor lists each variable it finds. Set its type, whether it is required, a default and a description. Fill in the Try it panel to see the exact messages the gateway will send, then save.Once the preset is saved, Run saved preset sends a real request with your test values and shows the reply, the model and the token counts. It uses your workspace’s credits. The same panel has cURL, TypeScript and Python code for the request, filled in with your test values.
2
Send the variables
Reference the preset in
prompt.id and put the values in prompt.variables. Leave out model, or set it to the same reference.3
Check the request
Open Gateway -> Logs to see the request, the model that served it and its cost. The request’s metadata records the preset, the variable names and the number of rendered messages, but not the variable values.
Use templates from each endpoint
The sameprompt object works on all three endpoints. The template’s system and developer messages become the endpoint’s system instructions, and its other messages go before any conversation your request sends.
You can send a conversation with the template. For example, a chat request can add the user’s follow-up turns after the template’s messages:
Template syntax
Templates use a small, logic-free subset of Mustache. Nothing in a template is ever run as code.
Values are inserted as plain text, without HTML escaping. A value can change the text of a message but never the structure of the request.
If a message renders to nothing but whitespace, it is dropped. Use this to make a whole message optional:
{{.}} for the current item:
{{> name}}), unescaped tags ({{{name}}} and {{& name}}), delimiter changes and lambdas are not supported, and the editor and API refuse templates that use them.
Variables
Each variable has a type. You only need to declare a variable to change its defaults; variables used in the messages but not declared are required text.
Each variable can also have:
required: the request fails when the value is missing. A required variable cannot have a default.default: used when the request leaves the value out. It must match the type.description: shown in the editor and in error messages, up to 500 characters.
notes and examples above, is optional and accepts any value.
Requests are checked strictly. A missing required value, a value of the wrong type or a name the template does not have returns a 400 that lists every problem at once, so a typo cannot silently drop part of a prompt.
Image variables
An image variable fills a whole content part of a user message, so the template decides where the image goes. In the editor, choose Add image inside a user message. In the API, use avariable part:
https URL, a data:image/... URL, or an image part in the chat completions, Responses or Messages shape. Phaseo converts it to the format of the endpoint you called. The selected model must accept image input.
Tools and response format
A template can includetools, tool_choice and response_format, written in the chat completions shape. Phaseo converts them for the Responses and Messages endpoints.
The request always wins when both set the same thing:
- Tools are joined by function name. If the request defines a tool with the same name, the request’s definition is used.
- The request’s
tool_choiceand response format (response_format,text.formatoroutput_config.format) replace the template’s.
temperature and max_tokens work as usual. The preset’s own defaults fill only the fields the request leaves out.
Create a template with the API
Templates are stored in the preset’sconfig.prompt. Create or update the preset with a management API key that has presets:write:
400 invalid_prompt_template and the location of each problem, both here and in the editor.
Saved changes reach requests within about two minutes.
Versions and labels
Each time you publish a preset, Phaseo saves an immutable version (see Presets). Requests run the latest published version unless they pin one. A pinned request uses that version’s models, parameters and template together. Pin a version withprompt.version:
prompt.version takes a version label such as v3, 1.2.0 or 2026.10.27, or a label such as production. You can also put the version in the model ID, with or without a template:
@publisher/support-triage@production. If model and prompt.version both pin a version, they must name the same one.
Labels
A label is a name, such asproduction or staging, that points at one published version. Labels are 1 to 32 lowercase letters, numbers, hyphens or underscores, start with a letter, and cannot look like a version label (v1, v2).
In Settings -> Presets, open the preset. Publish, next to Save Draft, saves your changes and publishes them as the next version. Open Versions and labels to manage labels: each label has a version picker, so choosing another version moves the label and choosing an earlier one rolls back. Use Add label for a new one. Open a version to see its models and template messages and how they differ from the default version (the one requests run when they don’t pin a version), and use Run to try that version with the test values from Prompt template. The preset’s creator can change its labels, and so can workspace owners and admins when the preset is shared. With a management API key that has presets:write:
version (a version label, or another label to copy where it points) or version_id. GET /v1/presets/{id}/labels lists labels, and DELETE /v1/presets/{id}/labels/{label} removes one. Requests that pin a removed label fail until it is added again.
Roll back
To roll back, move the label to the earlier version: choose that version in the label’s version picker in Versions and labels, or send the same request with"version": "v2". Requests that pin production run v2 again without any change to your application.
Label moves reach requests within about two minutes, the same as other preset changes.
Errors
Template problems in a request return400 with the code validation_error. reason holds the first problem’s code and details lists all of them with their path:
A
prompt.id that names no preset in your workspace returns 404.
A pinned version or label that does not exist, or that the key cannot use, returns 404 with the reason preset_version_not_found.
Limits
Guardrails and logs
Guardrails check variable values as user content, even when the template puts them into a system message. A guardrail that redacts a value redacts it everywhere the template inserted it, and one that blocks a value blocks the request. Request metadata records the preset, the variable names and the number of rendered messages. The values themselves are kept only where the request body is kept, under your workspace’s normal logging settings.Current limitations
modelsfallbacks cannot be combined with a template. Add fallback models to the preset instead.- Templates apply to chat completions, Responses and Messages requests only.