Skip to main content

Item List Prefill

Allows an Item List node to present a pre-populated table of candidate items to the user before they start adding iterations. Each candidate row can be selected as the starting point for a new iteration — the candidate's data is written to the carousel's #Start node, where iteration questions can reference it as default values. Once a candidate has been used to fill an iteration it is flagged as Used, allowing the UI to hide or de-emphasise already-consumed rows.

The most common data source is the OCR Extraction Logic Item, which reads uploaded receipt images and produces a JSON array of line items that is stored in the conversation value bag under the key Items. That array is then forwarded to the Item List node's PrefillData input by referencing [ocr.Items].


How it works end-to-end​

OCR Logic Item
└─ extracts Items from uploaded receipts
└─ stored in value bag as JSON array

Item List node (ListFromCarousel type)
└─ PrefillData = "[ocr.Items]" ← resolved at runtime to the OCR array
└─ PrefillTableDefinition ← describes which columns to display

GET /carousels/{id}/iterations
└─ ?prefillCandidateId={hash} ← pick a candidate row

SectionPlayer writes candidate fields to #Start node
└─ Start.Description, Start.TotalPrice, …

Iteration questions use Start.* as default values

POST /carousels/{id}/iterations/{n}
└─ ?prefillCandidateId={hash} ← must be repeated on save

Candidate is marked as Used in the carousel iteration value bag
└─ PrefillTable.DataRows[n].Used = true (next GetPrefillTable call)

Node input configuration​

The Item List node receives its prefill configuration via ListFromCarouselNodeInput.

FieldTypeDescription
PrefillDatastring (JSON array)Serialized array of objects. Each object is one prefill candidate. Typically populated from the OCR value bag with [ocr.Items].
PrefillTableDefinitionstring (JSON array of ColumnDefinition)Defines which columns appear in the prefill table and which property of each candidate maps to each column.
ShowTotalSumstring ("true" / "false")Whether to show a sum row at the bottom of the prefill table.
TotalSumLabelstringLabel displayed next to the total sum.
TotalSumUnitsstringUnits displayed next to the total sum (e.g. "EUR").

Column definition (ColumnDefinition)​

Each entry in PrefillTableDefinition controls one column of the prefill table.

FieldTypeDescription
TitlestringColumn header text (can be a message key resolved from conversation history).
ValuestringDot-notation path into the candidate object, e.g. "Description" or "tax.rate".
IsSummableboolWhether values in this column contribute to the total sum row.
MessageTypestring?Visual type hint for the cell (defaults to InputText).

Example PrefillTableDefinition​

[
{ "title": "Description", "value": "Description", "isSummable": false },
{ "title": "Amount", "value": "TotalPrice", "isSummable": true },
{ "title": "Tax rate", "value": "tax.rate", "isSummable": false }
]

The prefill table (PrefillItemListTable)​

When the Item List node is initialised and EnableItemListPreliminaryItems is enabled, ItemListLogicItem exposes a PrefillTable property on the API response.

FieldTypeDescription
CarouselNodeIdstringID of the carousel node this table belongs to.
ColumnsDictionary<int, ItemListColumn>Column definitions keyed by column index.
DataRowsPrefillItemListRow[]One row per candidate item.
ShowTotalSumboolMirrors the node input setting.
TotalSumLabelstringMirrors the node input setting.
TotalSumUnitsstringMirrors the node input setting.

Prefill candidate row (PrefillItemListRow)​

FieldTypeDescription
PrefillCandidateIdstringStable content-derived identifier for this candidate (8-char Base64url-encoded MD5 of the sorted item JSON). Survives re-processing — two rows with identical content always produce the same ID. Pass this value as prefillCandidateId on both API calls.
Usedbooltrue if an active (non-stale) iteration has already been filled from this candidate. Use this to hide or grey-out already-consumed rows in the UI.
CellsDictionary<int, string>Column index → display value for this row.

Content hash identity​

PrefillCandidateId is computed as:

  1. Sort the candidate object's properties alphabetically (recursively for nested objects).
  2. Serialize to compact JSON.
  3. Compute MD5 of the UTF-8 bytes.
  4. Encode as Base64url, take the first 8 characters.

This means the ID is position-independent — reprocessing the OCR or reordering the source array does not change the ID for an unchanged item. Two different items with identical content hash to the same ID; in practice this is safe for any realistic prefill dataset.


API usage​

1. Fetch the prefill table​

The PrefillTable is returned as part of the standard Item List node payload whenever the node is fetched. No additional call is needed.

GET /api/v1/conversations/{conversationId}/sections/{sectionId}

