Skip to main content
Runs a calculation against a published domain. A calculation happens inside a conversation: omit conversation_id to start a new conversation, or pass one to continue an existing one.

Request

Send an Idempotency-Key header to make a request safe to retry and to poll. Since natural language requests return immediately with 202 Accepted, an Idempotency Key is required to retrieve the final result. See Limits.

Natural language input

Structured input

Structured input is a set of key: value lines — one variable per line — plus a calculate: line naming the variable to solve for. For the full grammar — values, units, tables, scenario selectors, and how omitted lines are inferred — see Input formats.

JSON input

A JSON request sets input_format to json and passes a JSON string as prompt. Like structured text, it involves no language model and runs synchronously — the result returns in the same response. For the full object — inputs, calculate, scenario, and value conventions — see Input formats.
A prompt that parses as JSON but does not match the schema returns input.invalid_input_schema; a prompt that is not valid JSON returns the transport error error_invalid_json.

Automatic detection

Set input_format to automatic — or leave it out, or pass null or "" — to let TrueMath determine from the prompt whether it is natural language, structured text, or JSON, and process it accordingly. This is the default when the field is absent.
Because the detected format governs processing, the same request behavior applies once it is resolved — a prompt detected as natural_language is processed asynchronously, while one detected as structured or json runs synchronously. Specify input_format explicitly when you already know the format and want to skip detection.

Time zones

A stored date or clock time carries no time zone and never shifts. A value meaning 2:30 PM on July 21st reads as 2:30 PM on July 21st for every caller, in every country: it is never re-projected into a viewer’s zone and shown as 5:30 PM. That is why the UTC pin under Dates and durations renders one correctly — there is no zone to convert from. A zone is used for one thing, and has no other effect: reading what today and now mean at the moment a calculation runs and, with them, what year a date written without one falls in. Two things supply that zone:
  1. The request. Over the API that is the time_zone parameter, an IANA name such as America/New_York. In the Playground it is the browser’s own zone, sent with each calculation — never a timestamp, so a device with a wrong clock cannot move what today is. Either way the zone is applied once per request, so every keyword in one calculation agrees.
  2. Your account’s time zone, when the request supplies none or names a zone that is not recognized. That covers the API, an integration, and a scheduled job.
Every account has a time zone. It is detected from the browser the account was created in and can be changed in account settings; where detection is not possible it is UTC. The fallback is always a real zone rather than an unset one. Send your user’s zone whenever a person is waiting on the result. It is the only control you have over what those two words mean, and for an integration the account default may be nowhere near your user.

Response

The response echoes the conversation, message, and request metadata, and reports its outcome with status. A completed or error outcome returns 200 OK; an asynchronous request that is still running returns 202 Accepted with status: "in_progress". The echo of your input depends on the format. A structured request returns its result as structured_text. A natural_language request returns the natural_language reading plus the parsed input as parsed_json. A json request returns the parsed input as parsed_json. structured_text is always a key on a completed response — null for natural_language and json — while natural_language and parsed_json are present only for the formats noted above and omitted otherwise.

Completed

A completed calculation returns status: "completed" and a results object: the action taken, the scenario indexes, the activities applied, and every variable with its value, provenance, and display format. results.calculated is the id of the variable that was solved for (null when action is fetch).
Each variable’s key is its creator-defined variable name. source is user_input, calculated, or default_value, and historical indicates whether the value was carried forward from a prior scenario. value is a combined "value unit" string at full precision — the unit is part of the value string (see Units and precision). For a table, value is an array of such strings (nested for a 2-D table); see Tables. The scenario object reports the original scenario the calculation started from (0 starts a new scenario) and the current scenario the results belong to. action is one of new, extend, discard, or fetch — see Scenarios. When action is fetch, retrieve that scenario with GET /v1/conversations/:id/context.

Display formats

