API

REST API reference

Programmatic access to the semantic graph: browse catalog assets, traverse lineage, run impact analysis, query certified metrics, invoke Company Brain agents, and trigger connector syncs. All endpoints require a valid Bearer token unless noted.

Base URL for all requests:

endpoint
https://your-metroflow-host/api/v1

Replace your-metroflow-host with your deployment hostname (e.g. localhost:8080 in Docker Compose). See Authentication for token setup.

Authentication

Include an API token in the Authorization header on every request. Tokens are created in Workspace → Settings → API.

header
Authorization: Bearer mf_live_7f3a9c2e1b4d8a6f0e5c3b9a2d7f1e4

Tip: Use separate tokens per environment (dev/staging/prod) and scope them to the minimum role required. Full guidance is in the Authentication guide.

Rate limits

Metroflow enforces per-workspace rate limits to protect graph query performance. Limits apply per API token (or OAuth client) and reset on a rolling one-minute window.

Plan / defaultLimitHeaders
Self-hosted default 1,000 requests / minute X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
Enterprise (configurable) Up to 10,000 requests / minute Same headers; contact your admin to raise limits

When exceeded, the API returns 429 Too Many Requests with a Retry-After header (seconds until the window resets). Implement exponential backoff in batch jobs and CI pipelines.

Pagination

List endpoints use cursor-based pagination. Pass limit (default 50, max 200) and an optional cursor from the previous response.

response shape
{
"data": [ /* items */ ],
"pagination": {
"limit": 50,
"next_cursor": "eyJpZCI6ImFzc18wMTIzIn0",
"has_more": true
}
}

When has_more is true, pass next_cursor as the cursor query parameter on the next request. Cursors are opaque and expire after 24 hours.

Error codes

Errors return a JSON body with error (machine-readable code), message (human-readable), and optional details.

HTTPCodeMeaning
400bad_requestInvalid parameters, malformed JSON body, or unsupported change_type
401unauthorizedMissing, expired, or revoked Bearer token
403forbiddenToken valid but lacks permission for the resource or workspace
404not_foundAsset, metric, or connector ID does not exist in this workspace
429rate_limitedPer-minute request quota exceeded; retry after Retry-After
500internal_errorUnexpected server error; safe to retry idempotent GETs
example error
{
"error": "not_found",
"message": "Asset ast_9f2c1a8b not found in workspace ws_prod",
"details": { "asset_id": "ast_9f2c1a8b" }
}

Health

GET /health Health check

Returns API liveness and dependency status. Does not require authentication. Use for load balancer and Kubernetes probes.

Response

{
  "status": "ok",
  "version": "2.4.1",
  "uptime_seconds": 86412,
  "dependencies": {
    "graph_db": "ok",
    "metadata_store": "ok",
    "crawler_queue": "ok"
  }
}

Catalog

Search and retrieve assets from the unified metadata catalog: tables, models, dashboards, pipelines, and columns.

GET /catalog/assets List catalog assets

Returns a paginated list of assets matching optional filters. Results are ranked by relevance when search is provided.

Query parameters

NameTypeRequiredDescription
typestringNoFilter by asset type: table, model, dashboard, pipeline, column
searchstringNoFull-text search across name, description, and tags
limitintegerNoPage size (default 50, max 200)
cursorstringNoPagination cursor from a previous response

Examples

curl -s -G "https://your-metroflow-host/api/v1/catalog/assets" \
  -H "Authorization: Bearer $METROFLOW_TOKEN" \
  --data-urlencode "type=model" \
  --data-urlencode "search=revenue" \
  --data-urlencode "limit=25"
import os, requests

resp = requests.get(
    "https://your-metroflow-host/api/v1/catalog/assets",
    headers={"Authorization": f"Bearer {os.environ['METROFLOW_TOKEN']}"},
    params={"type": "model", "search": "revenue", "limit": 25},
)
resp.raise_for_status()
for asset in resp.json()["data"]:
    print(asset["id"], asset["name"], asset["certification"])
