API v2 Documentation (Beta)

Welcome to the Aito API v2 reference. v2 runs the new rep2 engine: the same from/where you'd use to filter data is also the evidence for predict, recommend, and relate — across linked tables, and explainable by construction ($why returns the factor tree behind every probability). Tables are schema-flexible: import JSON and the schema is inferred and evolves with your data.

New to Aito v2? Start with the Quickstart — an explained prediction in five minutes, no signup — then skim Core Concepts for the mental model and browse the Use Cases for end-to-end patterns. Prefer to poke around first? The Sandbox and Playground are live and read-only. Hitting an error? See Common Errors.

Note: v2 is in public beta — the API surface is stable enough to build on, unsupported operations fail loud with typed errors (never silently wrong results), and remaining gaps are listed openly in the operator reference. The current production default is the v1 API; v2 is its successor.

Guides:

  • Quickstart — zero to an explained prediction in five minutes, against the live sandbox.
  • Core Concepts — the mental model: evidence vs population, values vs features, links, calibration, $why.
  • Which Query Type? — pick between _query / _predict / _recommend / _estimate / _search / _relate.
  • CollectionDb — the v2 engine: collection vs table, JSON import, schema inference & evolution.
  • Schema Design — types (incl. Date, arrays), the quantity flag, links, nullable modelling.
  • Query Operator Reference — the full where / orderBy / select grammar (incl. $search FTS, $group, Date ops).
  • Inference — predict, recommend, relate, $context ranking, $why.
  • Use Cases — GL coding, support triage, auto-tagging, market basket, full-text search, behavioral analytics — with runnable, verified queries.
  • Environments & Auth — one database-level key, path-selected envs, branch/promote lifecycle.
  • Clusters & Scaling — the object-store-backed multi-node model; read/write scaling, latency & staleness; set up with Aito support.
  • Schema Migration & Maintenance — add/alter columns, declarative plan & apply, bulk backfill, _modify, optimize.
  • v2 vs v1 — by the numbers — memory, disk, speed, accuracy, warm-up.
  • Benchmarks — accuracy vs tuned ML baselines (Random Forest / LightGBM / FLAML / LLM+RAG) and honest write/query performance vs specialized engines.
  • Sandbox — a live, read-only v2 env you can query right now (no signup).
  • Playground — run v2 queries against that env in the browser, no setup.
  • Common Errors — auth & env addressing, 501, empty search, flat predict, and frequent query errors.

Base URL:

https://your-instance.aito.ai/api/v2/

What's New in v2

The v2 API introduces several improvements:

  • Query2 Engine: A new high-performance query engine with optimized execution
  • Simplified Syntax: Cleaner JSON query format with intuitive field-value conditions
  • Flexible CollectionDb: a schema-flexible columnar store — POST raw JSON and the schema is inferred, then evolves incrementally as new fields (or even new column types) appear
  • Deeper links: cross-table relationships now traverse multi-hop dotted paths (e.g. processor.company.name), not just the single hop v1 allowed
  • Explainable predictions: $why returns the factor tree behind every probability
  • Schema as code: declarative _plan / _apply (like terraform plan/apply), plus in-place column add and type/analyzer alter (re-indexed), beyond v1's add-only
  • Richer types: Int / Long / Decimal / String / Boolean / Text / Json + arrays + honest nullable columns (a real defined-mask, not sentinels), plus a numeric quantity flag that bins prices/ages so neighbours share evidence
  • More powerful text: per-language analyzers, phrase / positional matching, and $has membership into array / multi-value columns
  • Lean memory footprint: columnar storage with memory-mapped, zero-allocation reads — the linkage format is ~2.6× smaller and state rebuilds use ~6× less memory — keeping RAM low as data grows
  • Scales to millions of rows: predict latency stays low and roughly flat into the 10M-row range (see the internal InvoicePerf benchmarks)
  • Horizontal scaling: run Aito as a multi-node cluster for read scale-out, higher write throughput, high availability, and object-store-backed durability (see the Clusters & Scaling guide)
  • Unified Interface: Consistent API across different table types

Key Differences from v1:

Featurev1v2
Query endpoint/api/v1/_search/api/v2/_query
Filter syntaxOperator-basedField-value based
Table creationSchema-focusedType-aware
Batch insertSeparate endpointUnified /batch suffix

v2 Query Example:

{
  "from": "products",
  "where": { "tags": { "$has": "fresh" } },
  "orderBy": "price",
  "limit": 10
}

Behavioral differences from v1

Some v1-vs-v2 output differences are by design — improvements the rep2 engine was built for, not regressions. When comparing results across versions, check here before filing a bug:

  • Predict on text fields aggregates duplicate values. v1 returns duplicate text values as separate hits ("hello", "hello", … each with its own probability); v2 returns one "hello" candidate with the aggregated probability. Candidates are values, not rows — the v2 behavior is the correct one.
  • The prediction target determines exclusiveness. predict X scores distinct whole values exclusively; predict X.$feature scores each member value independently (multi-label). The v1-style exclusiveness flag is deprecated: if given, it must agree with the target or the request is rejected.
  • Unsupported operations fail loud. Where v1 sometimes degraded silently (empty results, substituted defaults), v2 returns a typed 4xx/501 with the reason. A 200 with an empty result always means "no match", never "unsupported and swallowed".

Non-exclusive per-member predict (v2):

{
  "from": "products",
  "where": { "category": "dairy" },
  "predict": "tags.$feature",
  "limit": 10
}

Query operator reference

The complete where operator vocabulary ($match, $search, $has, ranges, $and/$or, $nearest, $refs, …), plus orderBy, select, let, the top-level query types and config, lives in one place — the Query Operator Reference (v2).

Full-text search + explainable predict:

{
  "from": "products",
  "where": {
    "description": { "$search": "(wireless OR bluetooth) mouse -refurbished" }
  },
  "predict": "category",
  "select": ["$value", "$p", "$why"]
}

Authentication

The v2 API uses the same key-based authentication as v1 — include your API key in the x-api-key header. Keys are database-level: one read key reads every environment, one read-write key writes every environment; there is no env-scoped key. Environments are selected purely by URL path (not a header or body field), so a 401/403 that reads fine on master is almost always an addressing mistake. See Environments & Auth for the full model and Common Errors when a call is rejected.

curl -X POST \
  'https://your-instance.aito.ai/api/v2/_query' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"from": "products", "limit": 5}'

Environments

Environments are shared across API versions — the same branch/promote mechanism serves v1 and v2. Branch the database into named copies for sandboxes, per-user demos, or atomic side-prepared releases. Switch envs purely via URL — /env/{name}/api/v2/... resolves to the named env, /api/v2/... resolves to master.

Manage them under /api/v2/_envs: GET to list, POST to branch ({ "name": "sandbox", "basedOn": "master" }), POST /api/v2/_envs/{name}/promote to swap into master, DELETE /api/v2/_envs/{name} to drop.

See Environments & Auth for the full URL pattern, promote semantics, naming rules, and the authorization model.

v2 env-scoped query:

curl -X POST \
  'https://your-instance.aito.ai/env/sandbox/api/v2/_query' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"from": "products", "limit": 5}'

Query (v2)

POST/api/v2/_query

Query rows using the v2 Query2 engine.

The v2 Query API provides a simplified, high-performance query interface powered by the new Query2 engine. It supports filtering, sorting, and column selection.

