Skip to content

Assistant Config API

Version-control instructions and conversation stages, and push them from CI. The API sets the same assistant fields as the dashboard, with the same length limits and publish-snapshot lifecycle. Per-request injection addresses those same instruction fields and screens the resulting text with the publish safety gate.

The two instruction fields are customInstructions (System Instructions) and openingInstructions (opening / greeting instructions). Ragtime compiles these fields into the assistant’s prompt alongside its platform rules and configured capabilities.

Authentication is a project API key (Dashboard → Integrations → API keys) sent as a bearer token. Two scopes govern access:

Scope Grants
assistant:read GET the configuration
assistant:write PATCH the configuration

These are deliberately separate from ingest, so a content-ingestion credential can never rewrite the prompt that governs the assistant’s behaviour. See API Keys for issuing and scoping keys.

GET /api/v1/projects/{projectId}/assistant

Section titled “GET /api/v1/projects/{projectId}/assistant”
Terminal window
curl https://your-ragtime-instance.com/api/v1/projects/{projectId}/assistant \
-H "Authorization: Bearer rt_live_..."
{
"assistant": {
"customInstructions": "You are a calm, precise guide…",
"openingInstructions": "Greet the user and ask what they are working on.",
"openingInstructionsLiteral": false,
"openingInstructionsUseRag": false,
"conversationStages": null,
"updatedAt": "2026-07-30T09:12:44.000Z"
}
}

This returns the editable configuration. Public links serve the published snapshot, which may differ from the current draft.

PATCH /api/v1/projects/{projectId}/assistant

Section titled “PATCH /api/v1/projects/{projectId}/assistant”

Partial by design — only the fields you send are written, so a pipeline that owns the instruction fields does not have to round-trip settings it does not manage.

Terminal window
curl -X PATCH https://your-ragtime-instance.com/api/v1/projects/{projectId}/assistant \
-H "Authorization: Bearer rt_live_..." \
-H "Content-Type: application/json" \
-d '{
"customInstructions": "You are a calm, precise guide…",
"openingInstructions": "Greet the user and ask what they are working on.",
"conversationStages": {
"firstStageId": "intake",
"stages": [
{
"id": "intake",
"name": "Intake",
"purpose": "Find out what the user is trying to achieve",
"instructions": "Establish what the user is trying to achieve…",
"actionIds": [],
"moves": [{ "id": "m1", "toStageId": "capabilities", "when": "They are ready to scope capabilities" }]
},
{
"id": "capabilities",
"name": "Capabilities",
"instructions": "One relevance threshold applies to the whole list…",
"actionIds": [],
"moves": []
}
]
}
}'

Accepted fields: customInstructions, openingInstructions, openingInstructionsLiteral, openingInstructionsUseRag, conversationStages. Anything else is rejected rather than ignored, so a typo’d field in a deploy script fails loudly instead of silently doing nothing. An empty body is also rejected. A successful response uses the same { "assistant": ... } shape as GET.

Validation:

  • customInstructions ≤ 7,500 characters; openingInstructions ≤ 2,000. These are the same limits used by the dashboard and instruction injection, defined in $lib/shared/limits.
  • A stage has these fields: id, name, purpose (optional), instructions, actionIds and moves. A move has id, toStageId and when, the condition for moving on. Unknown fields in a stage or a move are a 400, like unknown fields in the body.
  • Stages have limits: a stage’s name is at most 100 characters, its purpose and each move’s when at most 500, and its instructions at most 2,000. A stage is added on top of the full main instructions, so it is a refinement and not a second prompt. Going over a limit is a 400.
  • Structural problems are errors, not warnings: a missing first stage or a move to a stage that does not exist is a 400. (The dashboard can show these next to the editor; an API caller has no editor to look at.)
  • conversationStages: null, or an empty stages list, clears the stages and returns the assistant to single-prompt behaviour.
  • conversationStages.enabled: false keeps the stages but turns them off. Leave it out for on.
  • Each stage can carry a purpose, a sentence on what the stage is for. The dashboard sends one, and the model reads it as part of the handoff tool.
  • actionIds lists action IDs. The dashboard offers the actions whose Start says “When the AI decides”.

Stages are part of the draft, like the instructions: visitors get them at the next publish. A PATCH that includes conversationStages reviews the stage text against the main instructions before it writes, so you see the verdict on the draft. The review looks for text that conflicts with the main instructions, tries to subvert the assistant’s rules, or is harmful. The result is stored with the stages as review and comes back in GET. You cannot set it yourself; the server ignores any review you send and writes its own.

A flagged review does not fail the request. The stages are saved but stay off until a later review is clear, and the assistant runs as a single prompt with all its actions meanwhile. If the review cannot run, status is unavailable: the stages stay off when the check itself failed, and stay as you set them when no AI provider is configured to run it.