const params = new URLSearchParams({ type: "model", search: "revenue", limit: "25" });
const res = await fetch(
  `https://your-metroflow-host/api/v1/catalog/assets?${params}`,
  { headers: { Authorization: `Bearer ${process.env.METROFLOW_TOKEN}` } }
);
const { data, pagination } = await res.json();
console.log(data.length, pagination.has_more);

Response

{
  "data": [
    {
      "id": "ast_mdl_fct_revenue",
      "type": "model",
      "name": "fct_revenue",
      "fqn": "analytics.finance.fct_revenue",
      "description": "Daily recognized revenue by product line",
      "tags": ["finance", "certified"],
      "certification": "certified",
      "owner": "data-finance@acme.com",
      "updated_at": "2026-07-14T09:22:11Z"
    }
  ],
  "pagination": {
    "limit": 25,
    "next_cursor": "eyJpZCI6ImFzdF9tZGxfZmN0X3JldmVudWUifQ",
    "has_more": true
  }
}
GET /catalog/assets/{id} Get asset detail

Returns full metadata for a single asset, including schema columns, upstream/downstream counts, and governance fields.

Path parameters

NameTypeRequiredDescription
idstringYesAsset identifier (e.g. ast_mdl_fct_revenue)

Response

{
  "id": "ast_mdl_fct_revenue",
  "type": "model",
  "name": "fct_revenue",
  "fqn": "analytics.finance.fct_revenue",
  "description": "Daily recognized revenue by product line",
  "columns": [
    { "name": "revenue_date", "type": "date", "description": "Recognition date" },
    { "name": "amount_usd", "type": "numeric", "description": "USD amount" }
  ],
  "lineage_summary": { "upstream_count": 4, "downstream_count": 12 },
  "tags": ["finance", "certified"],
  "certification": "certified",
  "owner": "data-finance@acme.com",
  "source_connector": "dbt_cloud_prod",
  "updated_at": "2026-07-14T09:22:11Z"
}

Lineage

Traverse the semantic graph upstream and downstream, or run impact analysis before schema changes.

GET /lineage/upstream Upstream lineage

Returns assets and edges feeding into the target asset, up to the specified depth.

Query parameters

NameTypeRequiredDescription
asset_idstringYesRoot asset for traversal
depthintegerNoHop depth (default 3, max 10)

Response

{
  "root": "ast_mdl_fct_revenue",
  "direction": "upstream",
  "depth": 3,
  "nodes": [
    { "id": "ast_tbl_raw_orders", "name": "raw_orders", "type": "table", "depth": 1 },
    { "id": "ast_mdl_stg_orders", "name": "stg_orders", "type": "model", "depth": 2 }
  ],
  "edges": [
    { "from": "ast_tbl_raw_orders", "to": "ast_mdl_stg_orders", "kind": "materializes" },
    { "from": "ast_mdl_stg_orders", "to": "ast_mdl_fct_revenue", "kind": "materializes" }
  ]
}
GET /lineage/downstream Downstream lineage

Returns consumers of the target asset: dashboards, exports, downstream models, and certified metrics that depend on it.

Query parameters

NameTypeRequiredDescription
asset_idstringYesRoot asset for traversal
depthintegerNoHop depth (default 3, max 10)

Response

{
  "root": "ast_mdl_fct_revenue",
  "direction": "downstream",
  "depth": 3,
  "nodes": [
    { "id": "ast_dash_exec_kpis", "name": "Executive KPIs", "type": "dashboard", "depth": 1 },
    { "id": "ast_met_mrr", "name": "monthly_recurring_revenue", "type": "metric", "depth": 2 }
  ],
  "edges": [
    { "from": "ast_mdl_fct_revenue", "to": "ast_dash_exec_kpis", "kind": "powers" },
    { "from": "ast_mdl_fct_revenue", "to": "ast_met_mrr", "kind": "defines" }
  ]
}
POST /lineage/impact Impact analysis

Simulates the blast radius of a proposed change (column rename, type change, or deprecation) and returns affected assets grouped by severity.

