> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ringg.ai/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To search or read these docs, connect the Ringg docs MCP server at https://docs.ringg.ai/mcp (no key needed; tools search_ringg_ai and query_docs_filesystem_ringg_ai) instead of browsing pages one by one. Setup for each client: https://docs.ringg.ai/resources/mcp-server/docs-mcp-server/mcp-for-ai-assistants.md
> The dashboard labels agents "Assistants"; these docs say "agent". Both mean the same object, identified by agent_id.
> API base URL: https://prod-api.ringg.ai/ca/api/v0. Send the workspace API key in the X-API-KEY header, from server-side code only.
> Placing a call dials a real phone number and spends credits. Confirm the number with the user before calling.
> To act on a Ringg workspace (place calls, edit agents, read transcripts), use the separate Ringg workspace MCP server at https://mcp.ringg.ai/mcp: https://docs.ringg.ai/resources/mcp-server/workspace-mcp-server/overview.md

# Lesson: Variables

> Add due_amount, due_date and loan_account as custom variables on the EMI reminder agent, insert them in the prompt with @, and fill them in Test assistant.

export const Quiz = ({question, answers, correctFeedback, incorrectFeedback}) => {
  const [selected, setSelected] = React.useState(null);
  const [checked, setChecked] = React.useState(false);
  const quizId = React.useId();
  const isCorrect = checked && answers[selected]?.correct;
  const reset = () => {
    setSelected(null);
    setChecked(false);
  };
  const optionStyle = (answer, i) => {
    const base = {
      display: "flex",
      alignItems: "flex-start",
      gap: "0.6rem",
      padding: "0.6rem 0.8rem",
      marginTop: "0.5rem",
      borderRadius: "0.6rem",
      border: "1px solid rgba(128, 128, 128, 0.35)",
      cursor: checked ? "default" : "pointer",
      lineHeight: 1.45
    };
    if (checked && answer.correct) {
      return {
        ...base,
        borderColor: "rgba(22, 163, 74, 0.8)",
        background: "rgba(22, 163, 74, 0.12)"
      };
    }
    if (checked && selected === i && !answer.correct) {
      return {
        ...base,
        borderColor: "rgba(220, 38, 38, 0.8)",
        background: "rgba(220, 38, 38, 0.1)"
      };
    }
    if (!checked && selected === i) {
      return {
        ...base,
        borderColor: "currentColor",
        background: "rgba(128, 128, 128, 0.12)"
      };
    }
    return base;
  };
  const buttonStyle = disabled => ({
    marginTop: "0.9rem",
    padding: "0.45rem 0.9rem",
    borderRadius: "0.5rem",
    border: "1px solid rgba(128, 128, 128, 0.5)",
    background: "rgba(128, 128, 128, 0.1)",
    color: "inherit",
    font: "inherit",
    fontSize: "0.9em",
    cursor: disabled ? "not-allowed" : "pointer",
    opacity: disabled ? 0.5 : 1
  });
  return <div style={{
    marginTop: "1.5rem",
    padding: "1rem 1.1rem",
    borderRadius: "0.8rem",
    border: "1px solid rgba(128, 128, 128, 0.35)"
  }}>
      <Badge color="green">Quiz</Badge>
      <p id={quizId + "-question"} style={{
    fontWeight: 600,
    margin: "0.6rem 0 0.2rem"
  }}>
        {question}
      </p>
      <div role="radiogroup" aria-labelledby={quizId + "-question"} aria-disabled={checked}>
        {answers.map((answer, i) => <label key={i} style={optionStyle(answer, i)}>
            <input type="radio" name={"quiz-" + quizId} checked={selected === i} onChange={() => !checked && setSelected(i)} disabled={checked} style={{
    marginTop: "0.3rem",
    flexShrink: 0
  }} />
            <span>{answer.text}</span>
          </label>)}
      </div>
      {checked && <div role="status" aria-live="polite" aria-atomic="true" style={{
    marginTop: "0.9rem",
    padding: "0.7rem 0.9rem",
    borderRadius: "0.6rem",
    lineHeight: 1.5,
    background: isCorrect ? "rgba(22, 163, 74, 0.12)" : "rgba(220, 38, 38, 0.1)"
  }}>
          <strong style={{
    marginRight: "0.4rem"
  }}>{isCorrect ? "✓" : "✗"}</strong>
          {isCorrect ? correctFeedback : incorrectFeedback}
        </div>}
      {!checked ? <button type="button" onClick={() => selected !== null && setChecked(true)} disabled={selected === null} style={buttonStyle(selected === null)}>
          Check answer
        </button> : <button type="button" onClick={reset} style={buttonStyle(false)}>
          Try again
        </button>}
    </div>;
};

export const RelatedTopics = ({items}) => <div className="not-prose mt-12">
    <div className="text-sm font-medium text-gray-500 dark:text-zinc-400 mb-3">Related topics</div>
    <div className="flex flex-col gap-2.5">
      {items.map(([title, href]) => <a key={href} href={href} className="flex items-center gap-2.5 text-sm text-gray-700 hover:text-gray-950 dark:text-zinc-300 dark:hover:text-white">
          <Icon icon="file-text" size={16} color="currentColor" />
          {title}
        </a>)}
    </div>
  </div>;

**Part 3: Making your agent smarter · Lesson 1 of 4 · 10 minutes**

