# Generating dbt exposures using OMNI APIs

**URL:** <https://community.omni.co/t/generating-dbt-exposures-using-omni-apis/392>\
**Category:** Modeling\
**Tags:** dbt\
**Created:** [September 16, 2025, 4:24pm UTC](https://community.omni.co/t/generating-dbt-exposures-using-omni-apis/392 "2025-09-16T16:24:48Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![samp](https://yyz2.discourse-cdn.com/flex004/user_avatar/community.omni.co/samp/32/520_2.png) [@samp](https://community.omni.co/u/samp)\
**Post date:** [September 16, 2025, 4:24pm UTC](https://community.omni.co/t/generating-dbt-exposures-using-omni-apis/392/1 "2025-09-16T16:24:48Z")

</div>

Here’s a how-to from the Zello team, hope it helps!

We built a pipeline in Pipedream that consumes Omni’s APIs and automatically outputs dbt exposures for dashboards.  
**Step 1.** Dashboards and Queries

- Call `/api/v1/documents` to list dashboards.
- For each dashboard, call `/api/v1/documents/{id}/queries` to get its queries.
- Store both dashboards and queries in Snowflake for further processing.

**Step 2.** Decide Path Based on `query.table`  
For each query, we make a decision based on the `query.table` field:

- **If** `query.table` **starts with** `omni_dbt_*__` → normalize it into a dbt model ref. E.g. **omni\_dbt\_intermediate\_\_dim\_networks → ref(‘dim\_networks’)**
- **If** `query.table` **is a non-dbt Omni model** → use `query.modelId` **+** `query.table` to fetch the YAML from `/api/unstable/models/{modelId}/yaml`.
  - Extract only the **top-level** `sql:` **block** and parse dependencies from that SQL.

- **If** `query.table` **is empty** → parse dependencies directly from `query.userEditedSQL`.

Step 3. Additional Dependency Signals

- `query.fields[]` → when a field looks like `table.column`, we use the prefix to infer joins or sources.
- `${...}` **macros** in SQL are parsed as dbt model refs.
- **FROM/JOIN clauses** in SQL are parsed as fully qualified relations.

Step 4. Generate Exposures

- Merge all dependencies per dashboard, dedupe, and sort alphabetically.
- For each dashboard we output a dbt **exposure** YAML with:
  - Name, label, URL (`https://zello.omniapp.co/dashboards/{id}`)
  - Owner (from dashboard metadata. Would be nice to have an email there, but did not want to make users call here to API)
  - Maturity + refresh cadence tag (derived from `views`)
  - Deterministic `depends_on` list from the rules above

**Result**  
Every Omni dashboard now has a dbt exposure, with dependencies coming directly from **Omni’s queries API (** `query.table` **,** `query.fields` **,** `query.userEditedSQL` **,** `query.modelId` **)** and, when needed, the **Omni model YAML API**.

---

<div class="post-metadata">

**Author:** ![jack](https://yyz2.discourse-cdn.com/flex004/user_avatar/community.omni.co/jack/32/14_2.png) [@jack](https://community.omni.co/u/jack)\
**Post date:** [September 17, 2025, 2:17am UTC](https://community.omni.co/t/generating-dbt-exposures-using-omni-apis/392/2 "2025-09-17T02:17:51Z")

</div>

Thanks for sharing, Sam! As a FYI for anyone who may read this as well, we do also have a native ability to push back dbt exposures from Omni for any dashboards built off dbt models.