The same from/where body also drives prediction, recommendation and relation analysis (predict / recommend / relate), and the full where operator vocabulary ($match, $search, $has, ranges, $and/$or, $nearest, $refs, …) plus orderBy, select and let are documented in the Query Operator Reference (v2). The /api/v2/_predict, /_search, /_recommend and /_relate endpoints are aliases that accept the same body.

Query Format

The query is specified as a JSON object with the following fields:

FieldTypeDescription
fromstringRequired. The table name to query.
whereobjectOptional. Filter conditions as field-value pairs. Supports dotted paths for linked fields (e.g., {"processor.role": "Manager"}).
orderBystringOptional. Column name to sort by. Supports linked field paths.
selectarrayOptional. List of column names to return. Supports linked field paths.
limitnumberOptional. Maximum number of rows to return (default: 10).
offsetnumberOptional. Number of rows to skip (default: 0).

Response Format

The response includes:

FieldTypeDescription
offsetnumberThe offset used in the query.
totalnumberTotal number of matching rows.
hitsarrayArray of matching documents.

Examples

Basic query

Retrieve rows from a table with a limit.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "googleImpressions": 100,
      "name": "Pirkka banana",
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ],
      "price": 0.166,
      "id": "2000818700008",
      "cost": 0.1,
      "category": "100",
      "googleClicks": 12
    },
    {
      "googleImpressions": 100,
      "name": "Cucumber Finland",
      "tags": [
        "fresh",
        "vegetable"
      ],
      "price": 0.9765,
      "id": "2000604700007",
      "cost": 0.586,
      "category": "100",
      "googleClicks": 11
    },
    {
      "googleImpressions": 100,
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "tomato"
      ],
      "price": 1.29,
      "id": "6410405060457",
      "cost": 0.774,
      "category": "100",
      "googleClicks": 10
    }
  ]
}

Query with filter

Filter rows using the where clause. Here we keep only products tagged fresh$has matches membership in an array column.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "fresh"
    }
  },
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "fresh" }
    },
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 5,
  "hits": [
    {
      "googleImpressions": 100,
      "name": "Pirkka banana",
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ],
      "price": 0.166,
      "id": "2000818700008",
      "cost": 0.1,
      "category": "100",
      "googleClicks": 12
    },
    {
      "googleImpressions": 100,
      "name": "Cucumber Finland",
      "tags": [
        "fresh",
        "vegetable"
      ],
      "price": 0.9765,
      "id": "2000604700007",
      "cost": 0.586,
      "category": "100",
      "googleClicks": 11
    },
    {
      "googleImpressions": 100,
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "tomato"
      ],
      "price": 1.29,
      "id": "6410405060457",
      "cost": 0.774,
      "category": "100",
      "googleClicks": 10
    },
    {
      "googleImpressions": 100,
      "name": "Chiquita banana",
      "tags": [
        "fresh",
        "fruit"
      ],
      "price": 0.28054,
      "id": "2000503600002",
      "cost": 0.168,
      "category": "100",
      "googleClicks": 9
    },
    {
      "googleImpressions": 100,
      "name": "Pirkka iceberg salad Finland 100g 1st class",
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "salad"
      ],
      "price": 1.29,
      "id": "6410405093677",
      "cost": 0.774,
      "category": "100",
      "googleClicks": 9
    }
  ]
}

Query with sorting

Sort results using the orderBy clause.

Request body

{
  "from": "products",
  "orderBy": "name",
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "orderBy": "name",
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "googleImpressions": 100,
      "name": "Atria Gotler ham sausage 300g",
      "$p": "Atria Gotler ham sausage 300g",
      "tags": [
        "meat",
        "sausage",
        "with-bread"
      ],
      "price": 1.75,
      "id": "6407870071224",
      "cost": 1.225,
      "category": "102",
      "googleClicks": 8
    },
    {
      "googleImpressions": 100,
      "name": "Atria lauantaimakkara bread sausage 225g",
      "$p": "Atria lauantaimakkara bread sausage 225g",
      "tags": [
        "meat",
        "sausage",
        "with-bread"
      ],
      "price": 0.89,
      "id": "6407870070333",
      "cost": 0.623,
      "category": "102",
      "googleClicks": 9
    },
    {
      "googleImpressions": 100,
      "name": "Breadded chicke nuggets 200g",
      "$p": "Breadded chicke nuggets 200g",
      "tags": [
        "meat",
        "food",
        "protein"
      ],
      "price": 1.49,
      "id": "6409100024628",
      "cost": 1.043,
      "category": "103",
      "googleClicks": 8
    },
    {
      "googleImpressions": 100,
      "name": "Chiquita banana",
      "$p": "Chiquita banana",
      "tags": [
        "fresh",
        "fruit"
      ],
      "price": 0.28054,
      "id": "2000503600002",
      "cost": 0.168,
      "category": "100",
      "googleClicks": 9
    },
    {
      "googleImpressions": 100,
      "name": "Coca-Cola 1,5l soft drink",
      "$p": "Coca-Cola 1,5l soft drink",
      "tags": [
        "drink",
        "soda"
      ],
      "price": 2.49,
      "id": "6415600501811",
      "cost": 1.743,
      "category": "108",
      "googleClicks": 8
    }
  ]
}

Query with select

Select specific columns to return.

Request body

{
  "from": "products",
  "select": [
    "name",
    "price"
  ],
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_query \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "select": ["name", "price"],
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "name": "Pirkka banana",
      "price": 0.166
    },
    {
      "name": "Cucumber Finland",
      "price": 0.9765
    },
    {
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "price": 1.29
    },
    {
      "name": "Chiquita banana",
      "price": 0.28054
    },
    {
      "name": "Pirkka iceberg salad Finland 100g 1st class",
      "price": 1.29
    }
  ]
}

Search (v2)

POST/api/v2/_search

Full-text and structured search over a v2 collection.

_search is an alias of _query — the v2 Query2 engine dispatches by the body fields, so a body with a $match where and no inference field behaves as a search. Use whichever name reads best for your call site.

Body

FieldTypeDescription
fromstringRequired. The collection to search.
whereobjectFilter conditions. $match does full-text matching on Text columns; exact values match String/Int/Decimal.
orderBystring / objectOptional sort — a column, or an operator such as $similarity.
selectarrayOptional list of columns to return.
limit / offsetnumberPaging (default limit 10).

See the Query Operator Reference (v2).

Predict (v2)

POST/api/v2/_predict

Predict the value of a field from the evidence in where.

The from/where you would use to filter is also the evidence for the prediction — you don't train a model per question, you ask the collection. Each candidate value comes back with a calibrated probability $p.

Body

FieldTypeDescription
fromstringRequired. The collection to predict from.
whereobjectThe evidence — field conditions, dotted link paths (processor.role), $match, $numeric, etc.
predictstringRequired. The field to predict.
selectarrayColumns/metadata to return per candidate — $p, $value, and $why.
configobjectInference tuning. config.ai defaults to group (group formation); see Inference (v2).
limitnumberMax candidates (default 10).

To make a prediction better — links, supporting fields, $numeric, scoping — see Improving Inference (v2).

Predict a product category

Given a product name, predict its category. Each candidate comes back with a calibrated $p.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "where": {
    "name": "rye bread"
  },
  "predict": "category"
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": { "name": "rye bread" },
    "predict": "category"
  }'

Response

{
  "offset": 0,
  "total": 11,
  "hits": [
    {
      "$p": 0.9729371230219164,
      "$value": "101"
    },
    {
      "$p": 0.0033219857319227723,
      "$value": "102"
    },
    {
      "$p": 0.0033219857319227723,
      "$value": "103"
    },
    {
      "$p": 0.003305953340962574,
      "$value": "100"
    },
    {
      "$p": 0.003305953340962574,
      "$value": "104"
    },
    {
      "$p": 0.003305953340962574,
      "$value": "108"
    },
    {
      "$p": 0.0027701548656267837,
      "$value": "109"
    },
    {
      "$p": 0.002227782360484964,
      "$value": "111"
    },
    {
      "$p": 0.002227782360484964,
      "$value": "115"
    },
    {
      "$p": 0.00163766295237681,
      "$value": "106"
    }
  ]
}

Explain the prediction ($why)

Ask Aito to return the factor tree behind each score. With group formation on by default, correlated features appear as a single $group factor.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "fresh"
    }
  },
  "predict": "category",
  "select": [
    "$p",
    "$value",
    "$why"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_predict \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "fresh" }
    },
    "predict": "category",
    "select": ["$p", "$value", "$why"]
  }'

Response

{
  "offset": 0,
  "total": 11,
  "hits": [
    {
      "$p": 0.9761207744130768,
      "$value": "100",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "100"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.059574630877425
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.9058785275709119
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 8.154928406423556
          }
        ]
      }
    },
    {
      "$p": 0.0028675737328865704,
      "$value": "101",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "101"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9923825725045433
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0028675737328865704,
      "$value": "102",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "102"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9923825725045433
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0028675737328865704,
      "$value": "103",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "103"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9923825725045433
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0028675737328865704,
      "$value": "104",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "104"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9923825725045433
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0028675737328865704,
      "$value": "108",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.11320754716981132,
            "proposition": {
              "category": {
                "$has": "108"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9923825725045433
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0024026894935425002,
      "$value": "109",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.09433962264150944,
            "proposition": {
              "category": {
                "$has": "109"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 0.9977998416652373
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    },
    {
      "$p": 0.0019321588950813253,
      "$value": "111",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.07547169811320754,
            "proposition": {
              "category": {
                "$has": "111"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.0029946882263068
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.023202174419000122
          }
        ]
      }
    },
    {
      "$p": 0.0019321588950813253,
      "$value": "115",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.07547169811320754,
            "proposition": {
              "category": {
                "$has": "115"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.0029946882263068
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 0.998676639829455
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.023202174419000122
          }
        ]
      }
    },
    {
      "$p": 0.001637174819392551,
      "$value": "106",
      "$why": {
        "type": "product",
        "factors": [
          {
            "type": "baseP",
            "value": 0.03773584905660377,
            "proposition": {
              "category": {
                "$has": "106"
              }
            }
          },
          {
            "type": "product",
            "factors": [
              {
                "type": "normalizer",
                "name": "exclusiveness",
                "value": 1.1015558096595366
              },
              {
                "type": "normalizer",
                "name": "trueFalseExclusiveness",
                "value": 1.0127697460141756
              },
              {
                "type": "calibration",
                "name": "support-tempering(auto)",
                "value": 1.6760810594421103
              }
            ]
          },
          {
            "type": "relatedPropositionLift",
            "proposition": {
              "tags": {
                "$has": "fresh"
              }
            },
            "value": 0.02320217441900012
          }
        ]
      }
    }
  ]
}

Recommend (v2)

POST/api/v2/_recommend

Recommend the values of a field that best advance a goal.

Recommend is a predict with an objective: instead of "what is most likely", it ranks candidates by how much they move a goal proposition — e.g. the products most likely to be purchased.

Body

FieldTypeDescription
fromstringRequired. The collection to recommend from.
recommendstringRequired. The field to recommend.
goalobjectRequired. The objective proposition to maximise — e.g. {"purchase": true}.
whereobjectOptional context/evidence.
configobjectInference tuning (config.ai, default group).
limitnumberMax recommendations (default 10).

Recommend products toward a goal

Recommend the products most likely to reach a goal — here, being purchased by a given user. The where sets the context (the user); goal is the outcome to optimise for.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "veronica"
  },
  "recommend": "product",
  "goal": {
    "purchase": true
  },
  "limit": 3
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_recommend \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "veronica" },
    "recommend": "product",
    "goal": { "purchase": true },
    "limit": 3
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.17469602156651695,
      "$value": "2000818700008"
    },
    {
      "$p": 0.1430041152201242,
      "$value": "6414880021620"
    },
    {
      "$p": 0.10520023908423279,
      "$value": "6413200330206"
    }
  ]
}

Relate (v2)

POST/api/v2/_relate

Find statistical relations between fields instead of returning rows.

Relate answers "how does one thing relate to another" — it reports the lift and conditional probabilities of the related fields against the where context, rather than ranking rows. A lift above 1.0 means the field is more likely than its base rate in that context.

Body

FieldTypeDescription
fromstringRequired. The collection to relate over.
relatearray | objectRequired. The v2 form is an array of field paths to relate to the where known set — e.g. ["purchase"] or ["product.tags", "product.category"]. An object condition (e.g. {"purchase": true}) is also accepted as the v1 form: relate all fields to that condition.
whereobjectThe context/known set the listed fields are related to.
configobjectInference tuning (config.ai).
limitnumberMax relations returned (default 10).

How a field relates to a context

Relate returns statistical relations (lift, probabilities) instead of rows. The v2 form takes an array of field names to relate to the where known set. Here we ask how purchase relates to products tagged vegetable — a lift above 1.0 means those products are more likely than average to be bought.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "impressions",
  "where": {
    "product.tags": {
      "$has": "vegetable"
    }
  },
  "relate": [
    "purchase"
  ],
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_relate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": {
      "product.tags": { "$has": "vegetable" }
    },
    "relate": ["purchase"],
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 2,
  "hits": [
    {
      "n": 90325,
      "info": 0.0005322901359249605,
      "condition": {
        "product.tags": {
          "$has": "vegetable"
        }
      },
      "related": {
        "purchase": true
      },
      "fs": {
        "fOnNotCondition": 4031,
        "n": 90325,
        "fOnCondition": 639,
        "f": 4670,
        "fCondition": 8632
      },
      "lift": 1.374662085019504
    },
    {
      "n": 90325,
      "info": 0.00053229013592495,
      "condition": {
        "product.tags": {
          "$has": "vegetable"
        }
      },
      "related": {
        "purchase": false
      },
      "fs": {
        "fOnNotCondition": 77662,
        "n": 90325,
        "fOnCondition": 7993,
        "f": 85655,
        "fCondition": 8632
      },
      "lift": 0.9794830840502661
    }
  ]
}

Match (v2)

POST/api/v2/_match

Match a context to the best-fitting values of a field.

Match ranks the candidate values of a field by how well they fit the given context — the frequency-and-fit ranking behind "which products suit this user".

Body

FieldTypeDescription
fromstringRequired. The collection to match over.
matchstringRequired. The field whose values are ranked.
whereobjectThe context — field conditions and dotted link paths (context.user).
limitnumberMax results (default 10).

Match a user to products

Rank the products that best match a context — here, a given user.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "impressions",
  "where": {
    "context.user": "larry"
  },
  "match": "product",
  "limit": 5
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_match \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "impressions",
    "where": { "context.user": "larry" },
    "match": "product",
    "limit": 5
  }'

Response

