Free-form procedures
Overview
Section titled “Overview”A free-form procedure describes one task in plain, natural language. The agent interprets the instructions and adapts the wording and order to the situation. A free-form procedure can call tools (including system tools like ending a call), look up knowledge base documents, and chain to other procedures.
When to use a free-form procedure
Section titled “When to use a free-form procedure”Use a free-form procedure when the agent can adapt wording and order to fit the situation, and you want to author it quickly in plain language. For how it compares to structured procedures, workflows, and the system prompt, see When to use procedures.
Anatomy of a procedure
Section titled “Anatomy of a procedure”Here is a refund procedure in the editor:

A procedure has two main parts: a trigger and content. Both can contain inline references to other resources, shown in the screenshot above as tags with wrench icons. Each procedure also has a name shown in the dashboard.
A short label that identifies the procedure in the dashboard. The name is never sent to the LLM, so it does not affect agent behavior.
Trigger
Section titled “Trigger”A description of when the agent should use this procedure, for example When the user asks to refund an order.
Leave the trigger empty only when creating a sub-procedure.
Content
Section titled “Content”The body of the procedure, written in markdown. Content describes what the agent should do: ask a question, look up an order, call a tool, or end the call. It can be a numbered sequence of steps to follow, or general guidance for the situation. Each step or guideline can be a single sentence (Ask the user for their order ID) or a short paragraph that explains what to do and why.
Use numbered steps for sequential actions and bullet points for requirements or sub-items within a step.
Inline references
Section titled “Inline references”Procedures can reference different kinds of resources inline:
- Tools (e.g. look up an order, charge a card, end the call, transfer to a human)
- Knowledge base documents
- Other procedures
Use inline references whenever a step needs the agent to use a tool, knowledge base document, or another procedure. References auto-attach the resource to the procedure so the agent can use it. Plain prose mentions (like use the calculator tool here) also work, but only if the resource is already attached to the agent.
Insert a reference by typing / in the trigger or content and choosing the resource from the slash menu. References appear as clickable tags in the editor. Click a tag to open the underlying resource and confirm its configuration.
When writing free-form content through the API, insert references with the following syntax:
[tool id="tool_abc123"][kb id="kb_abc123"][procedure id="agtprc_abc123"][system_tool id="end_call"]{{customer_id}}An inline procedure reference must use a procedure from the same agent. See Limitations for agent scope and duplication behavior.
A reference in the trigger lets the procedure fire based on a resource's output, for example When get_user returns tier 'gold'. A reference in content tells the agent to invoke or consult the resource at that step.
If a referenced resource is deleted later, or your account loses access to it, the tag shows as broken. The Errors badge at the top of the editor lists these references: invalid if the resource no longer exists, or unavailable if it exists but your account does not have access. Open the badge to see which step is affected and fix or remove the reference.

Sub-procedures
Section titled “Sub-procedures”A sub-procedure has an empty trigger. The agent can run it only from another procedure that references it.
Use sub-procedures to share steps within one agent and reduce the number of procedures available at once. Give the entry procedure a trigger, reference related sub-procedures from its content, and leave their triggers empty.
An escalation sub-procedure can hold the steps for handing the conversation to a human. Reference it from the refund and cancellation procedures and leave its trigger empty. The agent can escalate as a step of either procedure, but outside them the sub-procedure stays unavailable.
Importing from a document
Section titled “Importing from a document”You can bootstrap from an existing standard operating procedure (SOP). Choose From SOP in the procedure list + menu, then upload a file.
Supported formats: PDF, DOCX, TXT, MD, HTML, EPUB. Files must be 20 MB or smaller.
The importer analyzes the document, identifies up to 10 distinct procedures, and creates a draft for each one with a generated name, trigger, and content. Open each draft to refine it. If your document contains more than 10 SOPs, split it into smaller files before uploading.
Manage a free-form procedure
Section titled “Manage a free-form procedure”Build via the dashboard
Section titled “Build via the dashboard”Open your agent in the dashboard, then select Procedures. Use + to create a free-form procedure. Add a trigger and write the instructions in the content editor, then publish the agent changes.
Manage via the API
Section titled “Manage via the API”Free-form procedures store markdown in content.
Prerequisites
Section titled “Prerequisites”- An ElevenLabs API key in the
ELEVENLABS_API_KEYenvironment variable. - The target
agent_idandbranch_id. See Agent versioning for branch operations. - Version
2.60.0or newer of theelevenlabsPython package or@elevenlabs/elevenlabs-jsJavaScript package.
Procedure drafts are per-user, per-branch. Publishing saves your procedure changes in a new agent version on that branch. Other users' drafts are unaffected.
Create a draft
Section titled “Create a draft”from elevenlabs import CreateProcedureRequestModel, ElevenLabselevenlabs = ElevenLabs()procedure = elevenlabs.conversational_ai.agents.procedures.create( agent_id="agent_7101k5zvyjhmfg983brhmhkd98n6", branch_id="agtbranch_0901k4aafjxxfxt93gd841r7tv5t", request=CreateProcedureRequestModel( name="Refund request", type="free_form", trigger="When the user asks to refund, return, or get money back for an order", content="Ask for the order ID, then look it up with [tool id=\"tool_abc123\"].", ),)print(procedure.procedure_id)import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";const elevenlabs = new ElevenLabsClient();const procedure = await elevenlabs.conversationalAi.agents.procedures.create( "agent_7101k5zvyjhmfg983brhmhkd98n6", "agtbranch_0901k4aafjxxfxt93gd841r7tv5t", { name: "Refund request", type: "free_form", trigger: "When the user asks to refund, return, or get money back for an order", content: "Ask for the order ID, then look it up with [tool id=\"tool_abc123\"].", });console.log(procedure.procedureId);curl -X POST "https://api.elevenlabs.io/v1/convai/agents/agent_7101k5zvyjhmfg983brhmhkd98n6/branches/agtbranch_0901k4aafjxxfxt93gd841r7tv5t/procedures" \ -H "xi-api-key: $ELEVENLABS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Refund request", "type": "free_form", "trigger": "When the user asks to refund, return, or get money back for an order", "content": "Ask for the order ID, then look it up with [tool id=\"tool_abc123\"]." }'The response includes the new procedure_id. To update the draft, call
PATCH /procedures/{procedure_id}/draft with name, content, type, and an explicit
trigger.
Use a non-empty trigger for an entry procedure. For a
sub-procedure, use an empty string.
Publish the changes
Section titled “Publish the changes”Update the agent on the branch to publish your free-form procedure drafts in a new version. The request needs no body fields; publishing takes the drafts as they are.
from elevenlabs import ElevenLabselevenlabs = ElevenLabs()elevenlabs.conversational_ai.agents.update( agent_id="agent_7101k5zvyjhmfg983brhmhkd98n6", branch_id="agtbranch_0901k4aafjxxfxt93gd841r7tv5t",)import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";const elevenlabs = new ElevenLabsClient();await elevenlabs.conversationalAi.agents.update("agent_7101k5zvyjhmfg983brhmhkd98n6", { branchId: "agtbranch_0901k4aafjxxfxt93gd841r7tv5t",});curl -X PATCH \ "https://api.elevenlabs.io/v1/convai/agents/agent_7101k5zvyjhmfg983brhmhkd98n6?branch_id=agtbranch_0901k4aafjxxfxt93gd841r7tv5t" \ -H "xi-api-key: $ELEVENLABS_API_KEY" \ -H "Content-Type: application/json" \ -d '{}'See Manage procedures for draft removal and discard behavior, or the Procedures API reference for complete endpoint schemas.
Best practices
Section titled “Best practices”Writing procedures well means writing two parts well: a trigger that runs the procedure when it should, and content the agent can follow.
Writing triggers
Section titled “Writing triggers”Keep triggers concrete and disjoint
Section titled “Keep triggers concrete and disjoint”Overlapping or vague triggers cause the wrong procedure to run. Prefer When the user asks to cancel a subscription over When the user has a question about their account.
Write from the user's perspective
Section titled “Write from the user's perspective”Describe what the user is asking for, not what the agent should do. Triggers phrased as agent actions are less reliable.
Cover the way users actually ask
Section titled “Cover the way users actually ask”A narrow trigger can miss real requests when the user phrases things differently. Include the variations the user might say. When the user asks to refund, return, or get money back for an order runs more reliably than When the user requests a refund.
Writing content
Section titled “Writing content”Use imperative form
Section titled “Use imperative form”Write steps as instructions to the agent: Look up the customer's last order rather than You should look up the customer's last order. Direct instructions are easier to follow than suggestions.
Explain why a step matters
Section titled “Explain why a step matters”Reasoning generalizes to edge cases the procedure does not enumerate. A short because we need the order ID to issue a refund helps the agent handle situations the steps did not anticipate. Avoid all-caps MUSTs and rigid scripts where a one-line explanation would do the same work.
Keep each procedure focused on one task
Section titled “Keep each procedure focused on one task”If a procedure starts branching into unrelated outcomes, split it into smaller procedures and let the agent route between them.
Composing procedures
Section titled “Composing procedures”Extract shared steps into their own procedure
Section titled “Extract shared steps into their own procedure”If the same steps show up across multiple procedures (verifying a customer's identity, looking up an order, escalating to a human), extract them into a dedicated procedure and reference it from each one that needs it via the slash menu. Maintaining the shared steps in one place keeps every procedure that uses them consistent.
Use sub-procedures for reactive actions
Section titled “Use sub-procedures for reactive actions”Use a sub-procedure for an action the agent should run only when another procedure requests it, such as identity verification or escalation. Without a trigger, it does not compete with entry procedures at conversation start. Fewer trigger choices keep routing focused.
Use the system prompt for global behavior
Section titled “Use the system prompt for global behavior”Tone, identity, refusal policies, and guardrails belong in the system prompt. Put task-specific steps in procedures.
Procedures version with the agent
Section titled “Procedures version with the agent”Procedures are part of the agent's configuration, so they snapshot together when you publish a new agent version. To roll back to an earlier set of procedures, restore an earlier agent version. See Agent versioning.
Bootstrap from existing documentation
Section titled “Bootstrap from existing documentation”If your team already has SOPs, use the importer to turn them into drafts and refine from there.