Tools reference
Every tool Ontyx offers your assistant for your organization’s own data, with its inputs and what it answers. Your assistant reads the same descriptions and picks the tools itself; this page is for checking what a tool does, or for building on Ontyx directly.
- Every tool acts on the organization of the person signed in, worked out on each call from their membership.
- Who can call it. Tools that only read can be called by any member: owner, admin or reader. Tools that change anything can be called by owners and admins only. A reader’s assistant isn’t shown them, and a reader who calls one anyway is refused before anything happens.
- Tool names are stable. The tools for datasets, metrics and views are named
<resource>_<action>. - Answers are JSON:
{ "ok": true, … }on success,{ "error": { "code", "message" } }on a refusal. Messages are written to be passed on in plain words. No tool takes code or returns it. - Versions are always named:
schema_versionfor a structure,data_versionfor a load,metric_versionfor a metric. No answer carries a bareversion. - Dates are ISO 8601. A date and time without an offset is read in its column’s time zone.
- While your organization is getting started, answers carry
next_step: the natural next call. - None of these tools is metered.
The fields every data-returning answer carries (as_of, freshness, filters, read_from and the rest) are explained in Asking questions.
Errors
| Code | Meaning |
|---|---|
INVALID_REQUEST | The request doesn’t fit: a misspelled name (with a suggestion), a value of the wrong kind, a change the rules don’t allow, or rows that don’t fit (with failed_checks naming the checks they didn’t pass). |
NOT_FOUND | No dataset, metric or view by that name in your organization. A near miss gets a suggestion. |
CONFLICT | The state changed or doesn’t allow it: a change is already waiting, rows landed since a change was proposed, an uploaded file hasn’t arrived, a retired metric was asked, or a change would stop an approved metric. |
FORBIDDEN | The person’s role can’t do this: only an owner or admin can. |
ACCOUNT_NOT_SET_UP | The person isn’t in an organization yet. They need an invitation. |
TERMS_ACCEPTANCE_REQUIRED | The account hasn’t accepted the current Terms of Service. |
TIMEOUT | A question ran past its time limit (20 seconds) and was stopped. Ask a narrower one. |
UNAVAILABLE | It couldn’t be answered just now. Try again. |
UNAUTHENTICATED | The sign-in or key is missing, invalid or revoked. |
RATE_LIMITED | Too many requests in a short time. The error carries retryAfterMs. |
Datasets
dataset_list
The organization’s datasets and the state of each.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
marked_for_deletion | no | true lists only the datasets marked for deletion, soonest to go first, with deleted_after. |
looking_for | no | What the person is after, in a few words (1 to 200 characters), such as "ammo prices by caliber". The answer is then the closest datasets instead of the whole list. Can’t be combined with marked_for_deletion: true. |
Answers with count and datasets, each with name, description, status (waiting_for_approval, needs_new_proposal, ready or change_waiting_for_approval), schema_version, waiting_schema_version, has_data, data_version, as_of, freshness (and freshness_note when it’s out of date), expected_cadence, its relationships with how they matched at the last load, referenced_by (the datasets that point at it), and derived and sources for a dataset built from others. An organization with no datasets gets a message saying what Ontyx is for and the first step. Past 20 datasets, a note suggests looking_for.
With looking_for, it answers with the closest datasets, at most 5, in matches, closest first. Each has name, description, status, has_data, data_version, as_of, freshness (and freshness_note), rows (how many rows it has), columns (each column’s name and type), the approved metrics that read it (name and label), the saved views that ask those metrics, matched_on (which of its name, description and columns matched) and match: strong when its name matched or two or more of the words did, otherwise possible. others says how many datasets weren’t shown, and message sums it up in a sentence. When nothing matches, matches is empty and the message names every dataset, so your assistant can pick one or ask you without a second call.
The closest datasets are found by the words they share with what you asked: the dataset’s name counts most, then its column names, then its description. Common words are ignored, plurals and word endings are matched (prices meets price), and a shortened word is enough (ammo meets ammunition, temp meets temperature). The same words always give the same order. Datasets marked for deletion are never matched. If an answer would be too large, the column lists are left out first, then the descriptions, and a note says so.
dataset_define
Proposes a new dataset: structure version 1. No data can be loaded until an owner or admin approves it.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
name | yes | The short name: lowercase letters, digits and _, starting with a letter, up to 63 characters. Unique among the organization’s datasets, metrics and views. |
description | no | What the dataset is, in a sentence. |
columns | yes | Every column, in order (1 to 500): name, type, and optionally scale, timezone, nullable (default true) and description. |
key | no | The columns that together identify each row, in order (up to 8). Each must have nullable: false and can’t be json. |
default_load_mode | no | replace (default), append or upsert (needs a key). |
expected_cadence | no | hourly, daily, weekly, monthly, quarterly or yearly. |
keep_raw | no | Keep a copy of each original record (default true). |
relationships | no | Up to 10, each { columns, parent }: this dataset’s columns that hold the identifiers of rows in parent (which may be this dataset), in the order of the parent’s key. |
checks | no | Up to 50: { kind: "not_null", column }, { kind: "unique", columns } or { kind: "accepted_values", column, values } (up to 200 values). |
note | no | Where the data comes from, or why it’s shaped this way. |
Column types: string (text), integer (whole number), number (measurement or coordinate), decimal (exact amount; scale 0 to 6 decimal places, default 2), boolean (yes/no), date, timestamp (date and time, stored in UTC; timezone is the IANA zone for source times with no offset), json (a list or nested value kept whole). Column names may use dots for nested fields (properties.mag) and are case-insensitive.
Answers with dataset, status, and proposal: its schema_version and a summary of the structure in plain words to show the person.
dataset_get_schema
A dataset’s structure: what’s in force, what’s waiting, and its history.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
Answers with status, has_data, data_version, current (the approved structure in force: schema_version, columns, key, load mode, checks with each in words, relationships with their latest match), waiting_for_approval (the waiting change with its changes and warnings, or a first structure’s summary), history (the last 20 structure versions with who proposed and decided them, and any rejection_reason), last_rejected while the newest version is a rejected one, referenced_by, and derived for a dataset built from others.
dataset_propose_schema_change
Proposes a change to a dataset’s structure, as edits. It’s checked against the change rules (see Datasets) and, where data exists, against the rows already loaded. One change can wait at a time.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
add_columns | no | New columns, added at the end (same shape as in dataset_define). |
remove_columns | no | Columns to remove. Columns that identify a row can’t be removed. |
change_columns | no | Edits to existing columns by name: a wider type, scale, timezone, nullable, description. |
key | no | Only for a dataset with no key yet: the columns that will identify each row. The rows already loaded must have no blanks and no repeats in them. |
default_load_mode | no | replace, append or upsert. |
keep_raw | no | Keep a copy of each original record. |
add_relationships | no | Relationships to add, as in dataset_define. With data, the matches are counted and shown; refused only when no row matches. |
remove_relationships | no | Relationships to remove, by parent and columns. |
add_checks | no | Checks to add. An accepted_values check for a column that has one replaces its list. |
remove_checks | no | Checks to remove, by kind and column. |
description | no | A new dataset description. |
expected_cadence | no | A new refresh schedule. |
note | no | Why the change is being made. |
retire_metrics | no | Only after a refusal because the change would stop approved metrics working: exactly the metrics it named, to retire them when the change is approved. |
Answers with status and proposal: its schema_version, the changes in plain words and any warnings, relationship_checks for relationships it adds, and metrics_to_retire when it retires any.
dataset_approve_schema_change
Makes a waiting structure version (a new dataset’s first one, or a change) the one in force. Your assistant may only call it after the person says yes to that exact version in the conversation. Approval runs the data checks again, in case rows landed since the proposal. Approving a dataset built from others builds it.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
schema_version | yes | The structure version the person was shown. |
confirmed_by_person | yes | Must be true: the person said yes to this exact version. |
Answers with decision, decided_by, decided_at, status, schema_version_in_force, has_data, and when they apply relationship_checks, retired_metrics and built.
dataset_reject_schema_change
Discards a waiting structure version because the person said no. What’s in force stays as it is.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
schema_version | yes | The structure version to reject. |
reason | no | Why, in the person’s words (up to 1,000 characters). It’s kept with the rejected version. |
Answers with decision, rejection_reason and schema_version_in_force.
Loading data
dataset_load_rows
Loads rows sent in the call: JSON objects or CSV text. Every row is checked first; if any doesn’t fit, nothing is loaded.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. Its structure must be approved. |
rows | one of rows or csv | Up to 5,000 rows as JSON objects keyed by column name. Nested objects fill dotted columns. |
csv | one of rows or csv | Up to 5,000 rows (2,000,000 characters) of CSV text with a header row. |
mode | no | replace, append or upsert. Default: the dataset’s own. For more rows than one call carries, send the first batch with the dataset’s mode and the rest with append (or upsert). |
as_of | no | When the data is true of the world, with an offset (2026-10-01T00:00:00Z). Default: now. |
Answers with data_version, mode, rows_loaded, rows_added, rows_updated (upsert), rows_already_there (append or upsert on a keyed dataset), identical_rows_combined (when some were), total_rows, as_of, fields_without_a_column (when the original record keeps them), checks (everything it verified) and a message. A refusal is INVALID_REQUEST with every problem, up to 20, and failed_checks. See Push API for each field.
dataset_begin_upload
Starts loading a file too big to send inline: up to 100 MB.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. Its structure must be approved. |
format | yes | csv (with a header row), json (one list of records), jsonl (one record per line) or parquet. |
mode | no | replace, append or upsert. Default: the dataset’s own. |
as_of | no | When the data is true of the world. Default: now. |
Answers with upload_id, expires_at (about 30 minutes), largest_file, upload_page (a link for the person to open and choose the file), upload_command (a ready curl line, for an assistant that can run commands) and put (the address, method and exact headers for any other client).
dataset_finish_upload
Checks the uploaded file and loads it as a new data version, or refuses it. Either way the uploaded file is then discarded, so a corrected file needs a new upload. If the file hasn’t arrived yet, it says so (CONFLICT), and finishing can be tried again.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
upload_id | yes | The id dataset_begin_upload returned. |
Answers as dataset_load_rows does, plus file_size.
Looking and asking
dataset_preview
How many rows a dataset has, when it was loaded, whether it’s up to date, a summary of each column, and the first rows.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
limit | no | How many rows to show from the start: 0 to 100, default 20. |
include_original | no | Also show each row’s original record, when the dataset keeps it. Default false. |
Answers with the row envelope, total_rows, columns (for each: its type in words, blanks, smallest, largest and about how many distinct_values), showing and rows.
dataset_query
Answers a question from one dataset’s rows: filter, sort, group and total. See Asking questions.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
columns | no | Columns to show, in order (up to 100). Not with group_by or aggregates. |
where | no | Up to 20 filters, all of which must hold, each { column, op, value }. op is eq, ne, gt, gte, lt, lte, in (a list of up to 100), between (two values, both included), contains (text, ignoring capitals), is_blank or not_blank. |
group_by | no | Up to 5: a column, or { column, by } with by one of day, week, month, quarter, year for a date column. Named <column>_<by> in the answer. |
aggregates | no | Up to 10, each { fn, column, as } with fn one of count, count_distinct, sum, avg, min, max. |
order_by | no | Up to 5, each { column, dir } with dir asc (default) or desc. |
limit | no | Rows or groups to return: default 100, at most 1,000. |
data_version | no | An earlier data version to answer from. |
include | no | Up to 3 datasets this one points at through a declared relationship, each { parent, columns, via, as }. Their columns are named <parent>.<column> (or <as>.<column>) everywhere in the question. |
Answers with the row envelope for rows, or the data envelope for groups and totals, plus rows_matching, groups, rows_returned, fields, rows, include (for a question across datasets), built_from (for a dataset built from others) and a message.
dataset_check_key
Checks whether some columns would identify each row of the data loaded now, without changing anything.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
columns | yes | The columns that might identify each row, in order (1 to 8). |
Answers with total_rows, blanks per column, repeated_values and rows_with_repeated_values, up to 5 examples, holds and a one-sentence verdict.
dataset_check_join
Checks whether some columns of a dataset point at rows of another (or of itself), without changing anything. The columns are matched, in order, against what identifies each row of the other dataset.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset whose rows point at the other. |
columns | yes | Its columns that hold the other dataset’s identifiers (1 to 8). |
parent | yes | The dataset they point at. It must have something that identifies each row. |
Answers with the rows checked, rows with a blank (not checked), rows that match, rows that point at a row that isn’t there, match (such as "3 of 5 rows"), up to 5 examples and a one-sentence verdict.
History
dataset_row_history
One row as it stood in each of the latest 20 data versions, oldest first. See Lineage and history.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. It must have something that identifies each row. |
key | yes | The row’s value in each column that identifies it, named after the column: { "order_id": "A-1006" }. |
Answers with the row envelope (its row_ids is the row followed), has_row, versions_shown, more_versions and versions, each with data_version, schema_version, as_of, source, loaded_by, loaded_at, load_mode, has_row, row, change (unchanged, changed, added, removed or not_there), changed_columns and changes (each { column, from, to }), and a summary.
lineage
Where a dataset’s data, a metric’s number or a saved view’s answers come from. See Lineage and history.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
dataset | one of dataset, metric or view | The dataset to trace. |
metric | one of dataset, metric or view | The metric to trace. |
view | one of dataset, metric or view | The saved view to trace. It takes none of the inputs below. |
data_version | no | With dataset: an earlier data version to trace. |
metric_version | no | With metric: an earlier or retired version to trace. |
history | no | How many earlier loads to list (0 to 50). Default 5 for a dataset, 0 for each dataset a metric reads. |
A name given as the wrong kind (a view’s name as metric, say) is answered with what the name actually is; a misspelled one gets a suggestion.
Answers, for a dataset, with data_version, latest_data_version, schema_version, as_of, freshness, source (inline, upload, push_api or derived), source_ref, loaded_by (a member, a push key by name, or unknown; worked_out_from: "reference" when it was worked out rather than recorded), loaded_at, load_mode, parent_data_version, total_rows, built_from for a dataset built from others, history, more_history, relationships and a summary. For a metric: metric_version, latest_metric_version, status, retired (when it is), sentence, reads (each dataset’s columns, the structure version then and now, and structure_changed), datasets (each traced as above) and a summary. For a saved view: view, description, status, metrics (each with its version in use, saved_with_metric_version, what it reads and whether it’s behind), datasets (every dataset behind them, once each, with its data version, what it points_at and what it’s built_from) and a summary.
Datasets built from others
dataset_derive
Proposes a dataset built from a saved question over other datasets, instead of loaded. Approving it with dataset_approve_schema_change builds it. It’s rebuilt when one of its sources has new data, the next time it’s asked. It holds up to 250,000 rows and is built from up to 4 datasets.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
name | yes | The new dataset’s name. |
description | no | What it is, in a sentence. |
question | yes | dataset_query’s shape without limit or data_version: dataset, include, where, group_by, aggregates, and for rows rather than totals columns and order_by. |
expected_cadence | no | Default: the most frequent of its sources’. |
note | no | Why it’s being set up. |
dry_run | no | true only checks it and says what it would be, setting nothing up. |
Answers with status, derived, sources, question_in_words, key (its groups, when none can be blank) and proposal; when nothing would identify each row, a note with the exact not_blank filters to add. A dry run answers with status: "not_set_up" and the columns it would have.
dataset_rebuild
Builds a dataset built from others again now, from its sources’ current data. When none of them changed, nothing happens and the answer says so.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | A dataset built from others. |
Answers with rebuilt, has_data, data_version, previous_data_version, total_rows, as_of, built_from and a message.
Deleting
dataset_mark_for_deletion
Hides a dataset and deletes it for good after a number of days, unless it’s restored. Refused while another dataset points at it, a dataset is built from it, or approved metrics read it; the refusal names all of them.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The dataset’s name. |
keep_for_days | no | Days before it’s deleted for good: 1 to 30, default 7. |
retire_metrics | no | Only after a refusal because approved metrics read it: exactly those metrics, to retire them as it’s marked. |
Answers with marked_for_deletion, marked_for_deletion_at, marked_for_deletion_by, deleted_after and retired_metrics when there were any.
dataset_restore
Brings back a dataset marked for deletion exactly as it was: structure, data and versions.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The marked dataset’s name. |
Answers with status, has_data and data_version.
dataset_delete_permanently
Deletes a dataset that’s already marked for deletion, right now. This can’t be undone.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
dataset | yes | The marked dataset’s name. |
confirm | yes | The dataset’s name again, exactly. |
Answers with deleted: true.
Metrics
metric_propose
Proposes a metric, or a new version of an existing one. It’s checked against the dataset’s structure and the data loaded now. See Metrics and saved views.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
name | yes | The short name, unique among the organization’s datasets, metrics and views. An existing metric’s name proposes its next version. |
label | yes | The human name, up to 80 characters. |
description | yes | What it means in the person’s words, up to 500 characters. |
dataset | yes | The dataset it’s counted from. |
measure | yes | { fn, column } with fn one of count (no column counts rows), count_distinct, sum, avg, min, max; or { fn: "ratio", numerator, denominator }, each side a measure with its own optional filters. |
filters | no | Up to 20, always applied, in dataset_query’s where shape. |
time | no | { column, grains, default }: a date column, the periods it can be asked by (day, week, month, quarter, year) and the default. |
dimensions | no | Up to 20 things it can be split or filtered by: a column name, or { column, bands: { edges, labels, blank_label } } to split a number column into ranges. |
include | no | Up to 3 datasets it points at, { parent, via, as }, whose columns it may name. |
note | no | Why it’s being set up or changed. |
Answers with metric_version, status, sentence (the read-back to show the person word for word), reads, how_to_ask, filter_checks (how many rows each filter matches now), warnings and definition.
metric_approve
Makes a waiting metric version the one in force, after the person says yes to its sentence in the conversation. It’s checked again first. Approving a new version of a retired metric brings it back.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
metric | yes | The metric’s name. |
metric_version | yes | The version the person was shown. |
confirmed_by_person | yes | Must be true. |
Answers with decision, decided_by, decided_at, metric_version_in_force, sentence and reads.
metric_reject
Discards a waiting metric version because the person said no. The version in force, if any, stays.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
metric | yes | The metric’s name. |
metric_version | yes | The version to reject. |
reason | no | Why, in the person’s words. It’s kept with the version. |
Answers with decision and metric_version_in_force.
metric_list
The organization’s metrics.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
include_retired | no | true also lists retired metrics, with why they were retired. |
Answers with each metric’s name, label, dataset, status (waiting_for_approval, needs_new_proposal, ready, change_waiting_for_approval or retired), metric_version, waiting_metric_version and sentence.
metric_get
One metric: its sentence, definition, what it reads, how to ask it, and its versions.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
metric | yes | The metric’s name. |
metric_version | no | An earlier version to show. Default: the one in force. |
Answers with sentence, definition, reads, how_to_ask (the periods, the default, what it can be split and filtered by, and every band label), retired when it is, last_rejected while the newest version is a rejected one, and history.
metric_query
Asks a metric for its number. See Asking questions.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
metric | yes | The metric’s name. |
metric_version | no | An earlier approved version. Default: the one in force. |
grain | no | day, week, month, quarter or year (one of the metric’s), or total for one number. Default: the metric’s default. |
by | no | Up to 4 of the metric’s dimensions to split by. |
where | no | Extra filters, on its dimensions or its date column only. |
period | no | { from, to }, both included. A date-only to includes that whole day. |
data_version | no | An earlier data version of the metric’s dataset. |
limit | no | Rows to return: default 100, at most 1,000. |
Answers with the metric envelope, plus label, sentence, grain, period, group_by, rows_matching, groups, rows_returned, truncated, fields, rows and a message.
Saved views
view_save
Saves a view over approved metrics, or replaces the view with that name. It’s checked against the metrics in force. See Metrics and saved views.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
name | yes | The view’s short name, unique among the organization’s datasets, metrics and views. |
description | yes | What it answers, in the person’s words (up to 500 characters). |
metrics | yes | 1 to 10 approved metrics, each at most once, each { metric, by, where } as in metric_query. |
time | no | { grain, period }: the period every metric is counted by (day, week, month, quarter, year or total) and an optional fixed range. |
parameters | no | Up to 5 values filled in when it’s asked: { name, kind: "period" } for one period at the view’s grain, or { name, kind: "equals", binds_to: { column, metrics } } for a value a column must equal. |
Answers with saved (created or replaced), sentence, metrics (each with its metric_version and sentence), parameters (each with what it means), how_to_ask and a message.
view_list
The organization’s saved views.
Who can call it: any member.
This tool takes no inputs.
Answers with each view’s name, description, status (ready, some_metrics_retired or no_metric_can_be_asked), its metrics with the version in force, its parameter names, and who saved it and when.
view_get
One saved view: what it asks, its metrics now, and how to ask it.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
view | yes | The view’s name. |
Answers with sentence, status, metrics (each with status, metric_version, saved_with_metric_version, by and where), time, parameters and how_to_ask (the exact view_query call, with an example value for each parameter).
view_query
Answers a saved view by name. Every metric is answered exactly as metric_query answers it, at the version in force now.
Who can call it: any member.
| Input | Required | What it is |
|---|---|---|
view | yes | The view’s name. |
parameters | if the view has any | A value for each parameter, by name: { "month": "2026-09" }. A period is written as its grain: 2026-03-15, any day of a week, 2026-03, 2026-Q1 or 2026. |
limit | no | Rows per metric: default 100, at most 1,000. |
Answers with the view envelope: view, parameters, period, metrics, answers, not_answered, read_from, plus description, sentence and a message.
view_delete
Deletes a saved view. Its metrics and their data aren’t touched, and the name becomes free.
Who can call it: owners and admins.
| Input | Required | What it is |
|---|---|---|
view | yes | The view’s name. |
Answers with deleted: true and a message.
Connection check
ping
Checks that the connection works.
Who can call it: anyone connected.
| Input | Required | What it is |
|---|---|---|
message | no | Text to echo back. |
Answers with ok, a timestamp and echo (the message, when one was sent).