Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/api/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ Access is governed by your token's role at three levels:
`env_id` returns `403`.
2. **Resource scope** — the asset, column, and lineage endpoints require the
_assets_ view scope. A role that can reach the environment but isn't granted
the assets resource returns `403`.
the assets resource returns `403`. Test endpoints (**coming soon**) require
the _tests_ view scope.
3. **Per-asset access** — see below.

If your token's role is restricted to a subset of an environment's assets
Expand All @@ -87,9 +88,10 @@ columns and lineage edges derived from them — that you're allowed to see:
- Column-lineage edges are returned only when the downstream column's asset is
visible to you. A returned edge's `upstream_column_id` may reference a
restricted upstream asset; only the id is exposed, not its metadata.
- **Get-one endpoints** (`/assets/{id}`, `/columns/{id}`)
return `404` for an object you can't view — the same response as a nonexistent
object, so the API never discloses that a restricted asset exists.
- **Get-one endpoints** (`/assets/{id}`, `/columns/{id}`, and coming-soon
`/tests/{id}`) return `404` for an object you can't view — the same response
as a nonexistent object, so the API never discloses that a restricted asset
or test exists.

Because filtering is applied per page after rows are read, a page may contain
fewer than `limit` items while `has_more` is still `true`. Always iterate on
Expand Down
6 changes: 6 additions & 0 deletions docs/api/incremental-sync.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ Timestamps are UTC ISO-8601.
| Asset lineage | ✅ | Full replace |
| Column lineage | ✅ | ✅ (`synced_since`, `deleted_since`) |

<Note>
**Coming soon:** tests will use the same `synced_since` / `deleted_since`
pair as assets. Latest test executions will be a full snapshot (no incremental
feed). Per-test execution history is a time window, not an incremental feed.
</Note>

<Note>
Column lineage is returned one record per edge, but edges do not have their
own timestamps. The incremental filters use the downstream column's
Expand Down
54 changes: 39 additions & 15 deletions docs/api/introduction.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
title: 'Introduction'
description: "Read Elementary's assets, columns, and lineage over a REST API."
description: "Read Elementary's assets, columns, lineage, and tests over a REST API."
---

The **Elementary Public API** is a REST interface for programmatically reading
the assets, columns, and lineage Elementary tracks for one
environment. Use it to sync your data catalog and lineage into your own systems
(a warehouse, a BI tool, a data catalog, an internal service).
the assets, columns, lineage, and tests Elementary tracks for one
environment. Use it to sync your data catalog, lineage, and test results into
your own systems (a warehouse, a BI tool, a data catalog, an internal service).

