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

# Build a FormBharo Voice Agent from Your Form Fields

> Turn a paper or web form into a FormBharo voice agent: map fields to question types, add scripts, configure branching, and publish with the API.

export const FORMBHARO_URL = "https://api.formbharo.artpark.ai";

FormBharo lets you turn any form — paper intake sheets, web surveys, clinical questionnaires — into a voice agent that asks questions out loud and saves the answers. This guide walks through the full process: mapping fields, adding a script, configuring conditional branches, and publishing.

<Steps>
  <Step title="Create a draft agent">
    Start by sending a `POST /api/v1/agents` request with at minimum a `title` and a `questions` array. The API returns a new agent in draft state along with its `agent_id`, which you'll use in every subsequent request.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X POST {FORMBHARO_URL}/api/v1/agents \
        -H "Authorization: Bearer <api-key>" \
        -H "Content-Type: application/json" \
        -d '{
          "title": "Clinic intake",
          "questions": [
            {
              "id": "full_name",
              "label": "What is your full name?",
              "response_type": "string"
            },
            {
              "id": "date_of_birth",
              "label": "What is your date of birth?",
              "response_type": "date"
            }
          ]
        }'
      ```

      ```python python theme={null}
      import requests

      response = requests.post(
          "{FORMBHARO_URL}/api/v1/agents",
          headers={"Authorization": "Bearer <api-key>"},
          json={
              "title": "Clinic intake",
              "questions": [
                  {
                      "id": "full_name",
                      "label": "What is your full name?",
                      "response_type": "string",
                  },
                  {
                      "id": "date_of_birth",
                      "label": "What is your date of birth?",
                      "response_type": "date",
                  },
              ],
          },
      )

      agent = response.json()
      agent_id = agent["agent_id"]
      ```
    </CodeGroup>
  </Step>

  <Step title="Map each field to a question type">
    Every question needs a `response_type` that tells FormBharo how to parse and store the caller's spoken answer. Choose the type that matches the original form field.

    | `response_type` | What it stores                  | Extra options                                    |
    | --------------- | ------------------------------- | ------------------------------------------------ |
    | `string`        | Free-text answer                | —                                                |
    | `number`        | Numeric value                   | `number_format: "integer"` or `"decimal"`        |
    | `date`          | Date, stored as `DD-MM-YYYY`    | —                                                |
    | `boolean`       | Yes/no answer                   | `boolean_labels` to customise the spoken options |
    | `single-select` | One choice from a list          | `options[]` — required                           |
    | `multi-select`  | One or more choices from a list | `options[]` — required                           |

    For `single-select` and `multi-select`, pass `options` as an array of strings. The agent reads the list aloud and maps the caller's answer to the closest matching option.

    For `number`, omit `number_format` if the caller might say either integers or decimals; set it to `"integer"` or `"decimal"` when you know the expected format.
  </Step>

  <Step title="Add scripts">
    Scripts give the agent its opening and closing lines. Set them inside a `scripts` object on the agent body.

    * **`scripts.intro`** — What the agent says at the very start of the call, before the first question. Use this to greet the caller and explain the purpose of the call.
    * **`scripts.outro`** — What the agent says when all required questions have been answered and the call is complete.
    * **`scripts.outro_incomplete`** — What the agent says when the call ends before all questions are answered (for example, the caller hangs up early).

    <Note>
      You cannot set `outro_incomplete` without also setting `outro`. Both must be present if you want to customise the incomplete ending.
    </Note>

    ```json theme={null}
    {
      "scripts": {
        "intro": "Hi, I'm calling on behalf of City Clinic to complete your intake form. This will only take a couple of minutes.",
        "outro": "That's everything I need. Thank you for your time — we'll see you at your appointment.",
        "outro_incomplete": "It looks like we ran out of time. Our team will follow up to collect the remaining details."
      }
    }
    ```
  </Step>

  <Step title="Add conditional branches">
    Branches let you skip or show groups of questions based on a caller's earlier answer. The flow works like this:

    1. **Declare the branch** — add an entry to the top-level `branches` array. Give it a unique `id` and a `condition` that references a question `id` and a rule.
    2. **Tag questions** — set `branch_id` on every question that belongs to the branch. Those questions are only asked if the condition evaluates to `true` at runtime.

    A condition supports these fields:

    | Field     | Type    | Meaning                                                     |
    | --------- | ------- | ----------------------------------------------------------- |
    | `field`   | string  | The `id` of the question whose answer is evaluated          |
    | `equals`  | string  | Branch is active when the answer exactly matches this value |
    | `present` | boolean | Branch is active when the answer is any non-empty value     |

    <Note>
      `present` takes priority over `equals`. If both are set on the same condition, `present` is evaluated and `equals` is ignored.
    </Note>

    Use `equals` to branch on a specific value (for example, only proceed if the caller answered "yes"). Use `present` to branch whenever the caller gave any answer at all, regardless of what it was.

    <CodeGroup>
      ```json Equals condition theme={null}
      {
        "branches": [
          {
            "id": "has_insurance",
            "condition": {
              "field": "insurance_status",
              "equals": "yes"
            }
          }
        ],
        "questions": [
          {
            "id": "insurance_status",
            "label": "Do you have health insurance?",
            "response_type": "boolean"
          },
          {
            "id": "insurance_provider",
            "label": "Who is your insurance provider?",
            "response_type": "string",
            "branch_id": "has_insurance"
          },
          {
            "id": "policy_number",
            "label": "What is your policy number?",
            "response_type": "string",
            "branch_id": "has_insurance"
          }
        ]
      }
      ```

      ```json Present condition theme={null}
      {
        "branches": [
          {
            "id": "has_referral",
            "condition": {
              "field": "referral_source",
              "present": true
            }
          }
        ],
        "questions": [
          {
            "id": "referral_source",
            "label": "Were you referred by someone?",
            "response_type": "string"
          },
          {
            "id": "referral_name",
            "label": "What is the name of the person who referred you?",
            "response_type": "string",
            "branch_id": "has_referral"
          }
        ]
      }
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure screening">
    Use `end_call_values` to end a call early when a caller gives a disqualifying answer. Supply an array of strings; if the agent records any of those exact values, it ends the call immediately and marks the conversation `screened_out`. Screened-out calls count as successes, not failures.

    ```json theme={null}
    {
      "end_call_values": ["no", "not interested", "already completed"]
    }
    ```

    Screened-out calls appear in analytics separately from fully completed calls, so you can track the size of the disqualified cohort without it inflating your failure rate.
  </Step>

  <Step title="Publish">
    When your agent is ready, publish it with `PUT /api/v1/agents/{agent_id}`. Send the complete agent body — not just the changed fields — as the request body. The API validates the configuration and returns the published agent on success.

    <CodeGroup>
      ```bash curl theme={null}
      curl -X PUT {FORMBHARO_URL}/api/v1/agents/AGENT_ID \
        -H "Authorization: Bearer <api-key>" \
        -H "Content-Type: application/json" \
        -d '{
          "title": "Clinic intake",
          "questions": [ ... ],
          "scripts": { ... },
          "branches": [ ... ]
        }'
      ```

      ```python python theme={null}
      import requests

      agent_body = {
          "title": "Clinic intake",
          "questions": [...],
          "scripts": {...},
          "branches": [...],
      }

      response = requests.put(
          f"{FORMBHARO_URL}/api/v1/agents/{agent_id}",
          headers={"Authorization": "Bearer <api-key>"},
          json=agent_body,
      )

      if response.status_code == 400:
          print("Validation failed:", response.json()["validation_issues"])
      else:
          print("Published:", response.json())
      ```
    </CodeGroup>

    <Warning>
      If validation fails, the API returns `400` with a `validation_issues` array describing each problem. Fix every issue before retrying — partial saves are not supported.
    </Warning>
  </Step>
</Steps>

## Preview changes before saving

Before you publish a new version, you can review exactly what will change by calling `POST /api/v1/agents/{agent_id}/diff-preview` with the proposed agent body. The response contains an array of diff lines, each with a `type` field:

| Type      | Meaning                                                 |
| --------- | ------------------------------------------------------- |
| `add`     | Line present in the new version but not the current one |
| `remove`  | Line present in the current version but not the new one |
| `context` | Unchanged line shown for context                        |
| `hunk`    | Separator between diff sections                         |
| `meta`    | Header information about the diff                       |

Use this endpoint in CI pipelines or review tools to catch unintended changes before they reach a live agent.

```bash curl theme={null}
curl -X POST {FORMBHARO_URL}/api/v1/agents/AGENT_ID/diff-preview \
  -H "Authorization: Bearer <api-key>" \
  -H "Content-Type: application/json" \
  -d '{ "title": "Clinic intake", "questions": [ ... ] }'
```

<Tip>
  See **Agent Configuration** for every field, **Question Types** for per-type options, and **Branching** for the full branch rules.
</Tip>