Each variable carries a display object. data_type selects its shape — number, table, bar_chart, or pie_chart — and the remaining fields depend on it. It names the shape of the object, not the kind of the value: a date, a percent, and a plain number all arrive as number, and display_type is what tells them apart. Two fields recur across shapes: number — any single value: a scalar or unit number, a percent, or one of the four dates and durations.
table — a grid with per-column formats and optional row names.
bar_chart — a table presented as a bar chart.
The series array above names each series (name) and says how its values are formatted (display_type and decimal_format). It should match the number of series in the variable’s value itself. What each of these settings does to the chart is in Authoring charts. series_by describes whether each series is a row or a column of the table. A database, for instance, generally holds its series in columns. When labels.source is index, all data from the table is plotted and the x-axis labels are derived as integers starting with start_series_index. When labels.source is first_series, the first series in the table is used as the x-axis labels instead and not included in the chart’s plotted bars. How that data is formatted is derived from the metadata within series[0]. Your first plotted bar is therefore the second series, described by series[1]. pie_chart — a table presented as a pie chart.

Dates and durations

A display_type of duration, date, datetime, or time marks a value stored as a count of seconds carrying the unit s. The API renders nothing: the number arrives with its kind and its format token beside it, and you render it yourself.
Rendering one takes three facts, and the second one fails silently.
  1. Seconds, not milliseconds. new Date(1784592000) is 1970-01-21. Multiply by 1000.
  2. Format in UTC. The number is a naive wall clock — its components are the value, and it is not an instant in any particular zone. A zone-aware formatter moves the day.
  3. Branch on display_type. It changes the arithmetic, not just the format. A duration is a span with no date involved and never becomes a date. A time counts from midnight, which is the same number on 1970-01-01, so a UTC-pinned time-only format works. A date and a datetime count from the epoch.
Skip the UTC pin and the day moves. In Los Angeles, toLocaleDateString() renders 1784592000 as 2026-07-20 for a value that means 2026-07-21 — off by one day, for roughly half the world, and only in some seasons. Nothing reports an error.
What each format token renders is listed in Choosing a format.

Chart scaling

A chart whose cells carry different units of the same dimension3 ft, 4 in, 5 yd — is drawn to one common unit, so its bars and slices are proportioned honestly; see Mixed units in a chart. The API renders nothing, so it hands you those converted magnitudes: the variable carries them alongside value and display, in these fields. They are present only when relevant. value is unchanged and is what labels and tooltips are drawn from. A chart variable is in exactly one of three states:
  1. Scaledscale and scale_unit are present. Plot from scale, label the axis with scale_unit, and show the original value cell in tooltips.
  2. Incompatiblescale_incompatible and scale_types are present. There is no common axis; render a short message instead of a chart.
  3. Neither — no scale fields. The column is a single unit or unitless; plot the numeric part of each value cell directly, with the first cell’s unit as the axis unit.
scale values are full precision — format them with the variable’s display decimal settings, the same as value.
The bars sit at 3, 0.333, and 15 on a ft axis, while the second bar’s tooltip reads 4 in — the original authored value, not 0.333 ft. When the cells span different dimensions, no chart is drawn:

In progress

Natural-language requests will be processed asynchronously; structured-text and JSON requests run synchronously and never return in_progress. When a natural-language request is still running, the API responds with 202 Accepted, status: "in_progress" and no results:
To get the result for natural language requests, re-post the same body with the same Idempotency-Key until status is completed or error. Leave a 1–2 second gap between retries. This could take multiple retries but rarely more than 20 total. You can also poll the conversation with GET /v1/conversations/:id.

Error

A calculation that cannot complete returns status: "error" with an errors array. Each entry has a code and message, plus conditionally included args, offset, and missing fields (present only when the error uses them).
See Errors for what args, offset, and missing contain, and the full list of calculation error codes.

Transport errors

Problems with the request itself — rather than with the calculation — return a 4xx or 5xx status and a single error object: