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:
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.
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 / default | Limit | Headers |
|---|---|---|
| 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.
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.
| HTTP | Code | Meaning |
|---|---|---|
400 | bad_request | Invalid parameters, malformed JSON body, or unsupported change_type |
401 | unauthorized | Missing, expired, or revoked Bearer token |
403 | forbidden | Token valid but lacks permission for the resource or workspace |
404 | not_found | Asset, metric, or connector ID does not exist in this workspace |
429 | rate_limited | Per-minute request quota exceeded; retry after Retry-After |
500 | internal_error | Unexpected server error; safe to retry idempotent GETs |
Health
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.
Returns a paginated list of assets matching optional filters. Results are ranked by relevance when search is provided.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
type | string | No | Filter by asset type: table, model, dashboard, pipeline, column |
search | string | No | Full-text search across name, description, and tags |
limit | integer | No | Page size (default 50, max 200) |
cursor | string | No | Pagination 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
}
}
Returns full metadata for a single asset, including schema columns, upstream/downstream counts, and governance fields.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Asset 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.
Returns assets and edges feeding into the target asset, up to the specified depth.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Root asset for traversal |
depth | integer | No | Hop 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" }
]
}
Returns consumers of the target asset: dashboards, exports, downstream models, and certified metrics that depend on it.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Root asset for traversal |
depth | integer | No | Hop 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" }
]
}
Simulates the blast radius of a proposed change (column rename, type change, or deprecation) and returns affected assets grouped by severity.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
asset_id | string | Yes | Asset being changed |
change_type | string | Yes | One 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.
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 }
}
Returns the full metric specification: SQL/logic definition, dimensions, filters, certification audit trail, and lineage to source assets.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Metric 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.
Submit a natural-language question. The agent retrieves relevant assets, lineage paths, and certified metrics before synthesizing an answer with citations.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural-language question (max 4,000 characters) |
context | object | No | Optional 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.
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
| Name | Type | Required | Description |
|---|---|---|---|
connector_id | string | Yes | Connector 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
}
Returns the latest sync run for the connector, including asset counts, errors, and schedule metadata.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
connector_id | string | Yes | Connector 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.