Skip to content

Values and types

Every connection in a workflow carries a value of one type, and every port says which type it takes. The catalog uses about a dozen of them; on the data side, four matter:

Type Values Examples
text a string a customer name, a brief, a URL, a language code
number a finite JSON number a quantity, a price, a threshold, a duration in seconds
boolean true or false “express delivery”, “include subtitles”
json one JSON document: an object or an array an order, a product record, the answer of an AI model in JSON mode

Files have their own types (image, video, audio, pdf, document, …), and a few ports take any when a node passes a value through unchanged — a filter, for instance.

A workflow receives its values through input nodes, one per value that changes from run to run:

Node Emits Use it for
Text Input (input/text) text names, briefs, prompts, codes
Number Input (input/number) number quantities, thresholds, durations
Boolean Input (input/boolean) boolean switches a person turns on or off
JSON Value Input (input/json_value) json one whole document: an order, a record, a plan

Each input has a value used when the run does not provide one, and a Required switch. A required input must receive a value or keep its authored one; an optional input may be left empty — then the nodes that need it are skipped and everything else runs (see Branches and absence).

The value of a JSON Value Input is a JSON document written in its Default value field: an object, an array, a number, true or false, or a string written as JSON, quotes included ("draft"). Format & validate checks it as you type, and Import .json loads it from a file, up to 256 KB. A workflow saved with a value that is not JSON is refused (invalid_json_input_value, or json_input_value_too_large above 256 KB), so it never fails later on its own example. Through the API, parameters.value is the JSON itself ("value": [{"sku": "TP-01"}]); the text of a JSON document is accepted too. A value passed to the run always replaces it.

A value that is the same on every run is not an input: it is a parameter of the node that uses it, or a Constant (utility/constant) when several nodes need it.

Madoo never turns one type into another on its own. A Number Input refuses the text "2"; a boolean refuses "yes" and "true" written as text; a text is never read as a number because it looks like one.

This is deliberate. Silent conversion is where data bugs come from: "19,90" read with the wrong decimal separator becomes 1990, "0012" loses the zeros that made it a product code, "no" becomes true because it is not empty. Each of these produces a result that looks right. Refusing the value instead produces an error you can see and fix — before anything is spent.

When the wrong type reaches Madoo, the error names it:

  • At the start of the run. An API call, an MCP tool or an app that sends text to a number or boolean input is refused before the run starts, with 400 validation_error and a message such as Input 'gift_wrap_count' expects a number (for example "5"), not text: a value is never converted from text. No credit is reserved.
  • Inside a JSON document. A field of the wrong type is caught where it is read, by Extract with an expected type: Value at 'customer.vip' is 'text', not the expected 'boolean'. (EXTRACT_TYPE_MISMATCH).

Over the API, every input value is sent JSON-encoded: the text "Giulia" as "\"Giulia\"", the number 5 as "5", the boolean as "true", an object as its JSON text. The details, with code, are in Executions.

A JSON array can mean two different things, and Madoo has a node for each:

  • One value. An order with its lines is one document: the workflow reads fields from it, passes it to a template, stores it. Use JSON Value Input (input/json_value). It never iterates, even if the document is an array.
  • A list to work through. Twelve products to describe, one image each: every item runs the downstream nodes once. Use Enumerate JSON (enumerate/json), or JSON Input (input/json) when the list itself is the input. That is the subject of Iteration.

Choosing wrong is easy to notice: a whole list reaching a node that expected one item, or twelve runs of a node that should have run once.

A JSON value can travel inline, as part of the run, or as a stored JSON file: Aggregate JSON (aggregate/json) always stores the collection it builds, and very large values are moved to storage. The nodes that read JSON documents — Extract, Calculate, the Quality Gate and the nodes of the domain contracts (caption tracks, plans, manifests) — read both the same way, so you never need to know which one you have.

A file of another kind (an image, a PDF) is never read as JSON: connect it to a node made for that file.

A prompt, a caption or a message is text, and the values you want in it often are not: a total from Calculate, a delivery date, a yes/no decision, a list collected by Aggregate JSON. The placeholders of a Text Template (text/template) take text, so a value that is not text passes through Format as Text (text/format) first. That is the one place where a value becomes text, and where you choose how it reads:

Format Value it-IT en-GB
currency (EUR) 83.07 83,07 € €83.07
number, 2 decimals 1234.5 1.234,50 1,234.50
percent 0.22 22% 22%
date, long "2026-10-03" 3 ottobre 2026 3 October 2026

json writes a document on one line or indented, ready for a prompt; auto keeps text as it is, writes a number as it is written in JSON and a boolean as the words you choose for it (Sì/No, Yes/No). The language and the currency are parameters, or inputs when they come with the data: connect the language of an order to locale and one workflow writes each customer’s total the way that customer reads it. Money and numbers follow the same rules as the number formats of document templates.

Nothing is converted here either. A number format given the text "19,90", or a date format given "next Friday", fails with FORMAT_TYPE_MISMATCH instead of guessing: compute the number first, then format it.

When an optional input is left empty, the input node reports its value as absent. The nodes that cannot work without it are skipped — not failed — and the run still succeeds; the nodes that can work without it run. An optional reference image, for instance, is simply left out of the generation.

Absence has a second meaning, rejected, when a decision cuts a branch: that one stops every node it reaches. The difference matters as soon as a workflow contains a filter; it will have its own page in this section.

The values and JSON lab receives an order as JSON, a boolean and a number, and reads typed values out of the order. It is described with its results in Reading JSON.