Response includes the prefillTable property on the Item List visual node when candidates are available.


2. Create a prefilled iteration​

Pass the chosen PrefillCandidateId as a query parameter when requesting a new iteration.

GET /api/v1/conversations/{conversationId}/carousels/{carouselNodeId}/iterations
?prefillCandidateId={hash}

Effect:
The backend resolves the candidate item whose PrefillCandidateId matches the hash, flattens all its properties using dot-notation (e.g. tax.rate → key "tax.rate"), and writes each key-value pair into the #Start node's value bag for the new iteration.

Iteration questions can then reference those values using the Start. prefix, for example:

Reference in questionResolves to
Start.Description"Wireless Mouse"
Start.TotalPrice"29.90"
Start.tax.rate"21"

This pre-populates the question's default value, which the user can accept or override.


3. Save the iteration with the same candidate ID​

When saving a completed iteration, pass the same prefillCandidateId query parameter.

POST /api/v1/conversations/{conversationId}/carousels/{carouselNodeId}/iterations/{iterationId}
?prefillCandidateId={hash}

Body: { "visualNodeResults": [ … ] }

Effect:
On successful save the candidate ID is stored in the iteration's value bag under __itemListPrefillCandidateId. The next call to GetPrefillTable will compare that stored hash against every candidate and set Used = true on any matching row.

Important: if prefillCandidateId is omitted on the save call the candidate will not be marked as used, even if it was supplied on the get call.


Used flag and UI behaviour​

The Used flag on each PrefillItemListRow reflects whether an active (non-stale) iteration was created from that candidate.

  • If an iteration is later edited and re-saved without a candidate ID, the stored hash remains and the candidate stays marked as used.
  • If an iteration is deleted (marked stale), its stored hash is excluded from the used-set calculation and the candidate becomes available again.
  • The flag is read-only — it is recomputed fresh on every GetPrefillTable call from the current carousel state.

Recommended UI behaviour:

UsedSuggested presentation
falseShow row normally; allow selection
trueGrey out / hide row; optionally show a "already added" indicator

Full example — OCR receipt to prefilled iteration​

Setup​

Conversation properties on the OCR node:

ocr-Items = ""
ocr-MerchantName = ""
ocr-TransactionDate = ""

Item List node input:

{
"prefillData": "[ocr.Items]",
"prefillTableDefinition": "[{\"title\":\"Description\",\"value\":\"Description\",\"isSummable\":false},{\"title\":\"Amount\",\"value\":\"TotalPrice\",\"isSummable\":true}]",
"showTotalSum": "true",
"totalSumLabel": "Total",
"totalSumUnits": "EUR",
"carouselNodeName": "vWGkRI"
}

Runtime flow​

1. OCR runs and stores in value bag:

Items = "[{\"Description\":\"Wireless Mouse\",\"TotalPrice\":\"29.90\",\"MerchantName\":\"Demo Store\",\"TransactionDate\":\"2026-05-07\"}]"

2. Item List node is fetched — PrefillTable in response:

{
"prefillTable": {
"carouselNodeId": "vWGkRI",
"columns": {
"0": { "key": 0, "title": "Description", "isSummable": false },
"1": { "key": 1, "title": "Amount", "isSummable": true }
},
"dataRows": [
{
"prefillCandidateId": "Or8sHQ2k",
"used": false,
"cells": { "0": "Wireless Mouse", "1": "29.90" }
}
],
"showTotalSum": true,
"totalSumLabel": "Total",
"totalSumUnits": "EUR"
}
}

3. User picks the row — UI calls:

GET /api/v1/conversations/conv1/carousels/vWGkRI/iterations
?prefillCandidateId=Or8sHQ2k

The #Start node for the new iteration is populated:

Start.Description = "Wireless Mouse"
Start.TotalPrice = "29.90"
Start.MerchantName = "Demo Store"
Start.TransactionDate = "2026-05-07"

Iteration questions referencing Start.Description show "Wireless Mouse" as the default value.

4. User confirms — UI calls:

POST /api/v1/conversations/conv1/carousels/vWGkRI/iterations/1
?prefillCandidateId=Or8sHQ2k

{ "visualNodeResults": [ … ] }

5. Next GetPrefillTable call returns:

{
"prefillCandidateId": "Or8sHQ2k",
"used": true,
"cells": { "0": "Wireless Mouse", "1": "29.90" }
}

The UI hides or disables the row.


Feature flag​

The prefill feature is gated by ICoreFeatureToggleSettings.EnableItemListPreliminaryItems.
When the flag is false, PrefillTable is always null and prefill candidate IDs passed to the API are ignored.