Skip to content

Query, search and analytics

Query, search and analytics read the record at volume: one query grammar on every list, search indexes, metrics, reports, and sinks that stream it out.

From the record to every reader

Every read is masked by the caller's Role before it answers. Filled: what a reader sees.

Reading the record at volume

Every read below answers on every Interface and shows only what the caller's Role may see. An empty or partial answer says why.

FamilyWhat it does
One query grammarEvery list takes where (equality, ranges, sets, text, across Relationships), sort, group, count, sum, avg, min, max, fields, limit and cursor; the same words over the API, MCP, the SDK, the CLI and a view
Search indexessearch per Noun: words, typo-tolerant and per language; meaning, kept in the Customer's own Namespace; and facets with their counts. One search across Nouns ranks both
ViewsA saved filter and sort as data, served over every Interface with its count; grouping and totals are the query grammar's or a metric's
MetricsOne layer of measures (sum, count, avg, a ratio of two), dimensions (group), time grains (by) and filters, defined once in the file and answered the same everywhere
ComparisonsAny metric for two periods, or against a target the Customer sets, with the change between them
ReportsSaved metrics sent on a schedule to members by email or to a webhook, and any view or metric as a file on demand
SinksContinuous export of traces, logs, Events, the sales record, the audit log and a Namespace's change data, to OpenTelemetry, a SIEM, object storage or a warehouse
Two owners of sinksYou stream your product's own data on the Operator plane; each Customer streams its own Namespace's records and audit log, on its own Interfaces

A view, a metric and the UI contracts read this one grammar. A chart a UI draws and a number an agent asks for agree.

Example

Deals searched by title, meaning and stage; won value and win rate by month; and a weekly report to every member.

definition.ts
20 lines
import { define } from 'apis.dev'

/** Deals for each Customer, kicked off when won. */
export default define({
  name: 'pipeline', domain: 'pipeline.apis.dev',
  Company: { name: 'string', domain: 'url!#', deals: '<-Deal.company' },
  Deal: {
    title: 'string', amount: 'decimal(12,2)', company: '->Company.deals', notes: 'markdown?',
    stage: { open: [], qualify: 'opened', win: 'qualified', lose: ['opened', 'qualified'] },
  },
  search: { Deal: { text: ['title'], meaning: ['notes'], facets: ['stage'] } },
  metrics: {
    won:     { sum: 'Deal.amount', where: { stage: 'won' }, by: 'month', group: ['company'] },
    wins:    { count: 'Deal', where: { stage: 'won' }, by: 'month' },
    closed:  { count: 'Deal', where: { stage: ['won', 'lost'] }, by: 'month' },
    winRate: { ratio: ['wins', 'closed'], by: 'month' },
  },
  reports: { weekly: { metrics: ['won', 'winRate'], every: 'every Mon 08:00', to: 'email' } },
  offer: { Team: { month: 49, seats: 5, seat: 9 }, 'Deal.open': 0.001 },
})

A member's agent asks for the win rate by month; the answer says how current it is.

Response
HTTP/1.1 200 OK
Content-Type: application/json
X-Cost: price=0, currency="USD"
X-Request-Id: req_0b9d4f27e61a8c53d2e8

{
  "metric": "winRate",
  "by": "month",
  "items": [
    { "month": "2026-08", "value": 0.29 },
    { "month": "2026-09", "value": 0.34 },
    { "month": "2026-10", "value": 0.31 }
  ],
  "total": 3,
  "asOf": "2026-10-27T09:00:00Z"
}

That is GET /metrics/winRate?by=month, getMetric over MCP and pipeline metrics get winRate --by month in the CLI.

Metrics, reports and what a product tells you

A metric is defined once, in the file, and every reader gets the same number.

What your product tells you is a set of these: callers, the funnel, revenue, work and runs, each rebuilt from the record.

ReaderWhat it gets
A Customer's memberMetrics and views over its own org's records, masked by its Role, in the portal, any UI and the API
A Customer's adminThe same across child orgs its org graph rolls up, and a sink of its own Namespace to its own warehouse
YouYour product's signals across every Customer, without any Customer's private fields, and sinks of your own data
An agentAny metric or query by Verb, with asOf on each answer so it knows how fresh the number is
A tool outside the productSinks and the change feed: it reads the product through them and acts through its Verbs

Indexes, reports and sinks, state by state

Each is a Thing with Verbs on the product's API, MCP server and CLI, and each move writes its Event.

ThingStatesWhat moves it
A search indexbuilding, current, behind, rebuildingA deploy that adds or changes it; the Events it reads; a reply names how far behind it is
A metric answercurrent or behind, with asOfThe Events it reads; a period that has not closed is marked open
A reportscheduled, sending, then sent or failedIts schedule, in each Customer's timezone; a failed send retries, then falls back to another channel
A sinkconfigured, backfilling, flowing, then lagging, failed or pausedSink.create, then Sink.backfill from a point in time; a target that refuses holds the data and retries
A sink's schemaFollows the Version it ships inA deploy; a breaking change opens a new schema version beside the old one

Every sink keeps what it could not deliver for seven days, and Sink.backfill sends any range again.

What members, admins and agents meet

  • A member. Filter, group and total any list, search by words or meaning, and never see a record their Role hides.
  • An admin. One report each week, and the org's records and audit log flowing to its own warehouse and SIEM.
  • You. Traces and logs in your own observability tools, and the sales record in your own warehouse.
  • An agent. The same query words on every tool, metrics by name, and asOf on every number.

Every list, search, metric and sink reads one record through one grammar, so a chart, a report and an agent's answer always agree.