Skip to documentation

Conduit

Query live data

The knowledge base knows what your documents say; the data layer knows what your systems report right now. eli.ai bridges them through connectors (scoped, read-only external sources) and named queries(governed, parameterized SQL a human authored). This guide lists what's available, runs a query with full provenance, and then crosses the bridge in one call — a grounded answer that cites both documents and live rows.

Prerequisites

  • A key with data:read (list) and data:run (execute).
  • At least one connector and one named query configured in the workspace Data page — see Data connectors & domain components.

Authoring is deliberately not an API job

Creating connectors and named queries — with their credentials, SQL, and read-only validation — is an owner/admin task in the UI, not something an API key does. The API consumes the governed surface: it lists and runs, it never writes SQL. That boundary is what keeps the data layer from becoming a SQL prompt-injection target.

Discover the surface

List the connectors in scope and the named queries you can run. Secrets never appear — you see slugs, titles, descriptions, and parameter specs, which is exactly what you need to make a call.

GET/api/v1/data/connectorsBearer · data:read

List enabled connectors with health status. Credentials and connection configs are never returned.

Example requestbash
curl -s https://your-host/api/v1/data/connectors \
  -H "Authorization: Bearer $ELI_KEY"
Responsejson
{
  "connectors": [
    { "name": "northwind-ops", "kind": "postgres", "enabled": true, "lastStatus": "ok", "lastCheckedAt": "2026-07-21T08:00:00.000Z" }
  ]
}
GET/api/v1/data/queriesBearer · data:read

List named queries (domain components) available to run, with their parameter specs.

Example requestbash
curl -s https://your-host/api/v1/data/queries \
  -H "Authorization: Bearer $ELI_KEY"
Responsejson
{
  "queries": [
    {
      "slug": "stuck-orders-by-age",
      "title": "Stuck orders by age",
      "description": "Orders in STUCK status, grouped by how long they've been stuck. Use for Order Platform health.",
      "connectorName": "northwind-ops",
      "params": [
        { "name": "min_hours", "type": "number", "required": false, "default": 24, "description": "Only orders stuck at least this many hours." }
      ]
    }
  ]
}

Run a query

Call a query by its slug and supply validated params. The response is columns, rows (capped at the connector's maxRows, with a truncated flag), timing, and a dataCallId — the anchor into the append-only provenance trail. Every run, success or failure, writes a data_calls row recording the exact SQL, params, and status.

POST/api/v1/data/queries/{slug}/runBearer · data:run

Execute a named query with validated params. Read-only, capped, timed, and provenance-logged. Params are bound, never interpolated.

Request body

paramsobjectName → value map validated against the query's param specs. Types are coerced; required params must be present; defaults fill the rest.
Example requestbash
curl -s -X POST https://your-host/api/v1/data/queries/stuck-orders-by-age/run \
  -H "Authorization: Bearer $ELI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"params":{"min_hours":24}}'
Responsejson
{
  "dataCallId": "01KY10CCCCCCCCCCCCCCCCCCCC",
  "connectorName": "northwind-ops",
  "queryTitle": "Stuck orders by age",
  "columns": ["age_bucket", "order_count"],
  "rows": [
    { "age_bucket": "24-48h", "order_count": 9 },
    { "age_bucket": ">48h", "order_count": 5 }
  ],
  "rowCount": 2,
  "truncated": false,
  "durationMs": 41,
  "executedAt": "2026-07-21T09:14:03.412Z"
}

A slow or broken source is a status, not a 500

Queries run under a per-connector statement timeout and row cap. A timeout, an error, or a blocked statement returns a structured failure and still writes a data_calls provenance row (status timeout · error · blocked) — never a hung request. Invalid params return 400 with the offending field.

The bridge — one grounded call

The real payoff is not running SQL yourself — it is letting a natural-language question cross into live data automatically. POST /api/v1/query with includeData: true detects the entities in the question, runs their bound queries as governed lookups, and grounds the answer in both documents ([Sn]) and live rows ([Dn]) — the semantic and data layers fused in a single response.

ask across documents and live databash
curl -s -X POST https://your-host/api/v1/query \
  -H "Authorization: Bearer $ELI_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question":"Is anything stuck on the Order Platform right now?","includeData":true}'
dual-cited answer (excerpt)json
{
  "answer": "The Order Platform currently reports 14 stuck orders in the fulfillment queue [D1]. Per the incident runbook, stuck orders older than 24 hours should be requeued from the fulfillment console [S1].",
  "sources":   [ { "id": "S1", "docTitle": "Order Platform incident runbook", "chunkId": "01KY10BB…" } ],
  "dataCalls": [ { "id": "D1", "dataCallId": "01KY10CC…", "connectorName": "northwind-ops", "queryTitle": "Stuck orders by age", "rowCount": 14, "executedAt": "2026-07-21T09:14:03.412Z" } ]
}

The includeData path runs at most three governed lookups and skips any binding whose parameters would need the model to invent a value — it supplies only entity-name and constant params. For the mechanics of which entities map to which queries, see Entity bindings & live data, and for the full response schema, Structured query (v1).

The leverage

Your documents describe the process; your database knows the current state. This endpoint answers questions that need both — "what's our policy, and are we currently violating it?" — with every number traceable to a logged, read-only query and every recommendation traceable to a source chunk. No dashboards to wire, no SQL in your prompts, and a provenance row behind every figure you can hand to an auditor.