## Objective

Add the three values that change on every reminder call as custom variables and use them in the prompt, so one agent serves every customer.

## The scenario

In part 2, Ananya said the same thing to everyone. Rahul Verma owes ₹12,450 on 15 October; Priya Sharma owes ₹4,500 on 18 October. The amount, the date and the loan account change per call, so they become variables: the prompt names them once, and each call fills in its own values, from the **Test assistant** dialog now and from a campaign CSV in part 4.

## Hands-on

<Frame caption="Adding a variable and using it in the prompt">
  <video alt="Adding a variable and using it in the prompt" aria-label="Adding a variable and using it in the prompt" controls muted playsInline className="w-full rounded-xl" style={{ aspectRatio: "16 / 10" }} preload="metadata" controlsList="nodownload noremoteplayback" poster="/media/agents-variables/poster.webp">
    <source src="https://mintcdn.com/ringgai-0da73d20/zhzhS2waLZvF8qXk/media/agents-variables/video.webm?fit=max&auto=format&n=zhzhS2waLZvF8qXk&q=85&s=8bdd89f68025cb527a02ab93f39e480f" type="video/webm; codecs=&#x22;av01.0.09M.08&#x22;" data-path="media/agents-variables/video.webm" />
  </video>
</Frame>

<Steps>
  <Step title="Open Custom Variables">
    In Ananya's editor sidebar, click **Custom Variables**. The panel lists `callee_name` and `mobile_number`, the two permanent variables, with no remove button.
  </Step>

  <Step title="Add due_amount">
    Type `Due Amount` into **Enter variable name**. As you type, letters become lowercase and spaces become `_`, so the field reads `due_amount`. Click **Add** or press Enter: "Variables updated successfully". There is no separate Save.
  </Step>

  <Step title="Add the other two">
    Repeat for `due_date` and `loan_account`. The three new rows sit at the bottom of the list, each with a bin icon.
  </Step>

  <Step title="Use them in the prompt">
    Open **Prompt**. In **Conversation Script**, type `@` where a value belongs and pick it under **Custom Variables**; it becomes a chip. Rewrite the steps so they read:

    * Confirm you are speaking to `@{{callee_name}}` about loan account `@{{loan_account}}`.
    * Tell them their EMI of `@{{due_amount}}` is due on `@{{due_date}}`.
    * Ask when they will pay.
  </Step>

  <Step title="Cover a missing value">
    A call goes ahead even when a variable has no value. A variable sent empty is left blank; one that is not sent at all stays in the prompt as the literal text `@{{due_date}}`. So add a line to the script: "If the due date is not known, ask the customer to check their statement." Click **Save**: "Changes saved successfully".
  </Step>
</Steps>

<Frame caption="The Custom Variables panel after adding loan_account">
  <img src="https://mintcdn.com/ringgai-0da73d20/zhzhS2waLZvF8qXk/media/agents-variables/variables-panel.webp?fit=max&auto=format&n=zhzhS2waLZvF8qXk&q=85&s=358ccc4879ae5ca696d91eb8288707e6" alt="Custom Variables panel with the Enter variable name field and Add button, and the variables callee_name and mobile_number (no remove button), then due_amount, due_date and loan_account, each with a bin icon" width="548" height="632" data-path="media/agents-variables/variables-panel.webp" />
</Frame>

## Checkpoint

<Check>
  **Custom Variables** lists `due_amount`, `due_date` and `loan_account` below `callee_name` and `mobile_number`. The prompt shows them as chips with no red underline, and **Test assistant** shows one field for each.
</Check>

## Exercise

Create a variable from the prompt instead of the panel: in any section, type `@{{branch_name` and choose **Create** `"{{branch_name}}"` from the menu. Expected result: a `branch_name` chip in the text and a new row in **Custom Variables**. Then remove the variable with its bin icon: the chip turns red with a wavy underline, because the agent has nothing to fill it with. Delete the chip before you save.

## What you learned

* A variable is written once in the prompt and filled per call: from **Test assistant** now, from a CSV column or the API's `custom_args_values` later.
* Names are lowercase with `_` and unique per agent; the input converts as you type.
* A red token names something the agent does not have. Fix every one before you save.

<Quiz
  question="You type Branch Name into Enter variable name and click Add. What is the variable called, and where does its value come from on a campaign call?"
  answers={[
{ text: "branch_name; from a CSV column of the calling list", correct: true },
{ text: "Branch Name; from the prompt, where you write the value once", correct: false },
{ text: "branch-name; from the knowledge base", correct: false },
{ text: "BranchName; from Advanced Analysis after the call", correct: false },
]}
  correctFeedback="Right. The input lowercases letters and turns spaces into _ as you type, so the variable is branch_name. A variable is written once in the prompt and filled per call: from Test assistant now, from a CSV column or the API's custom_args_values later."
  incorrectFeedback="Not quite. Names are lowercase with _, converted as you type, so it becomes branch_name. Its value is filled per call, from Test assistant, a calling-list column or the API, never from the prompt or the knowledge base."
/>

<RelatedTopics items={[["Variables", "/documentation/build-agents/customize-agent-behaviour/custom-variables"], ["Write the prompt", "/documentation/build-agents/customize-agent-behaviour/agent-prompt"]]} />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.