Skip to main content

What are Dispositions?

Dispositions are LLM-powered post-call classifiers. After every call, each disposition defined for your agent runs against the transcript and produces a structured result — either a Free Text response or a Pre-defined value selected from options you configure. Use dispositions to automatically tag call outcomes, score leads, detect escalation needs, verify compliance, and more — without manually reading every transcript.
Dispositions are similar to Extractions but designed for classification rather than data capture. An extraction answers “what did the customer say?”; a disposition answers “what was the outcome?”.

Key Concepts

Categories

Dispositions are organized into categories (e.g., “Lead Quality”, “Compliance”, “Call Outcome”). Every disposition belongs to exactly one category. Categories are set per-disposition via the category field (default: "General").

Answer Types

Each disposition must declare one or both answer types:
TypeFieldDescription
Free Textis_subjective: trueLLM generates a free-text response based on the transcript and question prompt
Pre-definedis_objective: trueLLM selects a value from objective_options based on each option’s condition
You can enable both types on a single disposition to get a natural-language explanation alongside a structured label.

Subjective Types

When using Free Text (is_subjective: true), you can constrain the expected response format with subjective_type. This tells the LLM what format to produce and enables automatic post-LLM validation of the response.
TypeDescriptionExample Value
textAny free-form text (default)"Customer was satisfied with the demo"
timestampISO 8601 timestamp"2026-04-08T14:30:00"
numericInteger or decimal number"42", "3.14"
booleanExactly "true" or "false""true"
emailValid email address"user@example.com"
regexMust match a custom regex pattern"1234567890" (with pattern ^\d{10}$)
When subjective_type is regex, you must also provide a subjective_type_config object:
{
  "subjective_type": "regex",
  "subjective_type_config": {
    "pattern": "^\\d{10}$",
    "description": "10-digit phone number"
  }
}
FieldTypeRequiredDescription
patternstringYesThe regex pattern the response must match
descriptionstringNoHuman-readable description of the expected format

Copy-on-Write Updates

When you update a disposition that is shared using a scoped agent_id, Bolna automatically creates a private copy for that agent instead of modifying the original. This ensures changes to one agent’s dispositions don’t affect others. The API signals this with a 201 response (new resource created) rather than the usual 200 (updated in place). See the Update Disposition reference for full details.

Configuring Dispositions in the Dashboard

You can create and manage dispositions directly from the Analytics tab in your agent configuration.

Setting the Expected Format (Subjective Type)

When creating or editing a disposition with Free Text enabled, the form shows an Expected Format dropdown. This lets you constrain the LLM’s response format without writing any API calls.
Disposition form showing Free Text enabled with Expected Format dropdown set to Email
1

Enable Free Text

Check the Free Text checkbox to enable subjective responses.
2

Select Expected Format

Choose from the Expected Format dropdown:
  • Text (default) — Any free-form text
  • Timestamp — ISO 8601 date/time
  • Numeric — Integer or decimal
  • Booleantrue or false
  • Email — Valid email address
  • Custom Regex — Your own pattern
3

Configure Regex (if selected)

When Custom Regex is selected, two additional fields appear:
  • Pattern (required) — The regex pattern the response must match (e.g., ^\d{10}$)
  • Description (optional) — Human-readable explanation (e.g., “10-digit phone number”)
The form validates your regex in real-time and prevents saving if the pattern is invalid.
Disposition form showing Custom Regex selected with pattern and description fields
Invalid LLM responses are flagged but preserved — the validation object in results will show is_valid: false, but the original response is still returned in the subjective field so no data is lost.

Creating a Disposition via API

Single Disposition

POST /dispositions/

{
  "agent_id": "agt_abc123",
  "name": "Call Outcome",
  "question": "What was the final outcome of this call? Did the customer agree to a follow-up?",
  "category": "Lead Quality",
  "is_subjective": true,
  "is_objective": true,
  "model": "gpt-4.1-mini",
  "objective_options": [
    {
      "value": "interested",
      "condition": "Customer expressed genuine interest and agreed to a next step"
    },
    {
      "value": "not_interested",
      "condition": "Customer declined or was unresponsive to all proposals"
    },
    {
      "value": "follow_up",
      "condition": "Customer asked to be contacted again at a later time"
    }
  ]
}

With a Subjective Type Constraint

POST /dispositions/

{
  "agent_id": "agt_abc123",
  "name": "Follow-up Date",
  "question": "When did the customer say they want to be contacted next?",
  "category": "Scheduling",
  "is_subjective": true,
  "subjective_type": "timestamp"
}

With a Regex Subjective Type

POST /dispositions/