Request body

NameTypeRequiredDescription
asset_idstringYesAsset being changed
change_typestringYesOne of: column_rename, column_drop, type_change, deprecate

Examples

curl -s -X POST "https://your-metroflow-host/api/v1/lineage/impact" \
  -H "Authorization: Bearer $METROFLOW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"asset_id":"ast_mdl_fct_revenue","change_type":"column_drop"}'
import os, requests

payload = {"asset_id": "ast_mdl_fct_revenue", "change_type": "column_drop"}
r = requests.post(
    "https://your-metroflow-host/api/v1/lineage/impact",
    headers={"Authorization": f"Bearer {os.environ['METROFLOW_TOKEN']}"},
    json=payload,
)
impact = r.json()
print(impact["summary"]["high_risk_count"], "high-risk dependents")
const res = await fetch("https://your-metroflow-host/api/v1/lineage/impact", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.METROFLOW_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ asset_id: "ast_mdl_fct_revenue", change_type: "column_drop" }),
});
const impact = await res.json();
console.log(impact.summary);

Response

{
  "asset_id": "ast_mdl_fct_revenue",
  "change_type": "column_drop",
  "summary": {
    "total_affected": 18,
    "high_risk_count": 3,
    "medium_risk_count": 7,
    "low_risk_count": 8
  },
  "affected": [
    {
      "id": "ast_dash_exec_kpis",
      "name": "Executive KPIs",
      "type": "dashboard",
      "risk": "high",
      "reason": "Direct dependency on dropped column amount_usd"
    },
    {
      "id": "ast_met_mrr",
      "name": "monthly_recurring_revenue",
      "type": "metric",
      "risk": "high",
      "reason": "Certified metric definition references this model"
    }
  ]
}

Metrics

Access certified metric definitions with full lineage to source models and dimensions.

GET /metrics List certified metrics

Returns all metrics with certification status of certified or pending. Supports the same pagination parameters as catalog list endpoints.

Response

{
  "data": [
    {
      "id": "ast_met_mrr",
      "name": "monthly_recurring_revenue",
      "display_name": "MRR",
      "certification": "certified",
      "owner": "data-finance@acme.com",
      "definition_summary": "Sum of active subscription ARR / 12",
      "updated_at": "2026-07-10T14:00:00Z"
    },
    {
      "id": "ast_met_churn",
      "name": "logo_churn_rate",
      "display_name": "Logo churn",
      "certification": "certified",
      "owner": "revops@acme.com",
      "definition_summary": "Churned logos / starting logos",
      "updated_at": "2026-07-08T11:30:00Z"
    }
  ],
  "pagination": { "limit": 50, "next_cursor": null, "has_more": false }
}
GET /metrics/{id} Metric spec with lineage

Returns the full metric specification: SQL/logic definition, dimensions, filters, certification audit trail, and lineage to source assets.

Path parameters

NameTypeRequiredDescription
idstringYesMetric identifier (e.g. ast_met_mrr)

Response

{
  "id": "ast_met_mrr",
  "name": "monthly_recurring_revenue",
  "display_name": "MRR",
  "certification": "certified",
  "certified_by": "data-governance@acme.com",
  "certified_at": "2026-06-01T16:00:00Z",
  "definition": {
    "expression": "SUM(active_arr) / 12",
    "grain": "day",
    "dimensions": ["product_line", "region", "customer_segment"],
    "filters": ["status = 'active'"]
  },
  "lineage": {
    "source_assets": [
      { "id": "ast_mdl_fct_subscriptions", "name": "fct_subscriptions", "type": "model" }
    ],
    "downstream": [
      { "id": "ast_dash_exec_kpis", "name": "Executive KPIs", "type": "dashboard" }
    ]
  },
  "owner": "data-finance@acme.com",
  "updated_at": "2026-07-10T14:00:00Z"
}

Agents

Query the Company Brain, stack-aware AI that answers questions using live catalog, lineage, and metric context.

POST /agents/query Company Brain query