{
  "offset": 0,
  "total": 42,
  "hits": [
    {
      "$p": 0.03636645071658641,
      "category": "100",
      "cost": 0.586,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "2000604700007",
      "name": "Cucumber Finland",
      "price": 0.9765,
      "tags": [
        "fresh",
        "vegetable"
      ]
    },
    {
      "$p": 0.03303793576204806,
      "category": "100",
      "cost": 0.1,
      "googleClicks": 12,
      "googleImpressions": 100,
      "id": "2000818700008",
      "name": "Pirkka banana",
      "price": 0.166,
      "tags": [
        "fresh",
        "fruit",
        "pirkka"
      ]
    },
    {
      "$p": 0.03271082748717629,
      "category": "100",
      "cost": 0.774,
      "googleClicks": 10,
      "googleImpressions": 100,
      "id": "6410405060457",
      "name": "Pirkka bio cherry tomatoes 250g international 1lk",
      "price": 1.29,
      "tags": [
        "fresh",
        "vegetable",
        "pirkka",
        "tomato"
      ]
    },
    {
      "$p": 0.03142380061919346,
      "category": "101",
      "cost": 1.295,
      "googleClicks": 11,
      "googleImpressions": 100,
      "id": "6411402202208",
      "name": "Fazer Puikula fullcorn rye bread 9 pcs/500g",
      "price": 1.85,
      "tags": [
        "gluten",
        "bread"
      ]
    },
    {
      "$p": 0.029923824657771932,
      "category": "100",
      "cost": 0.168,
      "googleClicks": 9,
      "googleImpressions": 100,
      "id": "2000503600002",
      "name": "Chiquita banana",
      "price": 0.28054,
      "tags": [
        "fresh",
        "fruit"
      ]
    }
  ]
}

Evaluate (v2)

POST/api/v2/_evaluate

Measure how well a v2 query performs on your own data.

_evaluate splits the data into train and test sets, hides the test rows (a transient masked delete, so no test row leaks into its own prediction), runs the query per test row, and reports accuracy, ranking, and probability-quality metrics. On collection tables the test set is chosen with $index — including $index $mod [k, r] for deterministic, leak-free k-fold folds.

Body

FieldTypeDescription
evaluateobjectRequired. The query to measure (a _predict/_recommend/… body).
test / testSourceobjectWhich rows to test on. { "$index": { "$mod": [k, r] } } is a 1/k fold. Omitting both is a loud 400 — there is no implicit default test set.
selectarrayMetrics to return: accuracy, baseAccuracy, meanRank, geomMeanP, n, …

Full walkthrough — folds, metrics, config — in the Evaluation guide (v2).

Cross-validate a predict

Measure a category predict on a deterministic 25% fold ($index $mod). No test row trains its own prediction. See the Evaluation guide.

Request body

{
  "test": {
    "$index": {
      "$mod": [
        4,
        0
      ]
    }
  },
  "evaluate": {
    "from": "products",
    "predict": "category"
  }
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_evaluate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "test": {
      "$index": {
        "$mod": [4, 0]
      }
    },
    "evaluate": { "from": "products", "predict": "category" }
  }'

Response