<Warning>
This API is in **active development (beta)** and is **not intended for
Expand Down Expand Up @@ -53,18 +53,22 @@ Follow `next_cursor` until `has_more` is `false` — see [Pagination](/api/pagin

## What you can read

| Resource | Endpoint | Notes |
| -------------- | ------------------------------ | ---------------------------------------- |
| Environments | `GET /environments` | Account-scoped discovery |
| Assets | `GET /{env_id}/assets` | Every asset, common fields + `kind` |
| Table assets | `GET /{env_id}/assets/tables` | Table assets + warehouse-specific fields |
| BI assets | `GET /{env_id}/assets/bi` | BI assets + BI-specific fields |
| Columns | `GET /{env_id}/columns` | Columns of assets |
| Asset lineage | `GET /{env_id}/asset-lineage` | Asset-to-asset edges |
| Column lineage | `GET /{env_id}/column-lineage` | Column-to-column edges |
| Resource | Endpoint | Notes |
| ----------------------- | ------------------------------------------------- | ----------------------------------------------- |
| Environments | `GET /environments` | Account-scoped discovery |
| Assets | `GET /{env_id}/assets` | Every asset, common fields + `kind` |
| Table assets | `GET /{env_id}/assets/tables` | Table assets + warehouse-specific fields |
| BI assets | `GET /{env_id}/assets/bi` | BI assets + BI-specific fields |
| Columns | `GET /{env_id}/columns` | Columns of assets |
| Asset lineage | `GET /{env_id}/asset-lineage` | Asset-to-asset edges |
| Column lineage | `GET /{env_id}/column-lineage` | Column-to-column edges |
| Tests | `GET /{env_id}/tests` | Test definitions. **Coming soon.** |
| Latest test executions | `GET /{env_id}/latest-test-executions` | Current run per sub-test. **Coming soon.** |
| Test execution history | `GET /{env_id}/tests/{test_id}/executions` | History for one test. **Coming soon.** |

Every list endpoint supports a full scan and keyset pagination; assets and
columns also expose incremental feeds — see [Incremental sync](/api/incremental-sync).
Tests will use the same incremental pair when they ship.

## Assets: one base endpoint, plus typed endpoints

Expand Down Expand Up @@ -92,13 +96,33 @@ A typical flow: page `/assets` to build the graph, then enrich the kinds you
care about via the typed endpoints — use the `kind` field to decide which one.

The full endpoint and schema reference is generated from the API and lives under
**API Reference**.
**API Reference**. Test endpoints are documented there as **coming soon** until
they ship.

## Tests (coming soon)

Three datasets, one table each — definitions, current status, and per-test
history are not merged into a single response:

- **[`GET /tests`](/api/reference/tests/list-tests)** — the test definition
(name, type, asset, severity, config, owners/tags). Incremental
`synced_since` / `deleted_since`. A new run does not bump `Test.synced_at`.
- **[`GET /latest-test-executions`](/api/reference/latest-test-executions/list-latest-test-executions)** —
the current run per sub-test. Full snapshot; no incremental feed in this cut.
Join to tests on `test_id`.
- **[`GET /tests/{test_id}/executions`](/api/reference/test-executions/list-test-executions)** —
history for one test (default last 30 days). Not an environment-wide dump.

Table / relation name is a join to [table assets](/api/reference/assets/list-table-assets)
on `asset_id`, not a field on the test. Metric numbers behind a freshness/volume
verdict are not in this cut.

## Forward compatibility

Some string fields are **extensible enums**: they carry a value from a small,
known set today (e.g. `kind`, `source_type`, `data_platform`, `materialization`,
`bi_platform`, `bi_type`, `warehouse_type`, `last_sync_status`), but that set
`bi_platform`, `bi_type`, `warehouse_type`, `last_sync_status`, `test_type`,
`definition_type`, `status`), but that set
grows as Elementary adds integrations and asset types. In the schema these
fields are typed as plain strings with an `Extensible enum.` note and their
currently-known values listed under `examples` — they are **not** a closed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: 'Get a latest test execution'
description: 'Fetch the current run for one sub-test. Coming soon.'
---

<Info icon="clock">
**Coming soon.** This endpoint is not live yet. The contract below is the
planned shape and may change. Calling it today returns `404`.
</Info>

```
GET /public/beta/{env_id}/latest-test-executions/{sub_test_unique_id}
```

Path parameter is **`sub_test_unique_id`**, not the execution `id`. Unknown,
not permitted, or parent test not visible → `404`.

The body's `id` is the **current** execution id and **changes** on every new
run. Use `sub_test_unique_id` as the stable key.

## Response

Bare object. Field meanings match
[List latest test executions](/api/reference/latest-test-executions/list-latest-test-executions).

```json
{
"id": "exec_9f3c2a",
"test_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_test_unique_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_type": "freshness_anomalies",
"column_name": null,
"status": "PASS",
"failure_count": 0,
"start_time": "2026-08-20T11:55:00Z",
"duration_seconds": 12.4,
"quality_dimension": "freshness",
"result_reason": "NO_ANOMALY_DETECTED",
"exception": null,
"description": null,
"synced_at": "2026-08-20T11:55:10Z"
}
```

