Skip to main content
Legacy features off — 18 September 2026. After this date, custom_extractions and agent_extraction return null, and flat keys stop appearing in extracted_data. All results consolidate into extracted_data, nested category → extraction name → result object. Each value changes from a scalar to an object. This is a breaking change for any webhook, API, or CSV consumer.
Both shapes are populated today. Deploy the new read path, diff it against the old one on live calls, then disable the legacy features.

Am I affected?

Check a recent webhook payload or GET /executions response:
Legacy Extraction, Agent Extraction, and Custom Analytics toggles in the agent Extractions tab

The agent Extractions tab showing the Extraction toggle, the Agent Extraction toggle marked Internal, and the Custom Analytics section, under a heading badged to be deprecated.

Note the naming overlap: the block being retired is also labelled “Extractions.” The to be deprecated badge is what tells them apart.
Already migrated? Only nested keys means you are already on Extractions and no action is needed. Both shapes can appear together during the transition, with flat legacy keys sitting alongside nested categories. Check for flat keys specifically, rather than assuming you are done because nested ones are present.

Migration by feature

Four features, four different paths. Open the one whose field appears in your payload.

Extraction

extracted_data · flat keys → Rebuild as extractions. One extraction per field in your prose box. Keys stay stable if you reuse your current names.

Custom Analytics

custom_extractionsRebuild, one per item. Types map onto answer types. Numbers become strings, and min/max clamping has no equivalent — use validation.is_valid instead.

Agent Extraction

agent_extractionDiscontinued. No replacement template and no migration on your behalf. Identify the fields from a payload and author your own.

Call Summary

summaryNo change required. Stays a flat top-level key, now sourced from the Call Summary extraction. Keep reading it as you do today.

What the payload looks like

Category is a grouping label you choose. Name is the key you choose.

Result object fields

Which field to read:

Breaking changes

  • Values are two levels deeper. extracted_data.call_reason becomes extracted_data["Call Details"]["Call Reason"].
  • Values are objects, not scalars. Select objective or subjective from the result.
  • subjective and objective are always JSON strings. A numeric extraction returns "250000", not 250000. Custom Analytics returned a real number, so parse it yourself. Min/max clamping has no equivalent; use validation.is_valid to confirm the value parses.
  • custom_extractions and agent_extraction return null once the feature is removed from the agent, or on 18 September 2026. The keys stay in the payload.
  • summary stays a flat top-level key. Webhook payloads keep summary as a string at the top level, now populated by the Call Summary extraction instead of the legacy summarisation task. If you read top-level summary today, no change is required.
  • objective cannot drift. Pre-defined answers are constrained by the request, so the value matches your configured option character for character. Switch fuzzy matching to exact comparison.
  • New capabilities: per-answer confidence, LLM reasoning, and format validation. Route confidence_label: "Low" to human review.

Expected formats

A failed check never loses the value. is_valid: false is set and subjective holds the LLM’s response unchanged.

Calls with no user speech

This ships on 18 September 2026, alongside the deprecation. It applies to every agent, including ones already using Extractions. When a call contains no user turns (voicemail, an immediate hangup, dead air), the LLM has nothing to work from. Today it can still invent a plausible answer. From 18 September 2026 it will instead return a fixed sentinel across every extraction on the agent.
No user turns detected, from 18 September 2026
No User Turn Detected will appear in subjective, objective, reasoning_subjective and reasoning_objective, in every extraction across every category.
  • The top-level summary key will return it too. Anything writing summary into a CRM note, ticket field, or report will write that string. Check for it before persisting.
  • objective will return the sentinel even though it is not one of your configured options. Exact-match comparisons will not hit any branch, so handle the sentinel before comparing.
  • confidence will be 1.0 and confidence_label "High". The score reflects certainty that no user spoke, not certainty about an answer. Filtering on confidence alone will not exclude these calls.
  • Typed extractions will return the sentinel as a string. A numeric extraction returns "No User Turn Detected", so guard your parsing.
Check for the sentinel before reading any extraction value, and route these calls to your no-contact path rather than treating them as answered.

CSV exports

Seven columns per extraction instead of one, following extracted_data_<Category>_<Name>_<field>. Update any loader or formula referencing columns by name.

Configuring through the API

Extractions are managed under /dispositions. “Disposition” is the API’s name for a single extraction. The /extractions path is an internal template registry, not this endpoint.

Creating one

POST
  • name is the result key. category is the key above it.
  • question is the LLM prompt. State what to look at, what to ignore, and what each option means.
  • Always include a fallback option such as NA so the model is never forced to pick a real answer for a question the call never reached.
  • Set is_subjective: true for free text, is_objective: true for pre-defined, or both.
  • subjective_type accepts text, numeric, boolean, email, timestamp, regex. regex also requires subjective_type_config: {"pattern": "…"}.
  • Extractions in one category are answered in a single LLM call, so grouping related fields keeps their answers consistent with each other.

Verifying a migration

POST /v2/agent/{agent_id}/dispositions/test
Returns {"extracted_data": {…}} in exactly the shape a live call produces. Paste a real past transcript and diff against what your old configuration returned for that call. No call is spent.

Running both side by side

extracted_data is a shared field. While a legacy extraction task and Extractions are both enabled, one object holds both shapes, with flat legacy keys alongside nested categories:
During the transition
Check which shape you have rather than assuming. A nested category is an object whose own values are objects containing subjective and objective. Branching on the nested shape stays correct during and after the transition.
Namespace collision. Do not give a category the same name as a legacy extraction key while both run. They share one namespace and will collide.

Timeline

1

Now

Old and new run side by side. Newly created agents get Extractions only.
2

18 September 2026

custom_extractions and agent_extraction return null. Flat keys stop appearing in extracted_data. summary continues, sourced from the Call Summary extraction. Unmigrated configurations return no results.
No extension and no dual-write period past 18 September. Migration is self-serve, so we do not convert or map configurations on your behalf. Raise blockers this week, not in the final week.

FAQ

No. Completed calls keep the results and shape they were stored with, readable indefinitely. Only calls placed after you migrate use the new shape. Code that reads historical calls must keep handling the old shape permanently, not just until the cutoff.
Yes, and it is the recommended path. Change the read path first, then disable the legacy features once you have compared the two on live calls. See Running both side by side.
Free-text answers may be phrased differently for an identical call, because the prompt structure differs. Pre-defined answers are stable, since they can only be one of your configured values. Diff side by side before disabling anything.
Yes. Set each extraction’s name to your current key. The name is unchanged; the path is one level deeper.
No. Recreating extractions is self-serve, through the dashboard or the /dispositions API. This includes Agent Extraction, which is discontinued rather than replaced.
Agents keep taking calls. Only structured results stop: legacy fields return null, and no extractions run unless configured. Transcripts, recordings and call summaries are unaffected.
Email support@bolna.ai with the execution_id of the call, the field you were reading, and the value you expected. The execution_id is the id in the webhook payload and in GET /executions responses. One id is much quicker for us to work with than a description of the problem — we can pull that exact execution and see which extraction path produced the value.
Email support@bolna.ai to remove a legacy summarisation task, or with an execution_id for a payload that does not match this guide.

Next Steps

Using Extractions

Configure extractions in the dashboard

Dispositions API

Manage extractions programmatically

Webhooks

Receive extraction data in real-time