Skip to main content
Agents built in the platform’s prompt editor store their prompt as rich text: a list of typed nodes (plain text, variables, tool references and per-language wording), not one plain string. The API exposes that prompt as composition_by_language. Read it with GET /v2/agent/{agent_id}, edit it, and send it back with PUT /v2/agent/{agent_id}.

What is composition_by_language

composition_by_language is an object keyed by language code. Each value is an ordered list of nodes. Bolna joins the nodes in order to build the system prompt the agent runs on.
At call time this renders to:
{customer_name} is then filled from the call’s variables, exactly like a variable in a plain-text prompt. See Dynamic variables.

Node types

Every node has a type. No other keys than the ones listed below are accepted. variable
  • name: the variable name. Dotted and indexed paths are allowed, for example prior.loans.0.amount.
  • scope: one of execution, system or agent_context. Use execution for variables you pass when starting a call (user_data or batch CSV columns) and system for built-in variables such as current_date or timezone.
function_tool
  • name: the name of a tool configured on the agent, such as transfer_call. Letters, digits and underscores only, and it can’t start with a digit.
language_value
  • name: a slot name, by convention prefixed with language_ (for example language_greeting). Letters, digits and underscores only.
  • values: the wording for each language, keyed by language code: { "en": "...", "hi": "..." }. A value can also be a list of phrasings, such as ["okay", "alright"].

The two shapes

How the object is keyed depends on how the agent’s prompt is built.
Agents using the Single Prompt view have one key, the agent’s default language. The rules and flow are shared text nodes; every line that is spoken differently per language is a language_value node carrying all its translations.
On a Hindi call the greeting renders as the hi value, on an English call as the en value. A language missing from values renders as {language_greeting}, so fill in every language the agent speaks.
Keep the shape the agent already uses: edit the nodes you get back from GET instead of switching between the two shapes.

Read the prompt

GET /v2/agent/{agent_id} returns composition_by_language as a top-level field, next to agent_prompts.
Response (trimmed)
  • The composition is the published one for the agent version returned, the same prompt live calls use. Unsaved edits in the platform editor aren’t included.
  • GET /v2/agent/{agent_id}/versions/{agent_version_id} returns the composition of that specific version.
  • composition_by_language is null when the agent has no rich text prompt. Its prompt is then the plain-text agent_prompts.task_1.system_prompt, which you update as before.

Update the prompt

Send the edited composition_by_language as a top-level key in the PUT /v2/agent/{agent_id} body, alongside agent_config and agent_prompts.
1

Get the agent

Call GET /v2/agent/{agent_id} and keep composition_by_language.
2

Edit the nodes

Change text, add or remove variable and function_tool nodes, or update the wording inside a language_value node’s values. Keep every language key and every node you aren’t changing.
3

Send it back with PUT

Include the full composition_by_language in the PUT body, with the agent’s agent_config and agent_prompts.
Returns HTTP 200 like any agent update. The composition is saved with the new agent version, and the next calls run on it.
Always send composition_by_language on PUT for an agent that has one. Each PUT creates a new agent version, and only the composition sent in that request is linked to it. A PUT without it leaves the new version with no rich text prompt, so GET returns null and calls fall back to the plain-text agent_prompts.task_1.system_prompt.

Rules for the payload

  • The whole object is replaced. composition_by_language isn’t merged with what’s stored. A language key you leave out is removed from the prompt.
  • agent_prompts stays the plain-text fallback. While a composition is linked, calls use the composition. Keep agent_prompts.task_1.system_prompt in step with it (the prompt rendered as plain text) so the fallback matches.
  • Empty means no rich text prompt. Sending {}, or only empty node lists, saves no composition; the agent runs on agent_prompts.
  • Nodes are validated. An unknown type, a missing field, an extra key or an invalid name returns HTTP 400 with a message and a validation_errors list pointing to the node.
PATCH /v2/agent/{agent_id} doesn’t accept composition_by_language. Use PUT to change a rich text prompt. On an agent with a rich text prompt, patching agent_prompts changes only the plain-text fallback, not what calls say.

Next steps

Update agent

Full PUT /v2/agent/{agent_id} reference.

Get agent

Full GET /v2/agent/{agent_id} reference.

Single Prompt view

How marked lines and translations work in the editor.

Dynamic variables

Pass variable values when starting a call.