{
  "agent_id": "agt_abc123",
  "name": "Customer Phone",
  "question": "What phone number did the customer provide during the call?",
  "category": "Contact Info",
  "is_subjective": true,
  "subjective_type": "regex",
  "subjective_type_config": {
    "pattern": "^\\d{10}$",
    "description": "10-digit phone number"
  }
}

Bulk Create (for multiple dispositions at once)

POST /dispositions/bulk

{
  "agent_id": "agt_abc123",
  "dispositions": [
    {
      "name": "Agent Handover Needed",
      "question": "Did the customer explicitly request to speak with a human agent?",
      "category": "Escalation",
      "is_objective": true,
      "objective_options": [
        { "value": "Yes", "condition": "Customer asked to speak with a human or live agent" },
        { "value": "No", "condition": "Customer did not request a human handover" }
      ]
    },
    {
      "name": "Customer Sentiment",
      "question": "Describe the customer's overall tone and satisfaction level during the call.",
      "category": "Quality",
      "is_subjective": true
    }
  ]
}
Bulk creates are atomic — either all dispositions are created and linked, or none are.

Answer Types in Detail

Free Text

The LLM generates an open-ended response based on the question prompt and the transcript. Best for:
  • Summarizing customer concerns or objections
  • Explaining the reasoning behind an outcome
  • Capturing qualitative context
Example:
{
  "name": "Cancellation Reason",
  "question": "If the customer cancelled or declined, what was their stated reason?",
  "is_subjective": true
}
Result:
"subjective": "Customer mentioned they already signed with a competitor last week and were not open to switching."

Typed Free Text

You can constrain the free-text response format using subjective_type (see Subjective Types above). When a non-text type is set, the system automatically validates the LLM’s response and includes a validation object in the result. Example:
{
  "name": "Customer Email",
  "question": "What email address did the customer provide?",
  "is_subjective": true,
  "subjective_type": "email"
}
Result:
{
  "subjective": "user@example.com",
  "objective": null,
  "confidence": 0.95,
  "confidence_label": "High",
  "reasoning_subjective": "Customer clearly spelled out their email as user@example.com during the call.",
  "reasoning_objective": null,
  "validation": {
    "is_valid": true,
    "expected_type": "email"
  }
}

Pre-defined Options

The LLM selects a value from your objective_options list. Each option has a value (returned in the result) and a condition (instructions for when to select it). Best for:
  • Yes/No classifications
  • Status labels (hot/warm/cold)
  • Compliance checks
Example:
{
  "name": "Appointment Confirmed",
  "question": "Did the customer agree to schedule an appointment?",
  "is_objective": true,
  "objective_options": [
    { "value": "confirmed", "condition": "Customer agreed to a specific date and time" },
    { "value": "tentative", "condition": "Customer expressed interest but did not commit to a time" },
    { "value": "declined", "condition": "Customer did not agree to any appointment" }
  ]
}
Result:
"objective": "confirmed"

Confidence & Reasoning

Every disposition result now includes a confidence score and reasoning fields that explain why the LLM selected its answer.
FieldTypeDescription
confidencefloatScore from 0.0 to 1.0 indicating the LLM’s certainty
confidence_labelstringHuman-readable label: "High" (≥ 0.8), "Medium" (≥ 0.5), or "Low" (< 0.5)
reasoning_subjectivestring | nullBrief explanation of the free-text response. null if is_subjective is false
reasoning_objectivestring | nullBrief explanation of the pre-defined selection. null if is_objective is false
These fields help you audit LLM decisions programmatically and build confidence-based routing (e.g., flag low-confidence results for human review).

Nested Options

objective_options support recursive nesting via sub_options for hierarchical classifications:
{
  "value": "interested",
  "condition": "Customer showed interest in the product",
  "sub_options": [
    { "value": "high_intent", "condition": "Customer asked about pricing or next steps" },
    { "value": "low_intent", "condition": "Customer was politely interested but non-committal" }
  ]
}

Managing Dispositions

List Dispositions for an Agent

GET /dispositions/?agent_id=agt_abc123
Returns all dispositions linked to the specified agent.

Update a Disposition

PUT /dispositions/{disposition_id}
Include agent_id in the request body to use scoped (copy-on-write) mode:
{
  "agent_id": "agt_abc123",
  "question": "Updated: Did the customer agree to a demo or a follow-up call?",
  "objective_options": [
    { "value": "demo", "condition": "Customer agreed to a product demo" },
    { "value": "follow_up", "condition": "Customer agreed to a follow-up call" },
    { "value": "declined", "condition": "Customer declined both options" }
  ]
}
If the disposition you’re updating is shared with other agents, the API will return 201 instead of 200 — this means a new copy was created and linked to your agent. Your original agent behavior is preserved and isolated from other agents.