{
  "message": "The evaluated query's 'where' has no {\"$get\": ...} binding, so each prediction is conditioned on nothing and 'accuracy' reflects unconditioned base rates (≈ 'baseAccuracy'), not per-row accuracy. Bind the tested row's evidence fields, e.g. \"where\": { \"someField\": { \"$get\": \"someField\" } }.",
  "n": 11,
  "testSamples": 11,
  "trainSamples": 31,
  "features": 235,
  "error": 0.9090909090909091,
  "baseError": 0.9090909090909091,
  "accuracy": 0.09090909090909091,
  "baseAccuracy": 0.09090909090909091,
  "accuracyGain": 0,
  "meanRank": 4.090909090909091,
  "baseMeanRank": 4.090909090909091,
  "rankGain": 0,
  "informationGain": 0,
  "mxe": 3.350714024506782,
  "h": 3.350714024506782,
  "geomMeanP": 0.09802448555185775,
  "baseGmp": 0.09802448555185775,
  "geomMeanLift": 1,
  "meanNs": 2442462.4545454546,
  "meanUs": 2442.4624545454544,
  "meanMs": 2.4424624545454545,
  "medianNs": 1988353,
  "medianUs": 1988.353,
  "medianMs": 1.988353,
  "allNs": [
    3543326,
    2754322,
    2158558,
    3351738,
    4226401,
    1790617,
    1765218,
    1988353,
    1791007,
    1817657,
    1679890
  ],
  "allUs": [
    3543,
    2754,
    2158,
    3351,
    4226,
    1790,
    1765,
    1988,
    1791,
    1817,
    1679
  ],
  "allMs": [
    3,
    2,
    2,
    3,
    4,
    1,
    1,
    1,
    1,
    1,
    1
  ],
  "warmingMs": 1,
  "accurateOffsets": [
    2
  ],
  "errorOffsets": [
    0,
    1,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    10
  ],
  "cases": [
    {
      "offset": 0,
      "testCase": {
        "category": "100",
        "cost": 0.1,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "2000818700008",
        "name": "Pirkka banana",
        "price": 0.166,
        "tags": [
          "fresh",
          "fruit",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 1,
      "testCase": {
        "category": "100",
        "cost": 0.774,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6410405093677",
        "name": "Pirkka iceberg salad Finland 100g 1st class",
        "price": 1.29,
        "tags": [
          "fresh",
          "vegetable",
          "pirkka",
          "salad"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 2,
      "testCase": {
        "category": "101",
        "cost": 0.903,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6413467282508",
        "name": "Fazer Puikula fullcorn rye bread 330g",
        "price": 1.29,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      }
    },
    {
      "offset": 3,
      "testCase": {
        "category": "102",
        "cost": 1.953,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410405205483",
        "name": "Pirkka Finnish beef-pork minced meat 20% 400g",
        "price": 2.79,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "102"
      }
    },
    {
      "offset": 4,
      "testCase": {
        "category": "103",
        "cost": 1.393,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6412000030026",
        "name": "Saarioinen Maksalaatikko liver casserole 400g",
        "price": 1.99,
        "tags": [
          "meat",
          "food"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "103"
      }
    },
    {
      "offset": 5,
      "testCase": {
        "category": "104",
        "cost": 0.567,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "6410405082657",
        "name": "Pirkka Finnish semi-skimmed milk 1l",
        "price": 0.81,
        "tags": [
          "lactose",
          "drink",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 6,
      "testCase": {
        "category": "104",
        "cost": 1.365,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6408430000258",
        "name": "Valio eila™ Lactose-free semi-skimmed milk drink 1l",
        "price": 1.95,
        "tags": [
          "lactose-free",
          "drink"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 7,
      "testCase": {
        "category": "108",
        "cost": 2.415,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6420101441542",
        "name": "Kulta Katriina filter coffee 500g",
        "price": 3.45,
        "tags": [
          "coffee"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "108"
      }
    },
    {
      "offset": 8,
      "testCase": {
        "category": "109",
        "cost": 1.533,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6411401015090",
        "name": "Fazer Sininen milk chocolate slab 200g",
        "price": 2.19,
        "tags": [
          "candy",
          "lactose"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "109"
      }
    },
    {
      "offset": 9,
      "testCase": {
        "category": "111",
        "cost": 2.345,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6413200330206",
        "name": "Lotus Soft Embo 8 rll toilet paper",
        "price": 3.35,
        "tags": [
          "toilet-paper"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.07142857142857142,
        "field": "category",
        "feature": "111"
      }
    },
    {
      "offset": 10,
      "testCase": {
        "category": "115",
        "cost": 1.183,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410402010318",
        "name": "Pirkka tuna fish pieces in oil 200g/150g",
        "price": 1.69,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.07142857142857142,
        "field": "category",
        "feature": "115"
      }
    }
  ],
  "accurateCases": [
    {
      "offset": 2,
      "testCase": {
        "category": "101",
        "cost": 0.903,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6413467282508",
        "name": "Fazer Puikula fullcorn rye bread 330g",
        "price": 1.29,
        "tags": [
          "gluten",
          "bread"
        ]
      },
      "accurate": true,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      }
    }
  ],
  "errorCases": [
    {
      "offset": 0,
      "testCase": {
        "category": "100",
        "cost": 0.1,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "2000818700008",
        "name": "Pirkka banana",
        "price": 0.166,
        "tags": [
          "fresh",
          "fruit",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 1,
      "testCase": {
        "category": "100",
        "cost": 0.774,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6410405093677",
        "name": "Pirkka iceberg salad Finland 100g 1st class",
        "price": 1.29,
        "tags": [
          "fresh",
          "vegetable",
          "pirkka",
          "salad"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "100"
      }
    },
    {
      "offset": 3,
      "testCase": {
        "category": "102",
        "cost": 1.953,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410405205483",
        "name": "Pirkka Finnish beef-pork minced meat 20% 400g",
        "price": 2.79,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "102"
      }
    },
    {
      "offset": 4,
      "testCase": {
        "category": "103",
        "cost": 1.393,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6412000030026",
        "name": "Saarioinen Maksalaatikko liver casserole 400g",
        "price": 1.99,
        "tags": [
          "meat",
          "food"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "103"
      }
    },
    {
      "offset": 5,
      "testCase": {
        "category": "104",
        "cost": 0.567,
        "googleClicks": 12,
        "googleImpressions": 100,
        "id": "6410405082657",
        "name": "Pirkka Finnish semi-skimmed milk 1l",
        "price": 0.81,
        "tags": [
          "lactose",
          "drink",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 6,
      "testCase": {
        "category": "104",
        "cost": 1.365,
        "googleClicks": 8,
        "googleImpressions": 100,
        "id": "6408430000258",
        "name": "Valio eila™ Lactose-free semi-skimmed milk drink 1l",
        "price": 1.95,
        "tags": [
          "lactose-free",
          "drink"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "104"
      }
    },
    {
      "offset": 7,
      "testCase": {
        "category": "108",
        "cost": 2.415,
        "googleClicks": 9,
        "googleImpressions": 100,
        "id": "6420101441542",
        "name": "Kulta Katriina filter coffee 500g",
        "price": 3.45,
        "tags": [
          "coffee"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "108"
      }
    },
    {
      "offset": 8,
      "testCase": {
        "category": "109",
        "cost": 1.533,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6411401015090",
        "name": "Fazer Sininen milk chocolate slab 200g",
        "price": 2.19,
        "tags": [
          "candy",
          "lactose"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.09523809523809523,
        "field": "category",
        "feature": "109"
      }
    },
    {
      "offset": 9,
      "testCase": {
        "category": "111",
        "cost": 2.345,
        "googleClicks": 11,
        "googleImpressions": 100,
        "id": "6413200330206",
        "name": "Lotus Soft Embo 8 rll toilet paper",
        "price": 3.35,
        "tags": [
          "toilet-paper"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.07142857142857142,
        "field": "category",
        "feature": "111"
      }
    },
    {
      "offset": 10,
      "testCase": {
        "category": "115",
        "cost": 1.183,
        "googleClicks": 10,
        "googleImpressions": 100,
        "id": "6410402010318",
        "name": "Pirkka tuna fish pieces in oil 200g/150g",
        "price": 1.69,
        "tags": [
          "meat",
          "food",
          "protein",
          "pirkka"
        ]
      },
      "accurate": false,
      "top": {
        "$p": 0.11904761904761904,
        "field": "category",
        "feature": "101"
      },
      "correct": {
        "$p": 0.07142857142857142,
        "field": "category",
        "feature": "115"
      }
    }
  ],
  "alpha_binByTopScore": [
    {
      "meanScore": 0.11904761904761904,
      "maxScore": 0.11904761904761904,
      "minScore": 0.11904761904761904,
      "accuracy": 0.25,
      "n": 4,
      "accurateOffsets": [
        2
      ],
      "errorOffsets": [
        0,
        1,
        3
      ]
    },
    {
      "meanScore": 0.11904761904761904,
      "maxScore": 0.11904761904761904,
      "minScore": 0.11904761904761904,
      "accuracy": 0,
      "n": 4,
      "accurateOffsets": [],
      "errorOffsets": [
        4,
        5,
        6,
        7
      ]
    },
    {
      "meanScore": 0.11904761904761903,
      "maxScore": 0.11904761904761904,
      "minScore": 0.11904761904761904,
      "accuracy": 0,
      "n": 3,
      "accurateOffsets": [],
      "errorOffsets": [
        8,
        9,
        10
      ]
    }
  ]
}

Estimate (v2)

POST/api/v2/_estimate

Estimate the value of a numeric field from evidence.

Estimate predicts a continuous quantity (e.g. a price) rather than a categorical value, returning the expected value and its distribution.

Body

FieldTypeDescription
fromstringRequired. The collection.
estimatestringRequired. The numeric (Int/Decimal) field to estimate.
whereobjectThe evidence.
selectarrayInclude estimate for the point estimate.

Estimate a numeric field

Estimate the price of products matching a condition.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "where": {
    "tags": {
      "$has": "bread"
    }
  },
  "estimate": "price",
  "select": [
    "estimate"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_estimate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "where": {
      "tags": { "$has": "bread" }
    },
    "estimate": "price",
    "select": ["estimate"]
  }'

Response

{
  "estimate": 1.350545069703815
}

Aggregate (v2)

POST/api/v2/_aggregate

Compute aggregate statistics over a collection.

Aggregate reduces columns to summary statistics using the field.$op syntax — $mean, $sum, $variance, and related moments — optionally scoped by a where.

Body

FieldTypeDescription
fromstringRequired. The collection.
aggregatearrayRequired. A list of "field.$op" terms, e.g. ["price.$mean", "price.$sum"].
whereobjectOptional filter to aggregate over a subset.

Aggregate statistics

Compute mean/sum aggregates over columns with the field.$op syntax.

You can copy-paste the example curl command to your terminal.

Request body

{
  "from": "products",
  "aggregate": [
    "price.$mean",
    "price.$sum",
    "googleClicks.$mean"
  ]
}

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_aggregate \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  {
    "from": "products",
    "aggregate": ["price.$mean", "price.$sum", "googleClicks.$mean"]
  }'

Response

{
  "googleClicks.$mean": 9.80952380952381,
  "googleClicks.$mean.samples": 42,
  "googleClicks.$mean.variance": 1.9637188208616578,
  "googleClicks.$mean.standardDeviation": 1.4013275209106748,
  "googleClicks.$mean.standardError": 0.21622953087059052,
  "price.$sum": 70.38304000000001,
  "price.$sum.samples": 42,
  "price.$mean": 1.6757866666666668,
  "price.$mean.samples": 42,
  "price.$mean.variance": 0.9422393083365073,
  "price.$mean.standardDeviation": 0.9706901196244387,
  "price.$mean.standardError": 0.14978073723315463
}

Batch (v2)

POST/api/v2/_batch

Run several v2 queries in a single request.

Post a JSON array of query bodies; each runs through the same Query2 machinery as _query and the results are returned in order. Batching amortises request overhead when a page needs several predictions at once.

Body

A JSON array of query objects — each the body you would post to _query/_predict/_recommend/etc.

[
  { "from": "products", "where": { "name": "rye bread" }, "predict": "category" },
  { "from": "products", "where": { "name": "rye bread" }, "predict": "tags" }
]

Run several queries in one request

Post an array of queries; each runs through the same Query2 machinery as _query and the results come back in order.

Request body

[
  {
    "from": "products",
    "where": {
      "name": "rye bread"
    },
    "predict": "category"
  },
  {
    "from": "products",
    "where": {
      "name": "rye bread"
    },
    "predict": "tags"
  }
]

Request

curl -X POST \
  https://shared.aito.ai/db/aito-demo/api/v2/_batch \
  -H 'content-type: application/json' \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi' \
  -d '
  [
    {
      "from": "products",
      "where": { "name": "rye bread" },
      "predict": "category"
    },
    {
      "from": "products",
      "where": { "name": "rye bread" },
      "predict": "tags"
    }
  ]'

Response

[
  {
    "offset": 0,
    "total": 11,
    "hits": [
      {
        "$p": 0.9729371230219164,
        "$value": "101"
      },
      {
        "$p": 0.0033219857319227723,
        "$value": "102"
      },
      {
        "$p": 0.0033219857319227723,
        "$value": "103"
      },
      {
        "$p": 0.003305953340962574,
        "$value": "100"
      },
      {
        "$p": 0.003305953340962574,
        "$value": "104"
      },
      {
        "$p": 0.003305953340962574,
        "$value": "108"
      },
      {
        "$p": 0.0027701548656267837,
        "$value": "109"
      },
      {
        "$p": 0.002227782360484964,
        "$value": "111"
      },
      {
        "$p": 0.002227782360484964,
        "$value": "115"
      },
      {
        "$p": 0.00163766295237681,
        "$value": "106"
      }
    ]
  },
  {
    "offset": 0,
    "total": 25,
    "hits": [
      {
        "$p": 0.4962860612870516,
        "$value": "gluten"
      },
      {
        "$p": 0.48674349016827606,
        "$value": "bread"
      },
      {
        "$p": 0.0022722516257175397,
        "$value": "food"
      },
      {
        "$p": 0.0018429336402213446,
        "$value": "sausage"
      },
      {
        "$p": 0.0018429336402213446,
        "$value": "with-bread"
      },
      {
        "$p": 0.0005506164819255847,
        "$value": "candy"
      },
      {
        "$p": 0.0005506164819255847,
        "$value": "carbohydrate"
      },
      {
        "$p": 0.0005506164819255847,
        "$value": "coffee"
      },
      {
        "$p": 0.0005506164819255847,
        "$value": "drink"
      },
      {
        "$p": 0.0005506164819255847,
        "$value": "fresh"
      }
    ]
  }
]

Schema API

The Schema API v2 provides endpoints for managing table schemas. It supports both CollectionDb (document-oriented) and TableDb (row-based) table types.

Endpoints:

  • GET /api/v2/schema - List tables
  • GET /api/v2/schema/{table} - Get table schema
  • PUT /api/v2/schema/{table} - Create table
  • PUT /api/v2/schema/{table}/{column} - Add or alter a column
  • POST /api/v2/schema/{table}/_plan - Dry-run a schema change
  • POST /api/v2/schema/{table}/_apply - Apply a schema change
  • DELETE /api/v2/schema/{table} - Delete table
  • POST /api/v2/data/{table} - Insert document
  • POST /api/v2/data/{table}/batch - Batch insert

Schema migration & maintenance

Beyond creating and dropping tables, v2 collections can evolve their schema and data in place — no full reload:

  • Add or alter a columnPUT /api/v2/schema/{table}/{column} adds a column (backfilling existing rows from an optional value), or, if the column already exists, alters its type/analyzer and re-indexes the data. Type-compatible changes only: widening int → long → decimal, and string ↔ text with an analyzer.
  • Plan & apply, declarativelyPOST …/{table}/_plan dry-runs a target schema and returns a terraform plan-style diff (per column: add / rebuild / drop / rejected / no-op) without touching anything. POST …/{table}/_apply converges the table to that target atomically, refusing lossy changes and requiring ?confirm=true for column drops.
  • Modify rowsPOST /api/v2/data/_modify applies insert / update (with upsert) / delete operations, matched by a where clause, in one commit.
  • Bulk backfill a columnPOST /api/v2/data/{table}/_backfill sets column values on many existing rows at once, matched by a business key, using a compact columnar body — the fast way to populate a newly-added column.

These work on both CollectionDb (v2) and, where noted, legacy TableDb tables. See the Schema Migration & Maintenance guide for the full walkthrough with request/response examples.

Add a column with a default:

curl -X PUT \
  'https://your-instance.aito.ai/api/v2/schema/users/tier' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"type": "String", "value": "free"}'

Bulk-backfill it by key:

curl -X POST \
  'https://your-instance.aito.ai/api/v2/data/users/_backfill' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"key": "id", "keys": [1, 2, 3],
       "columns": {"tier": ["gold", "silver", "bronze"]}}'

List Tables (v2)

GET/api/v2/schema

List all tables in the database.

Returns schema information for all tables, including column definitions and types.

Response Format

The response is an object where each key is a table name and the value contains the table schema:

{
  "tableName": {
    "type": "collection" | "table",
    "columns": {
      "columnName": { "type": "String" | "Int" | "Decimal" | "Boolean" | "Text" | "Json" }
    }
  }
}

Table Types

TypeDescription
collectionCollectionDb table - optimized for document storage
tableTableDb table - traditional row-based storage

List all tables

Returns a list of all tables in the database with their schema information.

You can copy-paste the example curl command to your terminal.

Request

curl -X GET \
  https://shared.aito.ai/db/aito-demo/api/v2/schema \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi'

Response

{
  "schema": {
    "prompts": {
      "type": "table",
      "columns": {
        "assignee": {
          "type": "String",
          "nullable": true,
          "link": "employees.Name"
        },
        "tags": {
          "type": "String[]",
          "nullable": true
        },
        "sentiment": {
          "type": "String",
          "nullable": true
        },
        "prompt": {
          "type": "Text",
          "analyzer": "english"
        },
        "urgency": {
          "type": "String",
          "nullable": true
        },
        "categories": {
          "type": "String[]",
          "nullable": true
        },
        "answer": {
          "type": "Int",
          "nullable": true,
          "link": "answers.id"
        },
        "type": {
          "type": "String"
        }
      }
    },
    "visits": {
      "type": "table",
      "columns": {
        "purchases": {
          "type": "String[]"
        },
        "prev": {
          "type": "String",
          "nullable": true,
          "link": "this.id"
        },
        "week": {
          "type": "Int"
        },
        "id": {
          "type": "String"
        },
        "weekday": {
          "type": "String"
        },
        "day": {
          "type": "Int"
        },
        "user": {
          "type": "String",
          "link": "users.id"
        },
        "month": {
          "type": "Int"
        }
      }
    },
    "glCodes": {
      "type": "table",
      "columns": {
        "Department": {
          "type": "String"
        },
        "GLCode": {
          "type": "String"
        },
        "Name": {
          "type": "String"
        }
      }
    },
    "impressions": {
      "type": "table",
      "columns": {
        "context": {
          "type": "String",
          "link": "contexts.id"
        },
        "product": {
          "type": "String",
          "link": "products.id"
        },
        "purchase": {
          "type": "Boolean"
        }
      }
    },
    "products": {
      "type": "table",
      "columns": {
        "googleImpressions": {
          "type": "Int"
        },
        "name": {
          "type": "Text",
          "analyzer": "english"
        },
        "tags": {
          "type": "String[]"
        },
        "price": {
          "type": "Decimal"
        },
        "id": {
          "type": "String"
        },
        "cost": {
          "type": "Decimal"
        },
        "category": {
          "type": "String"
        },
        "googleClicks": {
          "type": "Int"
        }
      }
    },
    "price_history": {
      "type": "table",
      "columns": {
        "similar_products_on_sale": {
          "type": "Int"
        },
        "competitor_avg_price": {
          "type": "Decimal"
        },
        "weather_temp": {
          "type": "Decimal"
        },
        "name": {
          "type": "Text",
          "analyzer": "english"
        },
        "list_price": {
          "type": "Decimal"
        },
        "promotional_placement": {
          "type": "String"
        },
        "days_since_delivery": {
          "type": "Int"
        },
        "timestamp": {
          "type": "String"
        },
        "day_of_week": {
          "type": "String"
        },
        "tags": {
          "type": "String[]"
        },
        "category_name": {
          "type": "String"
        },
        "is_holiday_week": {
          "type": "Boolean"
        },
        "year": {
          "type": "Int"
        },
        "units_sold": {
          "type": "Int"
        },
        "brand": {
          "type": "String"
        },
        "days_until_expiry": {
          "type": "Int"
        },
        "category_products_count": {
          "type": "Int"
        },
        "week": {
          "type": "Int"
        },
        "date": {
          "type": "String"
        },
        "discount_percentage": {
          "type": "Decimal"
        },
        "sale_price": {
          "type": "Decimal"
        },
        "margin_percentage": {
          "type": "Decimal"
        },
        "units_in_stock": {
          "type": "Int"
        },
        "product_id": {
          "type": "String",
          "link": "products.id"
        },
        "category": {
          "type": "String"
        },
        "purchase_cost": {
          "type": "Decimal"
        },
        "is_weekend": {
          "type": "Boolean"
        },
        "month": {
          "type": "Int"
        }
      }
    },
    "invoices": {
      "type": "table",
      "columns": {
        "ReceiverAddress": {
          "type": "Text",
          "analyzer": "english"
        },
        "InvoiceType": {
          "type": "String",
          "nullable": true
        },
        "AccountNumber": {
          "type": "String"
        },
        "TotalAmount": {
          "type": "Decimal"
        },
        "Processor": {
          "type": "String",
          "nullable": true,
          "link": "employees.Name"
        },
        "VATAmount": {
          "type": "Decimal"
        },
        "Acceptor": {
          "type": "String",
          "nullable": true,
          "link": "employees.Name"
        },
        "Description": {
          "type": "Text",
          "analyzer": "english"
        },
        "PaymentDueDate": {
          "type": "String"
        },
        "GLCode": {
          "type": "String",
          "nullable": true,
          "link": "glCodes.GLCode"
        },
        "InvoiceID": {
          "type": "String"
        },
        "InvoiceDate": {
          "type": "String"
        },
        "SenderAddress": {
          "type": "Text",
          "analyzer": "english"
        },
        "SenderName": {
          "type": "Text",
          "analyzer": "english"
        },
        "InvoiceNumber": {
          "type": "String"
        },
        "ProductName": {
          "type": "Text",
          "analyzer": "english"
        },
        "ReceiverName": {
          "type": "Text",
          "analyzer": "english"
        },
        "PaymentMethod": {
          "type": "String"
        }
      }
    },
    "contexts": {
      "type": "table",
      "columns": {
        "query": {
          "type": "Text",
          "analyzer": "english"
        },
        "week": {
          "type": "Int"
        },
        "id": {
          "type": "String"
        },
        "prevBasket": {
          "type": "String[]"
        },
        "visit": {
          "type": "String",
          "link": "visits.id"
        },
        "weekday": {
          "type": "String"
        },
        "type": {
          "type": "String"
        },
        "queryPhrase": {
          "type": "String"
        },
        "day": {
          "type": "Int"
        },
        "basket": {
          "type": "String[]"
        },
        "user": {
          "type": "String",
          "link": "users.id"
        },
        "month": {
          "type": "Int"
        }
      }
    },
    "users": {
      "type": "table",
      "columns": {
        "id": {
          "type": "String"
        },
        "tags": {
          "type": "String[]"
        }
      }
    },
    "answers": {
      "type": "table",
      "columns": {
        "answer": {
          "type": "Text",
          "analyzer": "english"
        },
        "id": {
          "type": "Int"
        }
      }
    },
    "employees": {
      "type": "table",
      "columns": {
        "Department": {
          "type": "String"
        },
        "Name": {
          "type": "String"
        },
        "Role": {
          "type": "String"
        },
        "Superior": {
          "type": "String",
          "nullable": true
        }
      }
    }
  }
}

Get Table Schema (v2)

GET/api/v2/schema/{table}

Get the schema for a specific table.

Returns detailed schema information including column names, types, and table type.

Path Parameters

ParameterTypeDescription
tablestringThe name of the table.

Response Format

{
  "type": "collection" | "table",
  "columns": {
    "columnName": { "type": "String" | "Int" | "Decimal" | "Boolean" | "Text" | "Json" }
  }
}

Get schema for a specific table

Returns the schema definition for the specified table.

You can copy-paste the example curl command to your terminal.

Request

curl -X GET \
  https://shared.aito.ai/db/aito-demo/api/v2/schema/products \
  -H 'x-api-key: yg4rTlXkqDzm4y8gPeY75HCKaNwfbTQ2si64ONTi'

Response

{
  "type": "table",
  "columns": {
    "googleImpressions": {
      "type": "Int"
    },
    "name": {
      "type": "Text",
      "analyzer": "english"
    },
    "tags": {
      "type": "String[]"
    },
    "price": {
      "type": "Decimal"
    },
    "id": {
      "type": "String"
    },
    "cost": {
      "type": "Decimal"
    },
    "category": {
      "type": "String"
    },
    "googleClicks": {
      "type": "Int"
    }
  }
}

Create Table (v2)

PUT/api/v2/schema/{table}

Create a new table with the specified schema.

Creates a table using either CollectionDb or TableDb storage, depending on the type field.

Path Parameters

ParameterTypeDescription
tablestringThe name of the table to create.

Request Body

{
  "type": "collection" | "table",
  "columns": {
    "columnName": { "type": "String" | "Int" | "Decimal" | "Boolean" | "Text" | "Json" },
    "linkColumn": { "type": "String", "link": "targetTable.keyColumn" }
  }
}

Table Types

TypeDescription
collectionCreates a CollectionDb table - optimized for document storage with flexible schema
tableCreates a TableDb table - traditional row-based storage

Column Types

TypeDescription
StringShort text values
TextLong text with full-text search support
IntInteger numbers
DecimalFloating-point numbers
BooleanTrue/false values
JsonJSON objects

Link fields create relationships between tables, enabling cross-table queries using dotted path notation.

Defining a link:

{
  "type": "collection",
  "columns": {
    "processorId": { "type": "String", "link": "users.id" }
  }
}

Querying linked fields:

{
  "from": "invoices",
  "where": { "processorId.role": "Manager" },
  "select": ["amount", "processorId.name"]
}

The link property specifies targetTable.keyColumn - the table and column that this field references.

Response

Returns 201 Created on success with the table name.

Add or alter column (v2)

PUT/api/v2/schema/{table}/{column}

Add a column to an existing table, or alter an existing column in place.

  • Add — when the column is new, existing rows are backfilled from the optional value default. A non-nullable column with no value is rejected on a non-empty table (make it "nullable": true to backfill with null).
  • Alter — when the column already exists, its type/analyzer is changed and the data re-indexed. This is a CollectionDb (v2) capability; supported changes are type-compatible: widening Int → Long → Decimal, and String ↔ Text (analyzer). Legacy v1 (TableDb) tables do not support in-place alter.

To set new values across many rows afterwards, use a bulk backfill. A read-write API key is required.

Plan schema change (v2)

POST/api/v2/schema/{table}/_plan

Dry-run a declarative schema change — the terraform plan to _apply.

The body is a target table schema (same shape as create). The response is a classified diff of current vs target: per column an action of add, rebuild, drop, rejected or noop, plus a summary (change count, rows affected, whether it's additive-only, lossy, rejected, or needs confirmation).

_plan is read-only — the schema is not changed. CollectionDb (v2) only. A read API key is required.

Apply schema change (v2)

POST/api/v2/schema/{table}/_apply

Declaratively converge a table to a target schema — the terraform apply to _plan.

The body is a target table schema; _apply adds, rebuilds and drops columns atomically to match it. It refuses rejected/lossy type changes, and refuses column drops (data loss) unless ?confirm=true is passed. The response is the applied plan (same shape as _plan).

CollectionDb (v2) only. A read-write API key is required.

Delete Table (v2)

DELETE/api/v2/schema/{table}

Delete a table and all its data.

Permanently removes the specified table from the database. This operation cannot be undone.

Path Parameters

ParameterTypeDescription
tablestringThe name of the table to delete.

Response

Returns 200 OK on success with the deleted table name.

Warning

This operation permanently deletes the table and all data within it. Make sure to backup any important data before deletion.

Insert Document (v2)

POST/api/v2/data/{table}

Insert a single document into a table.

Adds one document to the specified table. The document fields should match the table schema.

Path Parameters

ParameterTypeDescription
tablestringThe name of the table to insert into.

Request Body

A JSON object containing the document fields and values:

{
  "field1": "value1",
  "field2": 123,
  "field3": true
}

Response

{
  "status": "inserted",
  "table": "tableName",
  "count": 1
}

Notes

  • Works with both CollectionDb and TableDb tables
  • Field names should match the table schema
  • Values are automatically converted to the appropriate column types

Batch Insert (v2)

POST/api/v2/data/{table}/batch

Batch insert multiple documents into a table.

Adds multiple documents to the specified table in a single operation. This is more efficient than inserting documents one at a time.

Path Parameters

ParameterTypeDescription
tablestringThe name of the table to insert into.

Request Body

A JSON array of documents:

[
  { "field1": "value1", "field2": 123 },
  { "field1": "value2", "field2": 456 },
  { "field1": "value3", "field2": 789 }
]

Response

{
  "status": "inserted",
  "table": "tableName",
  "count": 3
}

Notes

  • Works with both CollectionDb and TableDb tables
  • All documents in the batch should have consistent field names
  • Use batch insert for better performance when adding many documents
  • Each document's values are automatically converted to the appropriate column types

Modify data (v2)

POST/api/v2/data/_modify

Apply one or more atomic modification operations to v2 tables (CollectionDb or TableDb) through the unified modification engine.

A single request may carry one operation object, or { "operations": [ ... ] } to apply several in one commit. Supported operations:

  • insert{ "into": "t", "insert": { ... } }
  • update{ "update": "t", "set": { ... }, "where": { ... }, "upsert": true? }
  • delete{ "from": "t", "delete": { ... } }
  • backfill{ "backfill": "t", "key": "id", "keys": [...], "columns": { "col": [...] }, "upsert": false? } — bulk-set column values on existing rows by key (see also the _backfill sugar endpoint)
  • optimize, rename, copy, warm

A read-write API key is required.

Bulk backfill (v2)

POST/api/v2/data/{table}/_backfill

Bulk-set column values on existing rows, matched by a business key — the compact way to populate a column with new values after adding it.

The body is columnar: a key column name plus index-aligned keys and columns value arrays, so it stays small for large jobs (no per-row field-name repetition). All rows are applied in a single commit. A key that matches no row is a no-op unless upsert is true.

This is sugar over the backfill operation of _modify, and works on both CollectionDb (v2) and legacy TableDb tables. A read-write API key is required.

List envs

GET/api/v2/_envs

List the environments that exist in the database.

Identical behavior and response shape as the v1 list endpoint; the v2 path is provided so v2-only clients have a stable URL.

A read API key is sufficient.

See the Environments guide for the URL pattern, when to use envs, and promote semantics.

Branch env

POST/api/v2/_envs

Branch a new environment from an existing one.

Identical behavior, request body, and naming rules as the v1 branch endpoint.

A read-write API key is required.

After creation, target the new env via /env/{name}/api/v2/.... See the Environments guide.

Delete env

DELETE/api/v2/_envs/{env}

Drop the named environment.

Identical behavior as the v1 delete endpoint. Deleting env.master returns 400; reserved (_-prefixed) names are also rejected; missing envs return 404.

A read-write API key is required.

Promote env into master

POST/api/v2/_envs/{env}/promote

Atomically swap the named env into master.

Identical semantics as the v1 promote endpoint: swap-not-move, source preserved, single-transaction.

A read-write API key is required.

List releases

GET/api/v2/_releases

List the published releases of the database — each an immutable, named pointer to a committed head, returned with its content hash.

A read API key is sufficient.

See the Releases guide for how releases differ from environments, the publish/retire lifecycle, and mountable repositories.

Publish release

POST/api/v2/_releases

Freeze the database's current committed head as a new immutable release release.<name>, returning the frozen head hash.

A release is immutable: re-publishing an existing name returns 409 (retire it first). Reserved (_-prefixed) names return 400, as does publishing before the database has any committed state. Names follow the same rules as env names.

A read-write API key is required. See the Releases guide.

Retire release

DELETE/api/v2/_releases/{name}

Retire (unpin) a release. The head it pinned becomes garbage-collection eligible again unless another ref still reaches it. Retiring a release that does not exist returns 404.

A read-write API key is required.

List refs

GET/api/v2/_refs

List every ref in the database — branches (environments, including the default env.master) and releases together — each with its role, mutable flag, and head hash. The default branch is marked default: true.

This is the git-style plumbing read beneath _envs and _releases, so a console can render the whole version graph from one call. Filter with ?role=branch or ?role=release. Available on both v1 and v2 (read-only).

A read API key is sufficient. See the Releases guide.

Create or move a ref

PUT/api/v2/_refs/{ref}

Create or move a ref — the generic write plumbing the _envs/_releases porcelain is sugar over (v2 only; _refs is read-only on v1).

  • PUT /api/v2/_refs/{branch} with { "from": "env.master" } creates a branch from another branch; add ?force=true to move an existing branch.
  • PUT /api/v2/_refs/release.{name} freezes the current head as a release.

Invariants are enforced in the core, identical across every surface: protected refs (_…, system) → 403; re-publishing a release → 409; moving an existing branch without force409; a branch write missing from400. main/master alias the default branch.

A read-write API key is required. See the Releases guide.

Delete or retire a ref

DELETE/api/v2/_refs/{ref}

Delete a branch or retire a release (v2 only). A release.{name} ref is retired; any other ref is deleted as a branch.

Deleting the default (master) branch returns 400; protected refs (_…, system) return 403; a missing ref returns 404.

A read-write API key is required.