Read conversationStages.review after a PATCH to see whether your stages will run. Test them with the Ask API and draft: true. Publishing runs the review again against the instructions it publishes, and freezes the stages with that verdict.

Saving conversationStages runs the stage review, a model call on your organization’s credits, so a PATCH that changes stages counts against the organization’s rate limit and the key’s monthly credit cap. Changing only the instructions spends nothing. Every change is written to the audit log with the key’s id.

The MCP server offers the same as get_assistant and configure_assistant.

Saved instructions are screened when publishing, whether authored through the API or dashboard. PATCH saves the draft; it does not run the publish gate. The gate checks for attempts to subvert the assistant’s rules and for harmful content. It does not review writing style or prompt quality. Flagged instructions block publishing.

Publish verdicts are cached on the assistant against a hash of the two instruction fields. Unchanged text reuses that verdict. Request-time injection uses a separate cache, described below.

Saving and publishing are separate. A successful PATCH updates the editable configuration and recompiles its cached prompt. Public links continue serving their published snapshot until you publish again or refresh that snapshot, using the same publishing path as dashboard changes. See Preview & Publishing.

For instructions that vary by screen or step, an instructionOverrides payload addresses the same two fields:

{
"instructionOverrides": {
"customInstructions": {
"value": "Help the user scope capabilities for the current screen.",
"mode": "replace"
},
"openingInstructions": {
"value": "Ask which capability they want to work on.",
"mode": "replace"
}
}
}

Send this with a chat request, rather than as a PATCH body. Enable Deployment → Allow injection first. Omitted fields retain their configured values. replace sets a field; append adds text to its configured value.

Each injected value has the shared field limit: 7,500 characters for customInstructions, 2,000 for openingInstructions. In append mode, that limit applies to the supplied text; the safety check evaluates the combined result, including the configured text. Both resulting fields are screened together, even when only one is overridden.

Injection does not provide an unrestricted system-prompt field or bypass the published assistant’s platform rules and capabilities. For live traffic, the published snapshot remains the base configuration; request overrides do not save a draft or publish a new snapshot.

Text chat and realtime use the same validation and screening path. All supplied fields must validate and the resulting pair must be screened before any override is applied. A flagged result returns 422 with an explanation and refuses the request. It does not silently fall back to published instructions or apply only part of the payload. For realtime, refusal happens before the sideband connects.

If the safety service is unavailable, the request proceeds, matching the publish gate’s behavior. An unavailable result is not a safety pass and is not cached.

Successful screenings are cached by organization and the hash of the resulting instruction pair for 30 days. Repeated text reuses an unexpired pass, including when an application switches between a fixed set of stages. New text or an expired pass requires another check.

This cache stores the hash and timestamps, not instruction text or findings. Flagged results are returned to the caller and are not cached. Keep the resulting instructions stable when possible to avoid repeated screening calls. See Chat Injection for embedding and transport examples.

Status Meaning
400 An instruction field has an invalid value or mode, or exceeds its length limit.
403 Instruction injection is disabled for the deployment.
422 The resulting instruction pair was flagged by the safety gate; the request is refused.

Fix the payload before retrying a 400 or 422. Sending the same flagged text again triggers another screening rather than retrieving a cached refusal.

Errors use the standard v1 shape, with a stable code:

{
"code": "internal",
"error": "Configuration saved but the system prompt could not be recompiled.",
"retryable": true,
"hint": "Send the same PATCH again: the save is idempotent and retries the recompile."
}
Status Code Meaning
400 invalid_request Malformed JSON, an unknown field, or a value that fails validation.
500 internal The configuration was saved but the system prompt could not be recompiled.

Authentication, scope (assistant:read / assistant:write), project and rate-limit refusals work the same on every endpoint. See Errors and Rate limits.

A 500 here means the stored draft is current but its compiled prompt is stale. Retry the PATCH rather than treating it as a no-op. The published snapshot remains unchanged.

Putting instructions in code is worth doing mainly because it lets you assert on them. Two tests worth writing for any assistant that describes a UI:

  1. Content tests — the instructions you serve for each step name the controls that exist and do not name ones that do not. These catch a regression at edit time.
  2. A transcript test — ask a question late in a step, not on the first turn, and assert the answer still names the real controls. This is the one that catches context decay; a first-turn test passes even when the material is no longer reaching the model on turn five.
  • Conversation Stages: choose stages, instructions, actions, and move-on conditions.
  • Dynamic Instructions — what belongs in these fields, and when to send instructions per request instead.
  • API Keys — issuing keys and choosing scopes.