## Example

```bash
curl -H "Authorization: Bearer $ELEMENTARY_TOKEN" \
"$BASE/$ENV_ID/latest-test-executions/$SUB_TEST_UNIQUE_ID"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: 'List latest test executions'
description: 'Current run per sub-test. Coming soon.'
---

<Info icon="clock">
**Coming soon.** This endpoint is not live yet. The contract below is the
planned shape and may change. Calling it today returns `404`.
</Info>

```
GET /public/beta/{env_id}/latest-test-executions
```

Current status snapshot: one row per live sub-test, updated in place. There is
**no** incremental feed (`synced_since` / `deleted_since`) on this dataset —
re-pull the full list (or filter with `test_ids`) when you want a refresh.

Rows whose parent test is deleted are omitted. Cloud monitors are typically
1:1 with `test_id`; dbt tests may have multiple sub-tests.

The execution `id` on each row **changes** when a new run overwrites the row.
The stable key is `sub_test_unique_id`.

## Query parameters

Shared pagination: `cursor`, `limit` (default `500`, max `2000`). Filter arrays
are any-of within a param, AND across params, max `1000` values each.

| Parameter | Notes |
| ------------------ | --------------------------------------------------------------------------------------------- |
| `sub_test_ids` | Filter by `sub_test_unique_id`. |
| `test_ids` | Latest rows for these tests. |
| `asset_ids` | Latest rows whose parent test is on these assets. |
| `test_types` | Parent test `test_type`. Extensible. |
| `definition_types` | Parent test `definition_type`. Extensible. |
| `source_types` | Parent test `source_type`. Extensible. |
| `statuses` | As stored: `PASS`, `WARN`, `FAIL`, `ERROR`, `SKIPPED`, `NO_DATA`. |
| `order_by` | `id` (default) or `synced_at`. Here `id` means **`sub_test_unique_id`**, not the execution id. |
| `direction` | `asc` (default) or `desc`. |

## Response

List envelope `{ items, next_cursor, has_more }`. Item shape is shared with
[test execution history](/api/reference/test-executions/list-test-executions).

```json
{
"items": [
{
"id": "exec_9f3c2a",
"test_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_test_unique_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_type": "freshness_anomalies",
"column_name": null,
"status": "PASS",
"failure_count": 0,
"start_time": "2026-08-20T11:55:00Z",
"duration_seconds": 12.4,
"quality_dimension": "freshness",
"result_reason": "NO_ANOMALY_DETECTED",
"exception": null,
"description": null,
"synced_at": "2026-08-20T11:55:10Z"
}
],
"next_cursor": "eyJ...",
"has_more": true
}
```

| Field | Notes |
| --------------------- | ---------------------------------------------------------------------------------------------------------- |
| `id` | This run's execution id. On latest rows it **changes** when a new run overwrites the row. |
| `sub_test_unique_id` | Stable per sub-test. Path key for get-one. |
| `status` | As stored: `PASS`, `WARN`, `FAIL`, `ERROR`, `SKIPPED`, `NO_DATA`. |
| `failure_count` | Cloud freshness/volume often `0` — the signal is `status`. |
| `quality_dimension` | Nullable. Examples: `completeness`, `uniqueness`, `freshness`, `validity`, `accuracy`, `consistency`. |
| `result_reason` | Nullable. Examples: `ANOMALY_DETECTED`, `NO_ANOMALY_DETECTED`, `PERMISSIONS_ERROR`, `NOT_ENOUGH_DATA_SAMPLES`. |
| `description` | Empty string in storage is returned as `null`. No `metrics` in this cut. |

## Example

```bash
curl -H "Authorization: Bearer $ELEMENTARY_TOKEN" \
"$BASE/$ENV_ID/latest-test-executions?test_types=elementary_cloud&limit=500"
```
47 changes: 47 additions & 0 deletions docs/api/reference/test-executions/get-a-test-execution.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
title: 'Get a test execution'
description: 'Fetch one historical execution for a test. Coming soon.'
---

<Info icon="clock">
**Coming soon.** This endpoint is not live yet. The contract below is the
planned shape and may change. Calling it today returns `404`.
</Info>

```
GET /public/beta/{env_id}/tests/{test_id}/executions/{execution_id}
```

Path `test_id` unknown or not visible → `404`. An `execution_id` that exists
but belongs to a **different** test also returns `404`.

## Response

Bare object. Field meanings match
[Test execution history](/api/reference/test-executions/list-test-executions).

```json
{
"id": "exec_9f3c2a",
"test_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_test_unique_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_type": "freshness_anomalies",
"column_name": null,
"status": "FAIL",
"failure_count": 0,
"start_time": "2026-08-20T11:55:00Z",
"duration_seconds": 12.4,
"quality_dimension": "freshness",
"result_reason": "ANOMALY_DETECTED",
"exception": null,
"description": null,
"synced_at": "2026-08-20T11:55:10Z"
}
```

## Example

```bash
curl -H "Authorization: Bearer $ELEMENTARY_TOKEN" \
"$BASE/$ENV_ID/tests/$TEST_ID/executions/$EXECUTION_ID"
```
75 changes: 75 additions & 0 deletions docs/api/reference/test-executions/list-test-executions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
title: 'Test execution history'
description: 'Execution history for one test. Coming soon.'
---

<Info icon="clock">
**Coming soon.** This endpoint is not live yet. The contract below is the
planned shape and may change. Calling it today returns `404`.
</Info>

```
GET /public/beta/{env_id}/tests/{test_id}/executions
```

History for **one** test — not an environment-wide dump of every run. Unknown
or not-visible `test_id` → `404`.

There is no `synced_since` feed on this nested list. Default lookback is the
last **30 days** (`start_time >= now - 30d`) when `start_time_from` is omitted.
Default sort is `start_time` **descending**.

Item shape is shared with
[latest test executions](/api/reference/latest-test-executions/list-latest-test-executions).
Metrics (`metric_value`, `expected_min`, `expected_max`, `chart_data`) are not
in this cut.

## Query parameters

Shared pagination: `cursor`, `limit` (default `500`, max `2000`). Filter arrays
are any-of within a param, AND across params, max `1000` values each.

| Parameter | Notes |
| ----------------- | --------------------------------------------------------------------------------------------- |
| `sub_test_ids` | Filter by `sub_test_unique_id`. |
| `statuses` | As stored: `PASS`, `WARN`, `FAIL`, `ERROR`, `SKIPPED`, `NO_DATA`. |
| `start_time_from` | Inclusive lower bound (UTC ISO-8601). Default: 30 days ago. |
| `start_time_to` | Inclusive upper bound (UTC ISO-8601). |
| `order_by` | `start_time` (default) or `id`. |
| `direction` | Default `desc` when `order_by` is omitted; otherwise `asc` unless you pass `desc`. |

## Response

List envelope `{ items, next_cursor, has_more }`.

```json
{
"items": [
{
"id": "exec_9f3c2a",
"test_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_test_unique_id": "elementary_cloud.freshness_anomalies.analytics.orders",
"sub_type": "freshness_anomalies",
"column_name": null,
"status": "FAIL",
"failure_count": 0,
"start_time": "2026-08-20T11:55:00Z",
"duration_seconds": 12.4,
"quality_dimension": "freshness",
"result_reason": "ANOMALY_DETECTED",
"exception": null,
"description": null,
"synced_at": "2026-08-20T11:55:10Z"
}
],
"next_cursor": "eyJ...",
"has_more": true
}
```

## Example

```bash
curl -H "Authorization: Bearer $ELEMENTARY_TOKEN" \
"$BASE/$ENV_ID/tests/$TEST_ID/executions?limit=500"
```
Loading
Loading