Submit a natural-language question. The agent retrieves relevant assets, lineage paths, and certified metrics before synthesizing an answer with citations.

Request body

NameTypeRequiredDescription
querystringYesNatural-language question (max 4,000 characters)
contextobjectNoOptional scope: asset_ids, tags, or workspace_area

Examples

curl -s -X POST "https://your-metroflow-host/api/v1/agents/query" \
  -H "Authorization: Bearer $METROFLOW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What dashboards break if I rename amount_usd on fct_revenue?",
    "context": { "asset_ids": ["ast_mdl_fct_revenue"] }
  }'
import os, requests

r = requests.post(
    "https://your-metroflow-host/api/v1/agents/query",
    headers={"Authorization": f"Bearer {os.environ['METROFLOW_TOKEN']}"},
    json={
        "query": "What dashboards break if I rename amount_usd on fct_revenue?",
        "context": {"asset_ids": ["ast_mdl_fct_revenue"]},
    },
    timeout=60,
)
answer = r.json()
for cite in answer["citations"]:
    print(cite["asset_id"], cite["snippet"])
const res = await fetch("https://your-metroflow-host/api/v1/agents/query", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.METROFLOW_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    query: "What dashboards break if I rename amount_usd on fct_revenue?",
    context: { asset_ids: ["ast_mdl_fct_revenue"] },
  }),
});
const { answer, citations, confidence } = await res.json();

Response

{
  "query_id": "qry_8a3f2c1d",
  "answer": "Renaming amount_usd on fct_revenue affects 3 dashboards and 1 certified metric. Executive KPIs (ast_dash_exec_kpis) and the MRR metric (ast_met_mrr) are high-risk because they reference this column directly.",
  "confidence": 0.92,
  "citations": [
    {
      "asset_id": "ast_dash_exec_kpis",
      "asset_name": "Executive KPIs",
      "snippet": "Chart 'Revenue trend' uses fct_revenue.amount_usd"
    },
    {
      "asset_id": "ast_met_mrr",
      "asset_name": "monthly_recurring_revenue",
      "snippet": "Metric definition: SUM(amount_usd) grouped by month"
    }
  ],
  "suggested_actions": [
    { "type": "run_impact", "endpoint": "/lineage/impact", "params": { "asset_id": "ast_mdl_fct_revenue", "change_type": "column_rename" } }
  ]
}

Connectors

Trigger metadata syncs and poll connector health from CI pipelines or orchestration tools.

POST /connectors/{connector_id}/sync Trigger metadata sync

Enqueues a full or incremental metadata crawl for the connector. Returns a sync_id to poll via the status endpoint. Idempotent within a 5-minute window.

Path parameters

NameTypeRequiredDescription
connector_idstringYesConnector instance ID (e.g. conn_dbt_cloud_prod)

Response

{
  "sync_id": "sync_7b2e9f4a",
  "connector_id": "conn_dbt_cloud_prod",
  "status": "queued",
  "mode": "incremental",
  "queued_at": "2026-07-16T10:05:00Z",
  "estimated_duration_seconds": 120
}
GET /connectors/{connector_id}/status Connector sync status

Returns the latest sync run for the connector, including asset counts, errors, and schedule metadata.

Path parameters

NameTypeRequiredDescription
connector_idstringYesConnector instance ID

Response

{
  "connector_id": "conn_dbt_cloud_prod",
  "connector_type": "dbt_cloud",
  "health": "healthy",
  "last_sync": {
    "sync_id": "sync_7b2e9f4a",
    "status": "completed",
    "started_at": "2026-07-16T10:05:02Z",
    "completed_at": "2026-07-16T10:06:48Z",
    "assets_discovered": 342,
    "assets_updated": 28,
    "errors": []
  },
  "schedule": {
    "cron": "0 */6 * * *",
    "next_run_at": "2026-07-16T12:00:00Z"
  }
}

CI pattern: POST /sync after a dbt deploy, then poll /status until completed before running downstream impact checks via /lineage/impact.