Delete a Disposition

DELETE /dispositions/{disposition_id}
You can only delete dispositions you own. Admins can delete any disposition.

Disposition Output Format

After each call, disposition results are stored in the execution record under the dispositions key, organized by category:
{
  "dispositions": {
    "Lead Quality": {
      "Call Outcome": {
        "subjective": "Customer expressed strong interest and asked about enterprise pricing options.",
        "objective": "interested",
        "confidence": 0.92,
        "confidence_label": "High",
        "reasoning_subjective": "Customer asked about enterprise pricing and requested a follow-up demo.",
        "reasoning_objective": "Customer explicitly expressed interest and agreed to a next step.",
        "validation": null
      }
    },
    "Escalation": {
      "Agent Handover Needed": {
        "subjective": "",
        "objective": "No",
        "confidence": 0.88,
        "confidence_label": "High",
        "reasoning_subjective": null,
        "reasoning_objective": "Customer did not request to speak with a human agent at any point.",
        "validation": null
      }
    },
    "Contact Info": {
      "Customer Email": {
        "subjective": "user@example.com",
        "objective": null,
        "confidence": 0.95,
        "confidence_label": "High",
        "reasoning_subjective": "Customer clearly provided their email address during the call.",
        "reasoning_objective": null,
        "validation": {
          "is_valid": true,
          "expected_type": "email"
        }
      }
    }
  }
}

Field Reference

FieldTypeDescription
subjectivestring | nullFree Text LLM response. "" if no relevant information found; null if not configured (is_subjective: false)
objectivestring | nullSelected Pre-defined value. null if objective_options not configured or no condition matched
confidencefloatLLM confidence score from 0.0 to 1.0
confidence_labelstring"High" (≥ 0.8), "Medium" (≥ 0.5), or "Low" (< 0.5)
reasoning_subjectivestring | nullLLM’s reasoning for the free-text response. null if is_subjective is false
reasoning_objectivestring | nullLLM’s reasoning for the pre-defined selection. null if is_objective is false
validationobject | nullPost-LLM validation result for typed subjective responses. null for text type or when is_subjective is false

Accessing Disposition Results

Fetch any execution by ID to see its disposition results:
GET /executions/{execution_id}
The dispositions key is included in the execution response alongside transcript, extracted_data, and other post-call data.
If you’ve configured a post-call webhook, disposition results are included in the same execution payload delivered to your endpoint after every call.See Webhooks for payload details.
Open any call record from the Call History tab to view disposition results alongside the transcript and call summary.

Common Use Cases

Use CaseDispositionTypeSubjective Type
Lead scoringHot / warm / cold classificationPre-defined
Escalation detectionAgent handover requested?Pre-defined (Yes/No)
Appointment trackingWhen is the next appointment?Free Texttimestamp
Cancellation analysisWhy did the customer cancel?Free Texttext
Compliance auditingWas the required disclaimer read?Pre-defined (Yes/No)
Contact captureWhat email did the customer give?Free Textemail
NPS scoringWhat NPS score did the customer give?Free Textnumeric
Phone validationCapture a 10-digit phone numberFree Textregex
Opt-in confirmationDid the customer agree to marketing?Free Textboolean

Best Practices

  1. One concern per disposition — Keep each disposition focused on a single question. Split “was the customer satisfied AND did they agree to a follow-up?” into two separate dispositions.
  2. Write clear conditions — Objective option conditions should be mutually exclusive and cover all expected outcomes (including an “unknown” fallback if needed).
  3. Use both types together — Enabling both Free Text (is_subjective) and Pre-defined (is_objective) gives you a structured label for automation plus a human-readable explanation for review.
  4. Use categories to group related dispositions — Group escalation, compliance, and lead quality into their own categories to keep execution results readable.
  5. Scope updates with agent_id — Always pass agent_id when updating dispositions via the API to avoid unintentionally modifying a shared disposition.
  6. Use subjective types for structured data — When you need a specific format (date, number, email), set subjective_type instead of relying on prompt engineering alone. The system validates responses automatically.
  7. Monitor confidence scores — Use confidence_label to flag low-confidence results for manual review or re-processing.
  8. Use reasoning for auditing — The reasoning_subjective and reasoning_objective fields explain why the LLM chose its answer — use these for compliance audits or debugging unexpected results.

Next Steps

Dispositions API

Manage dispositions programmatically

Using Extractions

Capture structured data fields from calls

Webhooks

Receive disposition results in real-time

Executions API

Fetch disposition results from past calls