# Inviting new users
Source: https://docs.synq.io/admin/invite_user
Only users with admin-level permission can invite new users
1. Navigate to `Settings` → `Team`
2. Click `Add user`
3. Fill in the required fields
The invited user will receive an email with login details to Coalesce Quality.
# Monitor Usage
Source: https://docs.synq.io/admin/monitor-usage
Coalesce Quality is priced based on the number of monitors and users you have. Our admin panel gives you a real-time overview of how many monitors you’ve deployed.
### See monitor usage
* Head to [Settings](https://app.synq.io/settings/integrations) > [Usage](https://app.synq.io/settings/usage)
* The chart and table show the number of custom and automated monitors over time. See [Monitors overview](/monitors/monitors-overview) for a breakdown of what makes up custom and automated monitors.
See [setting up monitors](/monitors/setting-up-monitors) for guidelines on how to configure monitors. [We’re always up for a chat](https://calendly.com/d/yvm-cdr-r3z/synq-intro) if you want specific advice on how to best deploy your monitors
# Single Sign-On (SSO)
Source: https://docs.synq.io/admin/sso
Connect your identity provider so your team signs in to Coalesce Quality with your organization’s credentials
Single Sign-On (SSO) lets your team sign in to Coalesce Quality using your organization’s identity provider (IdP) — such as Microsoft Entra ID (Azure AD), Okta, Google Workspace, or any provider that supports SAML 2.0 or OpenID Connect (OIDC). Authentication is handled by your IdP, so users never need a separate Coalesce Quality password, and you keep central control over access, password policy, and offboarding.
SSO is an enterprise feature. Connections are set up together with our team — reach out to your Coalesce contact or email [support@synq.io](mailto:support@synq.io) to start.
## How SSO works at Coalesce
Coalesce Quality uses [Auth0](https://auth0.com/docs/authenticate/enterprise-connections) as its authentication layer. Setting up SSO is a short, guided exchange between you and our team:
Register Coalesce Quality as an application (sometimes called an “enterprise app”, “integration”, or “relying party”) in your IdP.
We give you the Coalesce Quality URL to add to your app, and you send us your app’s connection details in return.
Our team creates the enterprise connection on the Coalesce Quality side and links it to your workspace.
You verify a test login, then we enable SSO for your workspace.
## Before you begin
* **Administrator access to your identity provider** — you need to be able to create applications and assign users in your IdP.
* **An enterprise plan** with SSO enabled. Contact your Coalesce account team if you’re unsure whether it’s enabled.
* **Your region** — Coalesce Quality is deployed in three regions. Note which one your workspace uses: when you register an OAuth/OIDC app you’ll enter its **callback URL** as the redirect URI. (For SAML connections, Coalesce gives you a connection-specific ACS URL based on this.)
| Region | App URL | Callback URL |
| ---------------- | ------------------------ | --------------------------------------------------- |
| **EU** (default) | `https://app.synq.io` | `https://teamcoalesce.eu.auth0.com/login/callback` |
| **US** | `https://app.us.synq.io` | `https://teamcoalesce.us.auth0.com/login/callback` |
| **AU** | `https://app.au.synq.io` | `https://coalesce-prod.au.auth0.com/login/callback` |
## Step 1: Connect your identity provider
Select your identity provider below and follow its instructions end to end. Each one lists what you’ll need, the steps to perform in your IdP, and what to send back to us. The generic **SAML 2.0** and **OIDC** tabs cover any provider not listed — including Ping Identity, ADFS, OneLogin, and JumpCloud (see [Other identity providers](#other-identity-providers)).
**What you need:** the [**Redirect URI**](#before-you-begin) for your region.
**Steps:**
1. In the [Microsoft Entra admin center](https://entra.microsoft.com), go to **Identity → Applications → App registrations → New registration**.
2. Give it a name, choose the supported account types for your organization, and add the **Redirect URI** (platform **Web**) for your region.
3. Under **Certificates & secrets**, create a new **client secret** and copy its value immediately — it can’t be viewed again later.
4. Under **API permissions**, make sure **User.Read** is granted and grant admin consent. Add **Directory.Read.All** only if you need group or extended attributes.
5. Assign the users or groups who should have access.
**What you send:**
* **Application (client) ID**
* **Client secret**
* Your **Microsoft Entra (Azure AD) domain**
**What you need:** the [**Sign-in redirect URI**](#before-you-begin) for your region.
**Steps:**
1. In the Okta Admin Console, go to **Applications → Applications → Create App Integration**.
2. Select **OIDC – OpenID Connect** and **Web Application**, then click **Next**.
3. Add the **Sign-in redirect URI** for your region.
4. Under the **Assignments** tab, assign the users or groups who should have access.
5. Save the app, then copy its **Client ID** and **Client secret**.
**What you send:**
* **Client ID**
* **Client secret**
* Your **Okta domain** (`https://.okta.com`)
**What you need:** the [**Authorized redirect URI**](#before-you-begin) for your region.
**Steps:**
1. In the [Google Cloud Console](https://console.cloud.google.com), configure the **OAuth consent screen** for your organization (User type **Internal**).
2. Go to **APIs & Services → Credentials → Create credentials → OAuth client ID** and choose **Web application**.
3. Add the **Authorized redirect URI** for your region.
4. Create the client, then copy its **Client ID** and **Client secret**.
**What you send:**
* **Client ID**
* **Client secret**
* Your **Google Workspace domain**
For any IdP that supports SAML 2.0.
**What you need:** the **ACS URL** and **SP Entity ID / Audience** for your connection — Coalesce provides both.
**Steps:**
1. Create a new SAML application / relying party for Coalesce Quality.
2. Set the **Assertion Consumer Service (ACS) URL** and **SP Entity ID / Audience** to the values Coalesce provides. The ACS URL is your region’s callback URL with a `?connection=` parameter, and the Audience is a `urn:auth0:...` identifier.
3. Configure the assertion to send the user’s email (as the Name ID or an attribute) and name (see [Map user attributes](#step-2-map-user-attributes)).
4. Assign the relevant users or groups.
**What you send:**
* The IdP **SAML metadata XML** (or metadata URL) — this includes the IdP Entity ID / Issuer, the SSO endpoint URL, and the X.509 signing certificate
* If you can’t share metadata, send those three values individually
For any IdP that supports OpenID Connect.
**What you need:** the [**Redirect URL**](#before-you-begin).
**Steps:**
1. Register a new OIDC / OAuth 2.0 application for Coalesce Quality.
2. Set the **Redirect URL** to the callback URL for your region.
3. Enable the `openid`, `profile`, and `email` scopes (this sends the email and name; see [Map user attributes](#step-2-map-user-attributes)).
4. Assign the relevant users or groups.
**What you send:**
* **Client ID**
* **Client secret**
* **Issuer URL** (the OIDC discovery base, e.g. `https://your-idp.example.com`)
Send the **client secret** over a secure channel — a secrets manager, or a 1Password shared item or one-time link — never plain email or chat. The client ID, domain, and SAML metadata aren’t sensitive and can be shared normally.
## Step 2: Map user attributes
Coalesce Quality identifies users by their email address and uses their name for display. Make sure your IdP sends these claims:
| Attribute | Required | Notes |
| --------- | ----------- | ---------------------------------------------------------------------------------------------------- |
| **Email** | Yes | Used as the unique user identifier. For SAML, this is typically the Name ID or an `email` attribute. |
| **Name** | Recommended | Used for display. Send a full name, or first name and last name. |
For OIDC, requesting the `openid`, `profile`, and `email` scopes covers these claims.
## Step 3: Test and enforce SSO
1. Once we’ve configured the connection, we share a test login link (or you sign in from the configured app).
2. Confirm you’re redirected to your IdP, authenticate, and land in your Coalesce Quality workspace.
3. When the test succeeds, we enable SSO for your workspace.
Test with a real account from your IdP before rolling SSO out to your whole team. If attribute mapping is wrong, sign-in will fail or create users with missing details.
## User provisioning and roles
New users are provisioned automatically the first time they sign in through SSO (just-in-time provisioning). A newly provisioned user is assigned the **Business User** role, which has the most limited permissions — see [User roles](/admin/user_roles) for what each role can do.
We recommend [inviting users](/admin/invite_user) through the app UI and assigning their role **before** they sign in for the first time. Otherwise they land with the limited permissions of a Business User until an admin updates their role on the [Team page](https://app.synq.io/settings/team).
## Troubleshooting
Usually the URL you entered in your IdP doesn’t exactly match the one Coalesce provided. Re-check it for your region and that there are no trailing spaces.
For OAuth/OIDC connections (Entra ID, Okta, Google Workspace), the **client secret** has likely expired — Microsoft Entra secrets expire by default. Generate a new client secret in your IdP and send the new value to Coalesce.
The X.509 signing certificate Coalesce has doesn’t match the one your IdP is using — often after a certificate rotation. Send us your updated metadata so we can refresh the connection.
Check your attribute / claim mapping in [Map user attributes](#step-2-map-user-attributes). The email claim must be present and must be the address you expect to identify the user by.
Make sure the URLs and identifier you entered match your workspace’s region (`app.synq.io` for EU, `app.us.synq.io` for US, `app.au.synq.io` for AU). Values from another region won’t work.
## Other identity providers
Coalesce Quality works with any identity provider that supports SAML 2.0 or OpenID Connect, even if it isn’t listed in [Step 1](#step-1-connect-your-identity-provider):
* **Ping Identity (PingOne / PingFederate)** and **ADFS** — both support SAML 2.0 and OIDC. Create the application in your provider and follow the generic **SAML 2.0 (other)** or **OIDC (other)** instructions in [Step 1](#step-1-connect-your-identity-provider).
* **On-premises Active Directory / LDAP** — supported, but requires additional setup beyond the standard cloud flow. Contact [support@synq.io](mailto:support@synq.io) to connect an on-premises directory.
If you’re not sure whether your provider is supported, reach out to [support@synq.io](mailto:support@synq.io).
# User roles
Source: https://docs.synq.io/admin/user_roles
| Role | What this role is for | Example users | Key permissions |
| ----------------- | ---------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Admin** | People responsible for configuring and operating Coalesce Quality at the workspace level | Central data platform team, Senior data engineers | • Invite and manage users • Create and manage integrations • Provision API clients and tokens • View usage statistics • Configure workspace-wide settings • Can perform all actions of all other roles |
| **Developer** | Users who build and maintain data quality workflows and data products | Data engineers, Analytics engineers, Advanced analysts | • Deploy monitors and tests • Configure owners, alerts, and notifications • Create and manage data products • Can perform all Analyst actions |
| **Analyst** | Users who need to investigate issues, view lineage, and manage incidents | Data analysts, Product analysts, BI analysts, Data governance | • Manage issues and incidents • Provide feedback to monitors • Mute alerts temporarily • Drill into observability dashboards • View definitions (owners, alerts, integrations) |
| **Business User** | Stakeholders who need visibility into data quality but do not fix issues | PMs, Finance, Growth, RevOps, Marketing, Leadership | • View data product health, status, and issues • Access issue and incident details • View current quality snapshots |
You can contact an admin user in your workspace if you think you should have admin access.\
You can see all member roles on the [team page](https://app.synq.io/settings/team)
# Email
Source: https://docs.synq.io/alert-integrations/email
Integrating Email with Coalesce Quality
See [Link ownership with email](/ownership/creating-an-owner#link-ownership-with-email)
# Microsoft Teams
Source: https://docs.synq.io/alert-integrations/ms-teams
Current capabilities:
* Integrate with the Coalesce Quality app on Microsoft Teams.
* Set up the MS Teams integration.
* Add MS Teams channels and mentions in owners.
* Receive alerts for new issues.
# Setup
* Ask your Teams admin to install the app available [here](https://github.com/getsynq/releases/raw/main/msteams/coalesceQuality-v1.2.0.zip). There are various options for app installation. The easiest would be to directly install it on the team you wish to integrate with for alerts.
* Add an integration on the [settings page](https://app.synq.io/settings/integrations). Select `MS Teams` from the list of platforms. You will need to enter the team URL to create the integration. Once you enter the correct URL, hit `Create` to finalize the creation.
# Creating or Editing Owners
To receive notifications on a Teams channel, you will need to create an owner with the channel configured or update an existing owner with the Teams channel. The following steps apply to either scenario.
* Choose `Add Owner` or `Edit` from the owner's menu.
* Under the section `MS Teams` click `@ Add teams` to enable Teams for the owner. You can then select a channel from the configured Team and optionally add mentions for channel members.
* Once you confirm the create or edit, all alerts configured for the owner will land on the selected Teams channel! 🎉
# Troubleshooting
* If you do not see the option for `MS Teams` while creating or editing an owner, you might not have added the integration. Please setup the bot and integration before trying to edit / create owners.
* If the MS Teams option is disabled, the bot might not be correctly installed on your Team. Contact your Teams admin to set up the bot as per the guide above.
# Opsgenie
Source: https://docs.synq.io/alert-integrations/opsgenie
> **Current Capabilities:**
>
> * Send information about selected issues to Opsgenie.
> * Automatically acknowledge Opsgenie alerts when issues are being worked on.
> * Close Opsgenie alerts when issues are closed.
# Setting Up in Opsgenie
1. Go to the **Teams** section and select the team you want to integrate with Opsgenie.
2. Click on the **Integrations** tab.
3. Click on the **Add Integration** button.
4. From the list of products, select **API**.
5. Enter the integration name (e.g., `Coalesce Quality`) and select the assignee team.
6. Click the **Continue** button.
7. Copy the `API Key` and save it for later use.
8. Click the **Turn on Integration** button and ensure the integration status is set to **ON**.
# Setting up in Coalesce Quality
1. Go to the [Settings](https://app.synq.io/settings/integrations) page.
2. Click on the **Add Integration** button.
3. Select **Opsgenie** from the list of platforms.
4. Enter the `API Key` obtained from the Opsgenie setup and select the appropriate region (`EU` or `US`).
5. Choose the severity of issues and the assets for which alerts should be sent to Opsgenie.
6. Click the **Create** button to complete the integration setup.
# PagerDuty
Source: https://docs.synq.io/alert-integrations/pagerduty
Integrating PagerDuty with Coalesce Quality
# PagerDuty + Coalesce Quality integration benefits
Connecting PagerDuty with Coalesce Quality enhances your incident management and alerting capabilities, ensuring data issues are handled swiftly. Key benefits:
* **Instant Alerts:** Get real-time notifications from PagerDuty when a data issue arises.
* **Quick Impact Assessment:** Easily evaluate the downstream business impact of data issues (e.g., impacted data products) so your team can prioritize fixes.
* **Unified workflow:** On-call responders are alerted immediately, enabling faster, more efficient resolutions that fit your existing workflows.
# How it Works
* Issues triggered by monitors or transformation layer tests (from dbt, SQLMesh, or Coalesce Transform) are sent to PagerDuty as alerts, including details about the downstream impact, an error message, and the activity log
All actions taken in either tool are automatically synced, so both systems stay up-to-date.
# Requirements
* PagerDuty integrations require an Admin base role for account authorization. If you do not have this role, please contact an Admin or Account Owner within your organization to configure the integration.
# Support
If you need help with this integration, please reach out in our shared Slack channel.
# Integration Walkthrough
## In PagerDuty
1. There are two ways to integrate with PagerDuty: via Global Event Routing or on a PagerDuty Service. If you are adding this integration to an existing PagerDuty service, please skip to the Integrating with a PagerDuty Service section of this guide.
### Integrating With Global Event Routing
Integrating with Global Event Routing enables you to route events to specific services based on the payload of the event from your tool. If you would like to learn more, please visit our article on Global Event Routing.
1. From the Configuration menu, select Event Rules.
2. On the Event Rules screen, click on the arrow next to Incoming Event Source to display the Integration key information. Copy your Integration Key. This is the same integration key you will use for any other tool you want to integrate with using event rules. When you have finished setting up the integration in your tool, you will return to this interface to specify how to route events from your tool to services in PagerDuty.

### Integrating With a PagerDuty Service
1. From the **Configuration** menu, select **Services**.
2. There are two ways to add an integration to a service:
* **If you are adding your integration to an existing service**: Click the **name** of the service you want to add the integration to. Then, select the **Integrations** tab and click the **New Integration** button.
* **If you are creating a new service for your integration**: Please read our documentation in section [Configuring Services and Integrations](https://support.pagerduty.com/docs/services-and-integrations#section-configuring-services-and-integrations) and follow the steps outlined in the [Create a New Service](https://support.pagerduty.com/docs/services-and-integrations#section-create-a-new-service) section, selecting **Coalesce Quality** as the **Integration Type** in step 4. Continue with the "In Coalesce Quality" section below once you have finished these steps.
3. Enter an **Integration Name** in the format `monitoring-tool-service-name` (e.g., `coalesce-quality-warehouse-one-monitoring`) and select **Coalesce Quality** from the Integration Type menu.
4. Click the **Add Integration** button to save your new integration. You will be redirected to the Integrations tab for your service.
5. An **Integration Key** will be generated on this screen. Keep this key saved in a safe place, as it will be used when you configure the integration in the next section.

## In Coalesce Quality
1. Head to the **Settings** tab
2. Click **Add integration**
3. Select **PagerDuty Manual**
4. Enter the following
* Integration name: The name of your integration (default is PagerDuty)
* Sevice region: Select EU or US depending on your PagerDuty service
* Integration key: This is the Integration Key linked to your PagerDuty service integration. You can find it by opening the Integrations tab within your PagerDuty service. It’s a 32-character code.
5. Click **Create**
6. Under **Settings** you'll see your new PagerDuty integration
# Syncing the status between PagerDuty and Coalesce Quality
When taking action in PagerDuty, the following mappings apply:
* **Acknowledged**: Sets the status to *Investigating* in Coalesce Quality
* **Resolved**: Sets the status to *Fixed* in Coalesce Quality
When taking action in Coalesce Quality, the following mappings apply:
* **Investigating**: Sets the status to *Acknowledged* in PagerDuty
* **Fixed/Expected/No Action Needed**: Resolves the issue in PagerDuty
## Configuring it in Coalesce Quality
1. Ensure that the PagerDuty integration is working by navigating to **settings**
2. To set up syncing, edit the PagerDuty integration and copy the Webhook URL. You’ll need this URL to configure the Webhook in PagerDuty. When creating a new PagerDuty integration, the Webhook URL will appear after on the integration page.
## Configuring it in PagerDuty
Follow these steps to add a webhook for Coalesce Quality:
1. Go to **Services**, select the relevant service, and open the **Integrations** tab.
2. Scroll to the bottom and click on the option to **Add Webhooks** to the service.
3. Click **New Webhook**.
4. Paste the Webhook URL you obtained earlier, and add a description (e.g., `Coalesce Quality`).
5. Ensure all event subscriptions are selected.
6. Click **Add Webhook** at the bottom of the page.
7. *(Optional)* After the Webhook Subscription is created, PagerDuty will provide a secret to verify webhook payloads. Copy this secret and configure it in the PagerDuty service integration settings to authenticate events received through the webhook.
# Slack
Source: https://docs.synq.io/alert-integrations/slack
Integrating Slack with Coalesce Quality
This guide will walk you through how to set up the Slack integration, which powers our [alerting](/alerts/alert-overview). Coalesce Quality is available as a native Slack application through the marketplace, making it easy to integrate.
To be able to finish this guide, you’ll need:
→ Permission to install Slack 3rd party applications—*Slack allows this by default, but your team might have set up the [application approval process](https://slack.com/help/articles/222386767-Manage-app-approval-for-your-workspace) if you get permissions restriction. Please ask your workspace administrator to help with approval.*
⏱️ Estimated time to finish: 5 minutes.
To ensure we adhere to the principle of the least privilege, we request only minimal permissions to send Slack messages. We require the following permissions:
* **Content and info about channels & conversations** *(View emoji reactions and their associated content in channels and conversations that the app has been added to)*
* **Perform actions in channels & conversations** *(Send messages as @synq, send messages to channels @synq isn't a member of, view messages that directly mention @synq in conversations that the app is in)*
### Integrating Slack with Coalesce Quality
To connect to your Slack workspace, follow the steps below:
1. Visit [https://app.synq.io/slack](https://app.synq.io/slack)
2. Click the “Add to Slack” button that will initiate the integration flow
3. Confirm the permission grant by clicking the green “Allow” button. Depending on your Slack setup, your Slack Workspace Admin may have to approve this step.
### Private channels
If you want to send alerts to a private channel, invite the bot to the channel first by typing `@Coalesce Quality` in the channel and clicking `Invite Them`
# Alerts overview
Source: https://docs.synq.io/alerts/alert-overview
Get notified about the issues that matter, on the channels your teams already use
Alerts are built to bring you all the relevant information to triage, prioritize, and debug issues quickly. They are highly configurable and automatically populated based on your ownership, data product, and monitor settings. You can route them to multiple channels based on rules such as data warehouse schemas, metadata tags, or specific tables.
Coalesce Quality supports alerts for multiple asset types such as **monitors** (anomaly, freshness, volume, and schema monitors), **transformation layers** (dbt, SQLMesh, Coalesce Transform—e.g., test failures, model run failures, source freshness issues), **Airflow** task and DAG failures, and **schema changes**. Alerts can be delivered to **Slack**, **email**, **Microsoft Teams**, and **webhooks**—including **PagerDuty** and **Opsgenie** through webhook integrations. You can create an alert and send it straight to the channels you choose, or attach alerts to owners so they follow your ownership model—see [Routing alerts](/alerts/routing-alerts).
*Example anomaly monitor alert*
### Core concepts
* **Group new and ongoing issues**—receiving repetitive alerts around issues you already know about is tedious. At the same time, you may still want to be reminded of them. As a compromise, we have built an approach that helps you distinguish between new and ongoing issues. See [Configuring an alert](/alerts/setting-up-alerts#configuring-an-alert) for details.
* **Automatically embed ownership**—if issues happen on a data asset with an owner, the owner is automatically displayed. If the owner has a Slack handle attached, the person or group is automatically tagged to bring awareness to the alert.
* **Recent code changes**—alerts display the most recent code change on the data asset so you can quickly confirm or rule out that the last change could have been a cause of the error and who made it. Clicking on it takes you directly to GitHub/GitLab.
* **Downstream impacted assets**—shows the number of downstream tables and BI assets to help you assess the impact. The higher the number, the more likely it is that it’s an error with a high impact. Click on it to jump to a pre-filtered lineage view.
* **Clear error message**—alerts come with built-in error messages that are processed from a source system and, where possible, cleaned to be more human-readable. For example, in dbt and Coalesce Transform, each error message has two parts (1) a human-friendly description of the error to communicate what is wrong and (2) the actual number of rows that failed the given error to help you understand the issue's magnitude.
* **Anomaly chart**—shows the chart in case of an anomaly with an overlay of historical annotations.
* **Manage status and triage issues**—change the incident status to manage the issue resolution workflow and keep track of who’s currently working on the issue.
We have limited the number of issues included in a Slack message to prevent large Slack messages that feel like a wall of text rather than a helpful alert. We default to displaying the first 15 new and five ongoing ones. If some issues get excluded, we will show “*and X more …*” below the relevant section.
### Setting up an alert
* See [Setting up alerts](/alerts/setting-up-alerts)
### Routing alerts
* See [Routing alerts](/alerts/routing-alerts)
### Configuring an alert
* See [Configuring an alert](/alerts/setting-up-alerts#configuring-an-alert)
# Business alerts
Source: https://docs.synq.io/alerts/business-alerts
A **business alert** is a regular alert with a custom [template](/alerts/templates), written in plain language for non-technical stakeholders such as marketing, operations, and sales.
Set one up like any other alert — see [Setting up alerts](/alerts/setting-up-alerts). Scope it to a specific test or monitor to tailor the message, give it a custom subject and body, and [route](/alerts/routing-alerts) it to the channels that team already uses.
# Routing alerts
Source: https://docs.synq.io/alerts/routing-alerts
Every alert can be sent to one or more **destinations**. You can send an alert straight to specific channels, route it through an owner so it follows team ownership, or do both on the same alert. The available destinations are **Slack**, **email**, **Microsoft Teams**, and **webhooks** (including **PagerDuty** and **Opsgenie**).
## Send directly to channels
When you create an alert in **Settings → Alerts**, you pick where it goes on the **Targets** step — no owner needed. Add any mix of:
* a **Slack** channel
* a **Microsoft Teams** channel
* one or more **email** addresses
* a **webhook**, including PagerDuty and Opsgenie
This is the simplest way to route an alert: the alert knows where it goes, so you can see and change its destinations in one place. Use it for alerts that don't belong to a single team — for example a company-wide freshness alert to `#data-alerts`, or a webhook that opens a PagerDuty incident.
Not every destination is offered for every alert. Slack and Microsoft Teams are available for issue and schema-change alerts, email for every alert, and webhooks for issue alerts.
## Route through an owner
Instead of naming channels on the alert, you can send it to an **owner**. The alert then goes to all the channels that owner has set up — its Slack channel, Microsoft Teams channel, email addresses, and Coalesce Quality users. You set those up on the owner (see [Setting up alerts](/alerts/setting-up-alerts) and [Tagging owners](/alerts/tagging-owners)).
*Alert routed to #operations-data-team*
Routing through an owner is handy when you want alerts to follow team ownership: change the owner's channel once and every alert sent to that owner follows. You can also give the same assets more than one owner to alert several teams at once.
# Setting up alerts
Source: https://docs.synq.io/alerts/setting-up-alerts
There are two ways to set up alerts in Coalesce Quality:
* **Create an alert directly** in **Settings → Alerts**. You choose what it triggers on (specific assets, monitors, tests, or a data product), how it is configured, its message [template](/alerts/templates), and where it is sent — all on the alert itself. This is the most direct option and doesn't require an owner; see [Routing alerts](/alerts/routing-alerts) for the available destinations.
* **Attach alerts to an owner**, so they follow your ownership model and route through the channels configured on that owner. This is described below.
## Owner-based alerts
Owner-based alerts are set based on your ownership definitions (see [Ownership overview](/ownership/ownership-overview)).
Ownership can be defined in three main ways, serving as the backbone for owner-based alerts.
1. **All assets**—owns all assets. Use this to, e.g., create a `data team` owner and be notified of issues on any assets to your main alerting Slack channel.
2. **Custom query**—use this to select specific assets you want to be notified about using the browser or advanced filters. This is useful for setting up alerts for specific parts of your stack such as data assets in a specific database schema
3. **Data product**—use this to be notified on issues on or upstream of a data product. This is helpful for owners of data products to be aware of issues that may impact them.
### Setting up an alert for a new owner
1. Follow the steps to create a new owner and set up alerts following the step-by-step wizard: [Creating an owner](/ownership/creating-an-owner)
### Editing alerts for an existing owner
1. Navigate to `Owners` and click on the owner you want to modify
2. Click `Edit owner` to modify the owner name and its notification channels — a **Slack** channel and handles, a **Microsoft Teams** channel and mentions, **email** addresses, and **Coalesce Quality users**. Alerts routed through this owner are sent to whichever channels you set here.
3. To add additional assets to the owner, click `Add owned assets`
4. To modify existing assets or alerts, click the three dots and select `Edit definitions` to edit the asset selection or `Edit alerts` to edit the alert configuration.
### Configuring an alert
Alerts are highly configurable and can be set up to fit your needs.
1. When creating an alert for an owner or editing an existing alert, you’re presented with the following settings.
* **Severity**—choose which issue severities trigger the alert. Select any combination of `Critical`, `Error`, and `Warning` (e.g., select `Warning` to be notified of warn-level test issues from dbt, SQLMesh, or Coalesce Transform)
* **Upstream issues**—check if you want to receive alerts about upstream issues that could be impacting your data product
* **Ongoing issues alerts**—by default you are only alerted when a *new* issue is detected. Turn this on to also be reminded about issues that are still unresolved:
* **Disabled**—only alert on new issues (default)
* **Schedule**—send one reminder per day at a time you choose (UTC)
* **Each run**—alert on every failed run. Not recommended, as it often produces too many alerts
Expand **Advanced options** for a couple of extra settings:
* **SQL test audit link**—for SQL-based tests (dbt, SQLMesh, Coalesce Transform), include a link in the alert to the test audit report so recipients can inspect the rows that failed
* **Custom email reply-to**—for email alerts, set the reply-to address and the display name recipients see
# Tagging owners
Source: https://docs.synq.io/alerts/tagging-owners
If you set up an owner and link the owner to a Slack handle, the owner will automatically be tagged in the alert, making it clear to everyone responsible for addressing the alert.
Slack handles can be both individuals (e.g., `John Doe`) or groups (e.g., `product-analytics`)
It’s particularly helpful to associate Slack handles with owners when you have a central alerting channel (e.g., `#data-alerts`) and a larger data team, as it can otherwise be difficult to know who’s responsible for looking at an alert.
*The data team is being tagged for an anomaly alert*
### Setting up a Slack handle for an owner
* Follow the steps in [Link ownership to Slack](/ownership/creating-an-owner#link-ownership-with-slack)
# Writing alert templates
Source: https://docs.synq.io/alerts/templates
Customize the content and wording of your Coalesce Quality alerts
Alert templates let you control the exact content and wording of the alerts
Coalesce Quality sends so an alert reads the way your team expects.
## Choosing a template mode
Every alert offers three template modes. Pick one at the top of the template editor:
| Mode | When to use |
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| **Standard** | The default. Uses the built-in alert format — no customization needed. |
| **Custom plain text** | Set a fixed **title** and **body** that never change. See [Plain text templates](#plain-text-templates). |
| **Custom dynamic** | Compose the message from ordered blocks and template variables. See [Dynamic templates](#dynamic-templates). |
**Alerts for business stakeholders** can be set up as templated alerts with a custom subject and body — write plain-language content that non-technical teams (marketing, operations, sales) can act on. Scope the alert to a specific test or monitor to tailor the message per rule, and [route](/alerts/routing-alerts) it to the channels they already use.
## Plain text templates
Custom plain text lets you define a fixed **title** and **body**.
Leave a field empty to use the default for that alert. Use this mode when you want a fixed,
unchanging message, like sending static content to stakeholders.
## Dynamic templates
**Alpha feature.** Customizing alert content with Dynamic templates as
described here — are currently in Alpha. Contact the
Coalesce team to have them enabled for your workspace.
Dynamic templates use block-based template layout that is interpreted by a Jinja engine.
They allow you more control over the alert content with variables and sections.
### The block model
A template is an **ordered list of blocks**. Each block is a small,
self-contained fragment written in [Jinja](https://jinja.palletsprojects.com/),
and each block renders on its own — a block cannot reference or inherit from
another block. There is no shared base template: `{% extends %}` and
`{% include %}` are **not** supported and will fail to render.
Each alert ships with a **default template** made up of the shared catalog
blocks below. When you save a custom template it **replaces the default
entirely** — so to keep a section you must keep its block, and to remove a
section you simply omit its block.
### Layout sections
A rendered alert is laid out in two sections, and every block belongs to one of
them:
| Section | When it renders |
| ---------------- | -------------------------------------------------------------------- |
| **Summary** | Once per alert — the top-level message. |
| **Issue detail** | Repeated for each issue in the alert — the issue card or attachment. |
Catalog blocks have fixed placements per channel, so they land in the right
section automatically. A **custom block** renders in whichever section you
assign it to.
### Catalog blocks
Catalog blocks land in a fixed layout section — you don't place them yourself. The
sections below are the defaults for Ungrouped Issue alerts; Grouped Issue alerts
may repeat a block across both sections.
| Block | Section | What it shows |
| ---------------- | ------------ | ------------------------------------------------------------------------------------- |
| `headline` | Summary | The asset that triggered the alert, linked to the issue, plus its heads and folders. |
| `products` | Summary | Affected and downstream data products. |
| `ownership` | Summary | Owners of the asset and downstream owners, tagging them where a handle is configured. |
| `error_message` | Issue detail | The issue message. |
| `asset_metadata` | Issue detail | The most recent code change and schema change on the asset (within the last 30 days). |
| `incident_mgmt` | Issue detail | Drives the Incident Management tooling. Renders in Slack only. |
### Custom blocks
You are not limited to the catalog. Add your own named block with whatever Jinja
content you like; it renders in list order within the layout section you assign
it to.
### Variables and filters
**Variables** carry the alert's data; **filters** (tagged `filter` below) format
a value. Apply a filter with a pipe: `{{ asset.name | bold }}`. Every variable is
optional — a value that isn't available for a given alert renders as empty rather
than erroring, and a filter applied to an empty value renders as empty text.
Click **Available variables** in the editor to open a reference panel listing every
variable and filter grouped by category, so you can browse and insert them without
leaving the editor.
The following are available on **every** alert:
| Name | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `workspace` | Workspace identifier. |
| `alert.id` | Alert identifier. |
| `issue.url` | Link to the issue (or failing run) in Coalesce Quality. |
| `issue.message` | Issue or run message. |
| `asset.name` | Asset name (truncated). |
| `asset.path` | Fully-qualified asset path. |
| `asset.type_name` | Human-readable asset type, e.g. `Table`. |
| `asset.url` | Link to the asset. |
| `asset.folders` | List of folder names the asset lives in. |
| `asset.heads` | List of head assets, each with `name`, `path`, `type_name`, `url`. |
| `owners` | Asset owners, each with `id`, `title`, `path`, `mention`. |
| `downstream_owners` | Downstream owners, same fields as `owners`. |
| `commit` | Most recent code change (within 30 days): `short_message`, `author_name`, `mailto`, `url`, `ago`. Empty if none. |
| `schema_change` | Most recent schema change (within 30 days): `url`, `ago`. Empty if none. |
| `bold` `filter` | Bold text. |
| `italic` `filter` | Italic text. |
| `link(url)` `filter` | Render the value as a hyperlink to `url`; an empty `url` degrades to the bare label. |
| `code` `filter` | Inline / block code. Pass a language, e.g. `code("sql")`. |
| `date(layout)` `filter` | Format a timestamp. Accepts a `strftime` string (e.g. `"%Y-%m-%d"`) or a Go layout; defaults to `2006-01-02 15:04:05 UTC`. |
| `join` `filter` | Join a list into a string (standard Jinja filter). |
Filters are **channel-aware**: the same template renders native Slack markup,
HTML email, or MS Teams markup depending on where the alert is sent — you don't
(and can't) branch on the channel yourself. The `mention` field on `owners` and
`downstream_owners` is already formatted for the channel, so print it directly.
#### Ungrouped Issue alerts
Alerts that fire once per issue expose these in addition to the common set:
| Name | Description |
| -------------------------- | ---------------------------------------------------------------- |
| `alert.action` | `created`, `updated`, `status_updated`, or `closed`. |
| `alert.action_verb` | Human-readable action, e.g. `created`, `status updated`. |
| `issue.id` | Issue identifier. |
| `issue.group_id` | Identifier of the issue group. |
| `issue.title` | Issue title (truncated). |
| `issue.name` | Issue name. |
| `issue.muted` | Whether the issue is muted. |
| `asset.schema` | Asset schema, derived from the path. |
| `products` | Affected data products, each with `id`, `title`, `label`, `url`. |
| `downstream_products` | Downstream affected data products, same fields as `products`. |
| `incident_mgmt.set_status` | Whether the Set Status action is available. |
#### Grouped Issue alerts
Alerts that group issues by failing entity expose these in addition to the common
set:
| Name | Description |
| --------------------- | ------------------------------------------------------------------------- |
| `failure.message` | Failure message. |
| `failure.started_at` | When the failing run started (a timestamp — pair with the `date` filter). |
| `failure.status_verb` | Human-readable run status, e.g. `failed`. |
| `failure.duration` | How long the failing run took, pre-formatted (e.g. `3s`). |
### Worked examples
#### A stripped-back analyst Slack alert
To give analysts a lean alert, keep the headline, affected products, ownership,
and error message, and drop the asset metadata and incident-management sections.
Because a custom template replaces the default, you achieve this by keeping only
the blocks you want:
| Block | Section | Content |
| --------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `headline` | Summary | `{{ asset.type_name }} {{ asset.name \| link(issue.url) \| bold }}` |
| `products` | Summary | `{% if products %}Affected Products: {% for p in products %}{{ p.label \| link(p.url) }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}` |
| `ownership` | Summary | `{% if owners %}Owned by: {% for o in owners %}{{ o.title }}{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}` |
| `error_message` | Issue detail | `{{ issue.message }}` |
Omitting `asset_metadata` and `incident_mgmt` removes those sections — and
because `incident_mgmt` is gone, the Slack **Set Status** button is dropped too.
#### A headline that leads with the schema
To surface the schema in the headline, override the `headline` block on a
**per-issue alert**:
```jinja theme={null}
{{ asset.schema }}/{{ asset.name }} {{ alert.action_verb }}
```
For an issue that was just created on `analytics.orders`, this renders as
`analytics/orders created`. (Use this on per-issue alerts — `asset.schema` is not
available on grouped alerts.)
#### Adding a remediation playbook link to the summary
The summary can carry more than the default blocks. Add a **custom block** and
assign it to the **Summary** section to include a "what to do next" line — for
example, a link to your team's runbook for fixing the issue:
```jinja theme={null}
Runbook: {{ "Fix failing orders models" | link("https://wiki.example.com/runbooks/orders") }}
```
Because the link is a plain Jinja string, you can point it at any URL — a
Confluence page, a Notion doc, a GitHub README. The `link` filter renders it as a
native hyperlink in Slack, email, and Microsoft Teams alike. To make the link
follow the asset, build the URL from a variable instead of hard-coding it:
```jinja theme={null}
Runbook: {{ "Remediation steps" | link("https://wiki.example.com/runbooks/" ~ asset.name) }}
```
This new block renders alongside the headline in the alert summary, so recipients
see how to respond right next to what went wrong.
### When a template breaks
Templates are validated as you edit: the **live preview** in the editor renders
your template against a sample alert and shows any parse or render error inline,
so you can fix it before saving. Because filters are channel-aware, the same
template is previewed as it will appear in each channel — switch the preview
between **Slack**, **Email**, and **Microsoft Teams**:
If a saved template ever fails to render when a real alert fires — for example a
typo introduced later, or a variable used in a way that errors — Coalesce Quality
falls back to the **default template** for that alert and sends it. **Delivery is
never blocked and no partial message is sent.**
# Analytics overview
Source: https://docs.synq.io/analytics/analytics-overview
Coalesce Quality analytics gives you a bird's-eye view of the health of your data stack so you can systematically improve what matters most
Analytics is a helpful way to get everyone in your company on the same page regarding the state of your data. For example:
* Benchmark and monitor the performance of your most important data assets
* Keep stakeholders in the loop as you’re making improvements by tracking key metrics
* Identify gaps and segment your quality data across teams, platforms, and data products
## Data quality dimensions
All metrics are broken down into automated groupings
| Dimension | Description |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| Accuracy | Ensures data correctly represents real-world facts (e.g., accepted\_values test for valid statuses, custom SQL checks for calculated metrics). |
| Completeness | Confirms all necessary data is present (e.g., not\_null test for critical columns, row count checks). |
| Uniqueness | Ensures no duplicate entries exist (e.g., unique test on primary key columns). |
| Timeliness | Checks data freshness and update frequency (e.g., source freshness tests from dbt or Coalesce Transform, custom timestamp lag checks). |
| Validity | Confirms data adheres to formats and rules (e.g., accepted\_values test for categorical data, regex-based custom tests for formatting). |
| Uncategorised | Everything else |
## Data quality metrics
Coalesce Quality offers a wide range of metrics to track your data quality
* **% of tests without issues** — This metric helps monitor the overall health and stability of the system. A low percentage indicates that you have systemic issues, or should reevaluate if certain tests are needed.
* **Number of tests** — This reflects the breadth and scope of testing coverage, showing how thoroughly the system is tested.
* **Number of tests with issues** — Tracking tests with issues provides a direct view into potential problem areas within your stack. A high or increasing count can indicate recurring weaknesses or instability in certain areas, highlighting where teams should prioritize fixes or additional safeguards.
* **New and resolved issues** — This metric reveals the rate of new issues and resolution, indicating your team’s responsiveness to issues. An ideal balance shows that new issues are resolved quickly, while an imbalance with more new issues than resolved ones can indicate growing technical data debt.
* **# incidents** — Unlike data test errors, incidents are explicitly declared by you. Counting the number of incidents gives you an indication of how many severe issues you’ve had across key parts of your business.
## Actioning data quality insights
* **Segment your insights** — Use the `Add Filter` functionality to segment insights by the owner, data product, and platform. This helps make the insights actionable and focused.
* **Create data quality run books** – If you're in a larger team, include clear steps around addressing each data quality dimension so it's clear for everyone. For example, if the Timeliness score is low, you can recommend steps such as adding a source freshness check in your transformation layer (dbt, Coalesce Transform) or an automated freshness monitor.
# Check categories
Source: https://docs.synq.io/analytics/check-categories
Classify every check into governance and technical categories so analytics, coverage, and reporting stay consistent across your data stack
Checks arrive from many tools, each with its own naming. A dbt `not_null`
test, a dbt `not_null_proportion` test, an `elementary` test, a SQLMesh audit,
and a hand-written SQL assertion can all be checking the same thing — that a
column has no missing values — yet none of them share a name. Left as-is,
there's no way to ask *"how well is completeness covered across my stack?"*
without knowing every tool's vocabulary.
Check categorisation solves this. Coalesce Quality categorises every check
(dbt tests, SQLMesh audits, custom assertions, …) as it is ingested, mapping
each one onto a **consistent taxonomy** regardless of which tool produced it.
That shared vocabulary is what powers the analytics dashboards, coverage
reports, and filtering across the product — so a check only shows up in the
right place if it is categorised correctly.
Categorisation happens along **two independent dimensions**:
| Dimension | Answers | Example values | Primarily used by |
| -------------- | ------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| **Governance** | *What is the purpose of this check?* | Completeness, Accuracy, Validity, Timeliness, Uniqueness | Data governance teams tracking coverage against governance requirements |
| **Technical** | *What kind of check is this, mechanically?* | nullness, uniqueness, referential integrity, freshness | Analysts and developers navigating and organising checks |
The governance dimension maps onto the
[data quality dimensions](/analytics/analytics-overview) you see in Analytics.
The technical dimension groups checks by their validation logic — for example
every `not_null` variant across dbt, SQLMesh and custom SQL collapses into a
single `nullness` group.
A check carries **one category per dimension**. The two are resolved
independently, so a single check can be `Completeness` for governance and
`nullness` for technical at the same time.
## Where categories come from
For each dimension, a check's effective category is resolved from three
sources, in descending priority:
1. **Admin override** — a per-check category set by a workspace admin from the
**Checks** tab (see [Per-check overrides](#per-check-overrides)). Overrides
always win.
2. **Producer-explicit category** — set directly by the producer, or carried on
the source asset as a `synq.check_category` / `synq.governance_category`
annotation.
3. **Computed category** — derived by the categorisation engine from the
**categorisation rules** described below. A matching **workspace** rule wins
over a matching **global** rule.
If none of these produces a value the check is **Uncategorised** for that
dimension. When a higher tier supplies the value, the UI still shows which rule
*would* have matched — so you can see what an override or explicit value is
masking.
## Categorisation rules
A categorisation rule says *"checks matching this predicate get this
category"*. Rules are managed under **Health → Check categorisation**, which has
a section per dimension (**Governance**, **Technical**) plus a **Checks**
section for inspecting how individual checks were categorised.
Each rule has:
* a **category** — the value assigned to checks it matches (free-form, e.g.
`completeness` or `nullness`);
* a **priority** — when several rules match the same check, the
highest-priority rule wins;
* a **predicate** — either a [structured predicate](#structured-predicate) or a
[CEL expression](#cel-expressions), never both.
Rules created in the app are **workspace rules** — they apply only to your
workspace and win over the **global**, Coalesce Quality-provided rules on a
priority tie. Global rules are maintained by Coalesce Quality administrators.
### Structured predicate
The structured predicate matches on the facts a check already carries. A check
matches when **every non-empty group** below contains the check's value — an
empty group matches anything.
| Group | Matches against | Example |
| ------------------------- | -------------------------------------- | --------------------------------------- |
| **Platforms** | The platform the check comes from | `dbt`, `SQLMesh` |
| **Asset types** | The check's asset type | `dbt test`, `SQLMesh audit` |
| **Packages** | The package providing the check | `dbt-utils`, `elementary` |
| **Kinds** | The check's validation-logic kind | `not_null`, `unique`, `accepted_values` |
| **Names** | Glob patterns against the check's name | `freshness_*` |
| **Annotation predicates** | Key/value annotations on the check | `dbt.tag` equals `pii` |
For example, a rule with **Platforms** = `dbt` and **Kinds** = `not_null`,
`not_null_proportion` matches every dbt not-null-style test and nothing else.
**Names** use `*` as a wildcard for any sequence of characters (every other
character is literal); multiple patterns are OR-ed.
**Annotation predicates** match a check's annotations by key, with one of four
modes per key:
| Mode | Matches when the annotation… |
| ----------------- | -------------------------------- |
| **exists** | …is present, regardless of value |
| **equals** | …equals a given value |
| **is one of** | …equals any value in a list |
| **matches regex** | …matches a regular expression |
The platform and asset-type dropdowns are populated from checks actually present
in your workspace and narrow as you pick, so you only ever see real values.
### CEL expressions
When the structured predicate isn't expressive enough — string prefixes,
regular expressions, combining conditions with `||` — switch the predicate to a
**CEL expression**. The rule matches a check when the expression evaluates to
`true`.
[CEL](https://github.com/google/cel-spec) (Common Expression Language) is a
small, safe expression language. The following variables are available:
| Variable | Type | Description |
| -------------------- | --------------------- | --------------------------------------------------------------------- |
| `platform` | `string` | Platform name, e.g. `PLATFORM_DBT` |
| `asset_type` | `string` | Asset type name, e.g. `ASSET_TYPE_DBT_TEST` |
| `package` | `string` | Package providing the check, may be empty |
| `kind` | `string` | Validation-logic kind, e.g. `not_null` |
| `name` | `string` | Short name of the check |
| `description` | `string` | Human-readable description, may be empty |
| `is_platform_native` | `bool` | `true` for checks built into the platform (vs. custom or third-party) |
| `annotations` | `map` | Key/value annotations on the check |
`PLATFORM_*` and `ASSET_TYPE_*` enum names are exposed as string constants, so
you can compare against them directly.
```python theme={null}
# every dbt not-null-style test
platform == PLATFORM_DBT && kind.startsWith("not_null")
# checks the source asset tagged as PII
annotations["dbt.tag"] == "pii"
# anything matching a naming convention, on any platform
name.matches("(?i)^freshness_.*")
# custom assertions that are not platform-native
asset_type == ASSET_TYPE_CUSTOM_TEST && !is_platform_native
```
Prefer the structured predicate when it can express your rule — it's easier to
read at a glance and cheaper to evaluate. Reach for CEL only for the cases it
can't cover.
## Live impact preview
While you edit a rule, the dialog runs a **live impact preview** against the
checks in your workspace, showing how many checks the rule would match before
you save. A rule with no predicate (an empty structured predicate and no CEL
expression) is flagged as a **catch-all** — it would match every check at its
priority — and the preview is skipped until you add at least one condition.
## Per-check overrides
The **Checks** section lists every check with its resolved Technical and
Governance categories and the source that produced each one. Workspace admins
can pin a category on an individual check with **Set explicit category**, which
sets a Technical and/or Governance value that takes precedence over both the
producer-explicit value and any rule match. Clearing both dimensions removes the
override, and the check falls back to its underlying category.
You can also create a rule straight from a check — the rule dialog opens
prefilled with that check's platform, asset type, package, and kind so it
matches checks shaped like it.
## Recategorisation
Whenever you add, edit, or delete a rule, Coalesce Quality enqueues a
**recategorisation sweep** that re-evaluates existing checks against the
updated rule set. The Check categorisation page shows the sweep's progress;
new checks are categorised as they are ingested.
# API
Source: https://docs.synq.io/api-reference/api
## Services
### IncidentsService
(synq.incidents.v1.IncidentsService)
IncidentsService is a service for managing Incidents.
#### CreateIncident
CreateIncident ([CreateIncidentRequest](#createincidentrequest)) [CreateIncidentResponse](#createincidentresponse)
#### RenameIncident
RenameIncident ([RenameIncidentRequest](#renameincidentrequest)) [RenameIncidentResponse](#renameincidentresponse)
#### UpdateIncidentState
UpdateIncidentState ([UpdateIncidentStateRequest](#updateincidentstaterequest)) [UpdateIncidentStateResponse](#updateincidentstateresponse)
#### CancelIncident
CancelIncident ([CancelIncidentRequest](#cancelincidentrequest)) [CancelIncidentResponse](#cancelincidentresponse)
Cancel an incident
#### CloseIncident
CloseIncident ([CloseIncidentRequest](#closeincidentrequest)) [CloseIncidentResponse](#closeincidentresponse)
Close an incident
#### MergeIncidents
MergeIncidents ([MergeIncidentsRequest](#mergeincidentsrequest)) [MergeIncidentsResponse](#mergeincidentsresponse)
#### SplitIncident
SplitIncident ([SplitIncidentRequest](#splitincidentrequest)) [SplitIncidentResponse](#splitincidentresponse)
#### AddIssuesToIncident
AddIssuesToIncident ([AddIssuesToIncidentRequest](#addissuestoincidentrequest)) [AddIssuesToIncidentResponse](#addissuestoincidentresponse)
#### RemoveIssuesFromIncident
RemoveIssuesFromIncident ([RemoveIssuesFromIncidentRequest](#removeissuesfromincidentrequest)) [RemoveIssuesFromIncidentResponse](#removeissuesfromincidentresponse)
#### ListIncidents
ListIncidents ([ListIncidentsRequest](#listincidentsrequest)) [ListIncidentsResponse](#listincidentsresponse)
#### BatchGetIncidents
BatchGetIncidents ([BatchGetIncidentsRequest](#batchgetincidentsrequest)) [BatchGetIncidentsResponse](#batchgetincidentsresponse)
#### AssignIncidentOwner
AssignIncidentOwner ([AssignIncidentOwnerRequest](#assignincidentownerrequest)) [AssignIncidentOwnerResponse](#assignincidentownerresponse)
#### PostComment
PostComment ([PostCommentRequest](#postcommentrequest)) [PostCommentResponse](#postcommentresponse)
Post a comment on an incident.
### IamService
(synq.auth.iam.v1.IamService)
#### Iam
Iam ([IamRequest](#iamrequest)) [IamResponse](#iamresponse)
Iam returns information about caller authentication
### ConnectionsService
(synq.agent.dwh.v1.ConnectionsService)
ConnectionsService provides methods for managing data warehouse connections.
These connections represent data warehouse integrations configured in Coalesce Quality that can be used by:
* DWH Agent: For metadata extraction and data quality monitoring
* Coalesce Quality Scout: On-premise AI agent for data exploration and analysis
Both agents share the same or very similar configuration file format.
#### ListConnections
ListConnections ([ListConnectionsRequest](#listconnectionsrequest)) [ListConnectionsResponse](#listconnectionsresponse)
ListConnections retrieves data warehouse connections for a workspace.
Converts Coalesce Quality integration configurations to a standardized connection format.
Requires workspace context in the request metadata.
#### GenerateConnectionsYaml
GenerateConnectionsYaml ([GenerateConnectionsYamlRequest](#generateconnectionsyamlrequest)) [GenerateConnectionsYamlResponse](#generateconnectionsyamlresponse)
GenerateConnectionsYaml converts data warehouse connections to YAML configuration format.
The generated YAML can be used directly as a config file for DWH Agent or Coalesce Quality Scout.
Secret fields are replaced with environment variable placeholders (e.g., `${CONNECTION_ID_PASSWORD}`).
Documentation: [https://docs.synq.io/dw-integrations/agent#config-file-schema](https://docs.synq.io/dw-integrations/agent#config-file-schema)
### DwhAgentService
(synq.agent.dwh.v1.DwhAgentService)
#### Connect
Connect ([ConnectRequest](#connectrequest)) [ConnectResponse](#connectresponse)
buf:lint:ignore RPC\_NO\_CLIENT\_STREAMING
### YamlService
(synq.agent.recon.v1.YamlService)
YamlService provides stateless conversion between YAML config format and proto.
This is useful for UI editors that need to display/edit suite configs as YAML.
#### ParseYaml
ParseYaml ([ParseYamlRequest](#parseyamlrequest)) [ParseYamlResponse](#parseyamlresponse)
ParseYaml parses a YAML config string into a ReconciliationSuite proto.
Only the suite configuration fields are extracted (connections are ignored).
#### RenderYaml
RenderYaml ([RenderYamlRequest](#renderyamlrequest)) [RenderYamlResponse](#renderyamlresponse)
RenderYaml renders a ReconciliationSuite proto as a YAML config string.
### SuiteConfigService
(synq.agent.recon.v1.SuiteConfigService)
SuiteConfigService manages reconciliation suite configurations.
Managed suites are long-lived, optionally scheduled configs identified by suite\_name.
Ad-hoc suites are one-off configs that get a generated UUID as suite\_id.
#### UpsertSuiteConfig
UpsertSuiteConfig ([UpsertSuiteConfigRequest](#upsertsuiteconfigrequest)) [UpsertSuiteConfigResponse](#upsertsuiteconfigresponse)
Upsert a managed suite config. Creates if new, updates with new version if exists.
The suite\_id equals the suite name (from ReconciliationSuite.name).
Validates the ReconciliationSuite proto. Does NOT validate connections exist.
#### SubmitAdhocSuite
SubmitAdhocSuite ([SubmitAdhocSuiteRequest](#submitadhocsuiterequest)) [SubmitAdhocSuiteResponse](#submitadhocsuiteresponse)
Submit an ad-hoc suite for one-off execution.
Provide either an inline suite or a suite\_id referencing an existing managed suite.
Optionally apply environment overrides before execution.
The client-provided invocation\_id ensures idempotency.
#### GetSuiteConfig
GetSuiteConfig ([GetSuiteConfigRequest](#getsuiteconfigrequest)) [GetSuiteConfigResponse](#getsuiteconfigresponse)
Get the latest version of a suite config by suite\_id.
Works for both managed (suite\_id = suite\_name) and ad-hoc (suite\_id = UUID) configs.
#### ListSuiteConfigs
ListSuiteConfigs ([ListSuiteConfigsRequest](#listsuiteconfigsrequest)) [ListSuiteConfigsResponse](#listsuiteconfigsresponse)
List latest suite configs with filtering and pagination.
By default returns only managed suites. Set include\_adhoc to also include ad-hoc configs.
#### DeleteSuiteConfig
DeleteSuiteConfig ([DeleteSuiteConfigRequest](#deletesuiteconfigrequest)) [DeleteSuiteConfigResponse](#deletesuiteconfigresponse)
Delete a managed suite config (soft delete — inserts a deleted version).
#### ListSuiteConfigVersions
ListSuiteConfigVersions ([ListSuiteConfigVersionsRequest](#listsuiteconfigversionsrequest)) [ListSuiteConfigVersionsResponse](#listsuiteconfigversionsresponse)
Get version history for a suite config.
#### GetSuiteConfigVersion
GetSuiteConfigVersion ([GetSuiteConfigVersionRequest](#getsuiteconfigversionrequest)) [GetSuiteConfigVersionResponse](#getsuiteconfigversionresponse)
Get a specific historical version of a suite config.
### SuiteDeploymentService
(synq.agent.recon.v1.SuiteDeploymentService)
SuiteDeploymentService is the platform plane of reconciliation.
SuiteConfigService is the developer/authoring sandbox (edit, version, run
ad-hoc with your own credentials — preview-only, no Entity, no Run, no
Issue). A deployment is what SYNQ actually runs on the workspace's behalf:
a frozen snapshot of a suite config, mapped to workspace-level SYNQ
integrations, optionally scheduled or triggerable by API.
Identity: every deployment has a stable deployment\_id (UUIDv7) assigned on
first promote. It survives re-promotes, schedule/mapping changes, and
pause/resume. Downstream AssetCommand / RunCommand publication keys off
deployment\_id so Entity identity does not fragment on promote churn.
#### PromoteSuite
PromoteSuite ([PromoteSuiteRequest](#promotesuiterequest)) [PromoteSuiteResponse](#promotesuiteresponse)
Promote a suite config into production. Freezes a snapshot of the config
and stores the connection → integration mapping. Creates a new deployment
on first call; re-promotes the same suite\_id (reusing its deployment\_id)
on subsequent calls.
#### UnpromoteSuite
UnpromoteSuite ([UnpromoteSuiteRequest](#unpromotesuiterequest)) [UnpromoteSuiteResponse](#unpromotesuiteresponse)
Unpromote a deployment. Marks it inactive; scheduler and API triggers
stop. Deployment history is preserved; re-promoting the same suite\_id
reuses the original deployment\_id.
#### UpdateDeploymentSchedule
UpdateDeploymentSchedule ([UpdateDeploymentScheduleRequest](#updatedeploymentschedulerequest)) [UpdateDeploymentScheduleResponse](#updatedeploymentscheduleresponse)
Change schedule and/or triggerable\_by\_api on an existing deployment
without re-promoting the config snapshot or touching mappings.
#### UpdateDeploymentMappings
UpdateDeploymentMappings ([UpdateDeploymentMappingsRequest](#updatedeploymentmappingsrequest)) [UpdateDeploymentMappingsResponse](#updatedeploymentmappingsresponse)
Rewire connection → integration mappings on an existing deployment
without re-promoting the config snapshot.
#### UpdateDeploymentAnnotations
UpdateDeploymentAnnotations ([UpdateDeploymentAnnotationsRequest](#updatedeploymentannotationsrequest)) [UpdateDeploymentAnnotationsResponse](#updatedeploymentannotationsresponse)
Replace the deployment-level annotation overlay on an existing
deployment. Annotations are merged with suite-level and case-level
annotations from the frozen suite snapshot at promote/update time, then
surfaced on PromotedReconSuiteMetadata / PromotedReconCaseMetadata for
every asset under the deployment.
#### UpdateDeploymentCaseImpacts
UpdateDeploymentCaseImpacts ([UpdateDeploymentCaseImpactsRequest](#updatedeploymentcaseimpactsrequest)) [UpdateDeploymentCaseImpactsResponse](#updatedeploymentcaseimpactsresponse)
Patch the per-case ReconciliationFailureImpact map on an existing deployment
without re-promoting the suite snapshot. Useful for "apply to all"
FE actions and one-off toggles between RAISE\_ISSUE\_ON\_TABLES and
SHOW\_ON\_TABLES. Re-renders PromotedReconCaseMetadata so the
error\_tables / shown\_tables split reflects the new policy
immediately.
Merge semantics: keys present in the request overwrite the stored
value for that case. Keys absent from the request are left
untouched (no implicit reset). Sending RECONCILIATION\_FAILURE\_IMPACT\_UNSPECIFIED
clears the override for that case (falls back to the default
RAISE\_ISSUE\_ON\_TABLES). Unknown case names are rejected with
INVALID\_ARGUMENT so the FE catches typos before the deployment is
mutated.
#### PauseDeployment
PauseDeployment ([PauseDeploymentRequest](#pausedeploymentrequest)) [PauseDeploymentResponse](#pausedeploymentresponse)
Pause a deployment. Scheduled and API-triggered runs are suppressed until
`until` is reached, or indefinitely when `until` is absent.
#### ResumeDeployment
ResumeDeployment ([ResumeDeploymentRequest](#resumedeploymentrequest)) [ResumeDeploymentResponse](#resumedeploymentresponse)
Resume a paused deployment.
#### GetSuiteDeployment
GetSuiteDeployment ([GetSuiteDeploymentRequest](#getsuitedeploymentrequest)) [GetSuiteDeploymentResponse](#getsuitedeploymentresponse)
Fetch a deployment by suite\_id or deployment\_id.
#### ListSuiteDeployments
ListSuiteDeployments ([ListSuiteDeploymentsRequest](#listsuitedeploymentsrequest)) [ListSuiteDeploymentsResponse](#listsuitedeploymentsresponse)
List deployments for the caller's workspace. Filters support answering
"what is SYNQ running on behalf of this workspace?" and "which
deployments use this SYNQ integration?".
#### ListSuiteDeploymentHistory
ListSuiteDeploymentHistory ([ListSuiteDeploymentHistoryRequest](#listsuitedeploymenthistoryrequest)) [ListSuiteDeploymentHistoryResponse](#listsuitedeploymenthistoryresponse)
List the append-only history of a deployment (every promote,
re-promote, schedule/mapping change, pause/resume, unpromote).
#### TriggerDeployment
TriggerDeployment ([TriggerDeploymentRequest](#triggerdeploymentrequest)) [TriggerDeploymentResponse](#triggerdeploymentresponse)
Trigger an on-demand execution of a promoted deployment. Enqueues a run
using the frozen suite snapshot and connection mappings stored on the
deployment row — execution uses platform integration credentials, not the
caller's. Returns the freshly-allocated `run_id` so callers can poll
RunStateService for status.
Preconditions:
* Deployment must exist and be `active`.
* Deployment must have `triggerable_by_api = true` (FAILED\_PRECONDITION
otherwise).
* Deployment must not be paused (FAILED\_PRECONDITION when
`paused_until` is set and in the future).
### RunStateService
(synq.agent.recon.v1.RunStateService)
RunStateService exposes lifecycle status of reconciliation runs.
Polling-based read API — clients fetch the current state for one or more
suites and display progress. No notifications are emitted; clients re-poll
to observe transitions.
#### BatchReconciliationRunState
BatchReconciliationRunState ([BatchReconciliationRunStateRequest](#batchreconciliationrunstaterequest)) [BatchReconciliationRunStateResponse](#batchreconciliationrunstateresponse)
BatchReconciliationRunState returns the latest concluded run and any ongoing
(SCHEDULED or IN\_PROGRESS) run for each suite\_id. Returned map is keyed by suite\_id.
Suites with no recorded runs are omitted from the response map.
#### ListReconciliationRunState
ListReconciliationRunState ([ListReconciliationRunStateRequest](#listreconciliationrunstaterequest)) [ListReconciliationRunStateResponse](#listreconciliationrunstateresponse)
ListReconciliationRunState returns runs filtered by status and/or suite\_id.
Sorted newest-first by scheduled\_at.
#### CancelReconciliationRun
CancelReconciliationRun ([CancelReconciliationRunRequest](#cancelreconciliationrunrequest)) [CancelReconciliationRunResponse](#cancelreconciliationrunresponse)
CancelReconciliationRun marks a SCHEDULED or IN\_PROGRESS run as
CANCELLED so the suite is no longer "occupied" by a stuck occurrence
— used to recover from local-dev / executor outages where a run was
queued but never executed. Already-terminal runs are returned
unchanged. Idempotent: calling on an already-cancelled run is a
no-op.
Note: this only updates the run-state row. The corresponding
execution-job row is independent — when an executor eventually
wakes up to that job it will see the run is CANCELLED and skip.
### AuditLogService
(synq.agent.recon.v1.AuditLogService)
AuditLogService provides methods to ingest and query reconciliation audit logs.
#### IngestAuditLog
IngestAuditLog ([IngestAuditLogRequest](#ingestauditlogrequest)) [IngestAuditLogResponse](#ingestauditlogresponse)
IngestAuditLog stores a reconciliation run audit log.
Reporting a locally executed run is part of running one, so the scope that
authorises editing and running suites also authorises reporting their
results — a pipeline needs one credential, not two.
#### ListAuditLogs
ListAuditLogs ([ListAuditLogsRequest](#listauditlogsrequest)) [ListAuditLogsResponse](#listauditlogsresponse)
ListAuditLogs returns audit logs ordered from newest to oldest, optionally filtered by suite and time range.
#### GetAuditLog
GetAuditLog ([GetAuditLogRequest](#getauditlogrequest)) [GetAuditLogResponse](#getauditlogresponse)
GetAuditLog returns a single audit log by invocation ID.
### FeatureRequestService
(synq.agent.sre.v1.FeatureRequestService)
FeatureRequestService allows MCP clients to submit feature requests when users encounter
missing capabilities. This is a last-resort service — it should only be used when no
existing tool can fulfill the user's request.
#### SubmitFeatureRequest
SubmitFeatureRequest ([SubmitFeatureRequestRequest](#submitfeaturerequestrequest)) [SubmitFeatureRequestResponse](#submitfeaturerequestresponse)
SubmitFeatureRequest submits a feature request to the Coalesce Quality product team.
This method should only be called as a last resort when the user's request cannot be
fulfilled by any existing tool. It logs the request for product team review.
### SreAgentService
(synq.agent.sre.v1.SreAgentService)
#### Connect
Connect ([ConnectRequest](#connectrequest)) [ConnectResponse](#connectresponse)
buf:lint:ignore RPC\_NO\_CLIENT\_STREAMING
#### GetConfig
GetConfig ([GetConfigRequest](#getconfigrequest)) [GetConfigResponse](#getconfigresponse)
GetConfig returns the Scout configuration (system prompts + DWH connection
summary) for the caller's workspace. Authorized for the agent itself
(SCOPE\_SRE\_AGENT), for any caller with workspace integration-read access
(SCOPE\_INTEGRATION\_READ) so admins / owners can inspect the live prompts
via synqctl / fe-app without an agent token, and for MCP read tokens
(SCOPE\_MCP\_READ) — matches the sibling DWH ConnectionsService scope shape.
#### ListPromptSuggestions
ListPromptSuggestions ([ListPromptSuggestionsRequest](#listpromptsuggestionsrequest)) [ListPromptSuggestionsResponse](#listpromptsuggestionsresponse)
ListPromptSuggestions returns prompt-improvement suggestions recorded for the
caller's workspace. Default scope is pending suggestions only; set statuses to
include accepted / dismissed / superseded rows. Sorted newest first.
#### AcceptPromptSuggestion
AcceptPromptSuggestion ([AcceptPromptSuggestionRequest](#acceptpromptsuggestionrequest)) [AcceptPromptSuggestionResponse](#acceptpromptsuggestionresponse)
AcceptPromptSuggestion applies a pending suggestion to the matching SRE agent
prompt field. The applied value is `suggested_value` unless `edited_value` is set.
Returns FAILED\_PRECONDITION when the live prompt has drifted from the suggestion's
`baseline_value` since it was produced — the client should re-fetch and re-render.
#### DismissPromptSuggestion
DismissPromptSuggestion ([DismissPromptSuggestionRequest](#dismisspromptsuggestionrequest)) [DismissPromptSuggestionResponse](#dismisspromptsuggestionresponse)
DismissPromptSuggestion marks a pending suggestion as dismissed with an optional
free-text reason. The SRE agent configuration is left untouched.
#### RecordPromptSuggestion
RecordPromptSuggestion ([RecordPromptSuggestionRequest](#recordpromptsuggestionrequest)) [RecordPromptSuggestionResponse](#recordpromptsuggestionresponse)
RecordPromptSuggestion is the producer-side endpoint used by the offline
analyser to register a new suggestion for a workspace. The server snapshots
the current value of the targeted prompt field as `baseline_value`. Any
pending suggestion for the same `(workspace, field)` pair is marked as
superseded before the new row is inserted. Returns the recorded suggestion,
or an empty response when the baseline already matches `suggested_value`
(no-op).
Authorized for the agent / offline analyser (SCOPE\_SRE\_AGENT) and for
admins / owners with workspace integration-edit access
(SCOPE\_INTEGRATION\_EDIT), so an admin running synqctl can publish a
suggestion against a customer workspace via x-synq-workspace-override
without minting an agent token.
### TriageService
(synq.agent.sre.v1.TriageService)
Service for managing issue triage operations, allowing LLM agents to conclude investigations
and record evidence during the triage process.
#### Conclude
Conclude ([ConcludeRequest](#concluderequest)) [ConcludeResponse](#concluderesponse)
Concludes the triage investigation for one or more issues by providing a structured conclusion
and supporting evidence. This method is used by the LLM agent to finalize its investigation.
#### RecordEvidence
RecordEvidence ([RecordEvidenceRequest](#recordevidencerequest)) [RecordEvidenceResponse](#recordevidenceresponse)
Records evidence collected during the triage investigation. This method allows the LLM agent
to incrementally add evidence as it discovers information during the investigation process.
#### BatchLatestConclusions
BatchLatestConclusions ([BatchLatestConclusionsRequest](#batchlatestconclusionsrequest)) [BatchLatestConclusionsResponse](#batchlatestconclusionsresponse)
Retrieves the latest triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
#### BatchTriageState
BatchTriageState ([BatchTriageStateRequest](#batchtriagestaterequest)) [BatchTriageStateResponse](#batchtriagestateresponse)
Retrieves the triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
#### ListTriageState
ListTriageState ([ListTriageStateRequest](#listtriagestaterequest)) [ListTriageStateResponse](#listtriagestateresponse)
Retrieves the triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
#### MarkAsInProgress
MarkAsInProgress ([MarkAsInProgressRequest](#markasinprogressrequest)) [MarkAsInProgressResponse](#markasinprogressresponse)
Marks an issue as in progress. This method is used by the LLM agent to indicate that it has started working on an issue.
#### MarkFailed
MarkFailed ([MarkFailedRequest](#markfailedrequest)) [MarkFailedResponse](#markfailedresponse)
Marks an issue as failed triaging. This method is used by the LLM agent to indicate that it was unable to triage.
### TestsSuggestionStateService
(synq.agent.sre.v1.TestsSuggestionStateService)
#### SuggestFor
SuggestFor ([SuggestForRequest](#suggestforrequest)) [SuggestForResponse](#suggestforresponse)
#### GetActiveSuggestionStatesFor
GetActiveSuggestionStatesFor ([GetActiveSuggestionStatesForRequest](#getactivesuggestionstatesforrequest)) [GetActiveSuggestionStatesForResponse](#getactivesuggestionstatesforresponse)
#### BatchSuggestionStates
BatchSuggestionStates ([BatchSuggestionStatesRequest](#batchsuggestionstatesrequest)) [BatchSuggestionStatesResponse](#batchsuggestionstatesresponse)
#### ListSuggestionStates
ListSuggestionStates ([ListSuggestionStatesRequest](#listsuggestionstatesrequest)) [ListSuggestionStatesResponse](#listsuggestionstatesresponse)
#### MarkAsRunning
MarkAsRunning ([MarkAsRunningRequest](#markasrunningrequest)) [MarkAsRunningResponse](#markasrunningresponse)
#### MarkAsCompleted
MarkAsCompleted ([MarkAsCompletedRequest](#markascompletedrequest)) [MarkAsCompletedResponse](#markascompletedresponse)
#### MarkAsFailed
MarkAsFailed ([MarkAsFailedRequest](#markasfailedrequest)) [MarkAsFailedResponse](#markasfailedresponse)
#### MarkAsCancelled
MarkAsCancelled ([MarkAsCancelledRequest](#markascancelledrequest)) [MarkAsCancelledResponse](#markascancelledresponse)
### LlmService
(synq.agent.sre.v1.LlmService)
Service for evaluating LLM requests and producing structured output.
#### Evaluate
Evaluate ([EvaluateRequest](#evaluaterequest)) [EvaluateResponse](#evaluateresponse)
Evaluates an LLM request with a structured output schema and message history.
The main prompt should be constant as it will be cached for efficiency.
### QueriesService
(synq.queries.v1.QueriesService)
QueriesService compiles and evaluates ResolverQL — the compact text query
language used across Coalesce Quality to select entities — over the public
API.
ResolverQL is a string DSL (for example `with_type("TABLE")` or
`in_folder(...)`); a structured `synq.queries.v1.Query` is its parsed,
machine-readable form. This service is the bridge between the two and the
read-only execution surface for both:
* `TranslateResolverQl` compiles a ResolverQL expression into a structured
`Query` without evaluating it — inspect it, validate it, or reuse it as a
filter on another API (entity listing, folder browsing, ...).
* `ResolveQuery` compiles a ResolverQL expression (or takes an
already-structured `Query`), evaluates it against the catalog, and
returns the matched entity ids. This is the general author -> resolve
loop.
#### TranslateResolverQl
TranslateResolverQl ([TranslateResolverQlRequest](#translateresolverqlrequest)) [TranslateResolverQlResponse](#translateresolverqlresponse)
Compile a ResolverQL expression into a structured public `Query`. Unlike
`ResolveQuery`, it does not evaluate the query against the catalog. A
syntactically invalid or uncompilable expression fails with
INVALID\_ARGUMENT.
#### ResolveQuery
ResolveQuery ([ResolveQueryRequest](#resolvequeryrequest)) [ResolveQueryResponse](#resolvequeryresponse)
Evaluate a selection and return the matched entity ids, paginated. Pass a
ResolverQL expression via `resolver_ql` (it is compiled server-side) or an
already-structured `query`. Invalid ResolverQL fails with INVALID\_ARGUMENT.
### NLQueryService
(synq.queries.v1.NLQueryService)
NLQueryService generates structured Query protos from natural language descriptions using an LLM.
#### GenerateQuery
GenerateQuery ([GenerateQueryRequest](#generatequeryrequest)) [GenerateQueryResponse](#generatequeryresponse)
GenerateQuery generates a Query from a natural language description.
### DomainsService
(synq.domains.v1.DomainsService)
DomainsService can be used to manage domains.
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Create or update a domain.
#### BatchGet
BatchGet ([BatchGetRequest](#batchgetrequest)) [BatchGetResponse](#batchgetresponse)
Get multiple domains by their identifiers.
#### FetchDomainWithSubDomains
FetchDomainWithSubDomains ([FetchDomainWithSubDomainsRequest](#fetchdomainwithsubdomainsrequest)) [FetchDomainWithSubDomainsResponse](#fetchdomainwithsubdomainsresponse)
Get a domain with its sub-domains
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
List all the domains in the current workspace.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete a domain by its identifier.
#### SetDefinition
SetDefinition ([SetDefinitionRequest](#setdefinitionrequest)) [SetDefinitionResponse](#setdefinitionresponse)
Set the definition for an existing domain.
#### UpsertDefinitionPart
UpsertDefinitionPart ([UpsertDefinitionPartRequest](#upsertdefinitionpartrequest)) [UpsertDefinitionPartResponse](#upsertdefinitionpartresponse)
Upsert definition part to the definition of an existing domain.
#### RemoveDefinitionPart
RemoveDefinitionPart ([RemoveDefinitionPartRequest](#removedefinitionpartrequest)) [RemoveDefinitionPartResponse](#removedefinitionpartresponse)
Remove definition part from the definition of an existing domain.
#### GetUsage
GetUsage ([GetUsageRequest](#getusagerequest)) [GetUsageResponse](#getusageresponse)
### DomainMembersService
(synq.domains.members.v1.DomainMembersService)
DomainMembersService can be used to manage domain memberships.
#### AddDomainMembers
AddDomainMembers ([AddDomainMembersRequest](#adddomainmembersrequest)) [AddDomainMembersResponse](#adddomainmembersresponse)
Add domain members.
#### RemoveDomainMembers
RemoveDomainMembers ([RemoveDomainMembersRequest](#removedomainmembersrequest)) [RemoveDomainMembersResponse](#removedomainmembersresponse)
Remove domain members.
#### ListDomainMembers
ListDomainMembers ([ListDomainMembersRequest](#listdomainmembersrequest)) [ListDomainMembersResponse](#listdomainmembersresponse)
List domain members.
#### ListUserDomains
ListUserDomains ([ListUserDomainsRequest](#listuserdomainsrequest)) [ListUserDomainsResponse](#listuserdomainsresponse)
List domains for the given user.
#### SetDefaultUserDomain
SetDefaultUserDomain ([SetDefaultUserDomainRequest](#setdefaultuserdomainrequest)) [SetDefaultUserDomainResponse](#setdefaultuserdomainresponse)
Set default domain for user.
### DomainsService
(synq.domains.v2.DomainsService)
DomainsService manages data domains — named areas of ownership that group the
assets, data products and sub-domains belonging to one part of the business.
Ids are opaque UUIDs supplied by the caller, which makes writes idempotent
(a retried create converges instead of duplicating). Mutable fields are
optional on Upsert: a field that is set is written, a field that is omitted is
left unchanged. Pass the `etag` you last read to guard against overwriting a
concurrent edit.
A domain may contain other domains and data products, so membership resolution
is recursive. Every write that adds such a reference — including a change of
`parent_id` — is rejected if it would close a loop, so a definition can always
be resolved in finite time.
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Create or update a domain. The id is supplied by the caller (a UUID);
repeating the same request converges to the same domain. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
#### BatchGet
BatchGet ([BatchGetRequest](#batchgetrequest)) [BatchGetResponse](#batchgetresponse)
Fetch multiple domains by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
List the domains in the workspace, paginated. Narrow to one level of the
hierarchy with `parent_id`.
#### FetchDomainWithSubDomains
FetchDomainWithSubDomains ([FetchDomainWithSubDomainsRequest](#fetchdomainwithsubdomainsrequest)) [FetchDomainWithSubDomainsResponse](#fetchdomainwithsubdomainsresponse)
Fetch a domain together with its direct sub-domains, keyed by id.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete a domain. Idempotent — deleting an already-deleted or unknown domain
succeeds. Soft-deletes by default; set `purge` to hard-delete and release the
id, which is refused while the domain still has sub-domains. Pass `etag` to
guard against deleting a concurrently-edited domain.
#### SetDefinition
SetDefinition ([SetDefinitionRequest](#setdefinitionrequest)) [SetDefinitionResponse](#setdefinitionresponse)
Replace the entire membership definition of a domain.
#### UpsertDefinitionPart
UpsertDefinitionPart ([UpsertDefinitionPartRequest](#upsertdefinitionpartrequest)) [UpsertDefinitionPartResponse](#upsertdefinitionpartresponse)
Add or replace a single definition part (matched by its part id).
#### RemoveDefinitionPart
RemoveDefinitionPart ([RemoveDefinitionPartRequest](#removedefinitionpartrequest)) [RemoveDefinitionPartResponse](#removedefinitionpartresponse)
Remove a single definition part by its part id. Idempotent.
#### ListMembers
ListMembers ([ListMembersRequest](#listmembersrequest)) [ListMembersResponse](#listmembersresponse)
List the assets that currently belong to a domain, resolved from its
definition — including everything contributed by the data products and
domains it references, and by its own sub-domains — and returned as opaque
entity ids. Paginated.
#### GetUsage
GetUsage ([GetUsageRequest](#getusagerequest)) [GetUsageResponse](#getusageresponse)
Report how many domains the workspace uses, split into top-level domains and
sub-domains.
### AlertsService
(synq.alerts.services.v1.AlertsService)
AlertsService provides operations for managing alert configurations.
#### Create
Create ([CreateRequest](#createrequest)) [CreateResponse](#createresponse)
Create a new alert configuration.
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
Retrieves a list of alert configurations based on filters.
#### BatchGet
BatchGet ([BatchGetRequest](#batchgetrequest)) [BatchGetResponse](#batchgetresponse)
Get multiple alert configurations by their identifiers.
#### Update
Update ([UpdateRequest](#updaterequest)) [UpdateResponse](#updateresponse)
Update an existing alert configuration.
The config can be identified by either ID or FQN.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete an existing alert configuration.
The config can be identified by either ID or FQN.
#### ToggleEnabled
ToggleEnabled ([ToggleEnabledRequest](#toggleenabledrequest)) [ToggleEnabledResponse](#toggleenabledresponse)
Enables or disables an existing alert configuration.
The config can be identified by either ID or FQN.
### PlatformsService
(synq.platforms.v1.PlatformsService)
PlatformsService is a service for managing Platforms and Integrations.
#### SetPlatformAuthentication
SetPlatformAuthentication ([SetPlatformAuthenticationRequest](#setplatformauthenticationrequest)) [SetPlatformAuthenticationResponse](#setplatformauthenticationresponse)
### DataproductsService
(synq.dataproducts.v1.DataproductsService)
DataproductsService can be used to manage data products.
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Create or update a dataproduct.
#### Get
Get ([GetRequest](#getrequest)) [GetResponse](#getresponse)
Get multiple dataproducts by their identifiers.
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
List all the dataproducts in the current scope.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete a dataproduct by its identifier.
Soft deletes by default. Optionally purge the dataproduct to release the identifier.
#### SetDefinition
SetDefinition ([SetDefinitionRequest](#setdefinitionrequest)) [SetDefinitionResponse](#setdefinitionresponse)
Set the definition for an existing dataproduct.
#### UpsertDefinitionPart
UpsertDefinitionPart ([UpsertDefinitionPartRequest](#upsertdefinitionpartrequest)) [UpsertDefinitionPartResponse](#upsertdefinitionpartresponse)
Upsert definition part to the definition of an existing dataproduct.
#### RemoveDefinitionPart
RemoveDefinitionPart ([RemoveDefinitionPartRequest](#removedefinitionpartrequest)) [RemoveDefinitionPartResponse](#removedefinitionpartresponse)
Remove definition part from the definition of an existing dataproduct.
### DataproductsService
(synq.dataproducts.v2.DataproductsService)
DataproductsService manages data products — named, owned groupings of data
assets with a membership definition, a priority and an optional folder.
Ids are opaque UUIDs supplied by the caller, which makes writes idempotent
(a retried create converges instead of duplicating). Mutable fields are
optional on Upsert: a field that is set is written, a field that is omitted is
left unchanged. Pass the `etag` you last read to guard against overwriting a
concurrent edit.
A data product is a leaf in the reference graph — its definition may not
reference another data product or domain — so membership resolution always
terminates.
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Create or update a data product. The id is supplied by the caller (a UUID);
repeating the same request converges to the same product. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
#### BatchGet
BatchGet ([BatchGetRequest](#batchgetrequest)) [BatchGetResponse](#batchgetresponse)
Fetch multiple data products by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
List the data products in the workspace, paginated. Narrow with `folder`
and `priorities`.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete a data product. Idempotent — deleting an already-deleted or unknown
product succeeds. Soft-deletes by default; set `purge` to hard-delete and
release the id. Pass `etag` to guard against deleting a concurrently-edited
product.
#### SetDefinition
SetDefinition ([SetDefinitionRequest](#setdefinitionrequest)) [SetDefinitionResponse](#setdefinitionresponse)
Replace the entire membership definition of a data product.
#### UpsertDefinitionPart
UpsertDefinitionPart ([UpsertDefinitionPartRequest](#upsertdefinitionpartrequest)) [UpsertDefinitionPartResponse](#upsertdefinitionpartresponse)
Add or replace a single definition part (matched by its part id).
#### RemoveDefinitionPart
RemoveDefinitionPart ([RemoveDefinitionPartRequest](#removedefinitionpartrequest)) [RemoveDefinitionPartResponse](#removedefinitionpartresponse)
Remove a single definition part by its part id. Idempotent.
#### ListMembers
ListMembers ([ListMembersRequest](#listmembersrequest)) [ListMembersResponse](#listmembersresponse)
List the assets that currently belong to a data product, resolved from its
definition and returned as opaque entity ids. Paginated.
### OwnersService
(synq.owners.v1.OwnersService)
OwnersService manages owners and their ownerships — the "alert routing as
code" surface. An owner is a named responsible party with notification
channels (contacts); an ownership assigns a set of assets to an owner and
configures the alerts routed to it. Owner is the resource, ownership its
sub-resource: an ownership is meaningless without its owner, and deleting an
owner deletes its ownerships.
Ids are opaque UUIDs supplied by the caller, which makes writes idempotent (a
retried create converges instead of duplicating). Mutable fields are optional
on the Upsert calls: a set field is written, an omitted field is left
unchanged. Pass the `etag` you last read to guard against overwriting a
concurrent edit.
Related: `synq.dataproducts.v2.DataproductsService` (an ownership can own a
whole data product), `synq.alerts.v1.AlertsService` (how the configured alerts
are reported), and `synq.users.v1.UsersService` (resolve the users behind
`UserContact` and Slack/Teams mentions).
#### UpsertOwner
UpsertOwner ([UpsertOwnerRequest](#upsertownerrequest)) [UpsertOwnerResponse](#upsertownerresponse)
Create or update an owner. The id is supplied by the caller (a UUID);
repeating the same request converges to the same owner. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
#### BatchGetOwners
BatchGetOwners ([BatchGetOwnersRequest](#batchgetownersrequest)) [BatchGetOwnersResponse](#batchgetownersresponse)
Fetch multiple owners by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
#### ListOwners
ListOwners ([ListOwnersRequest](#listownersrequest)) [ListOwnersResponse](#listownersresponse)
List the owners in the workspace, paginated.
#### DeleteOwner
DeleteOwner ([DeleteOwnerRequest](#deleteownerrequest)) [DeleteOwnerResponse](#deleteownerresponse)
Delete an owner and all of its ownerships. Idempotent — deleting an
already-deleted or unknown owner succeeds. Soft-deletes by default; set
`purge` to hard-delete and release the id. Pass `etag` to guard against
deleting a concurrently-edited owner.
#### UpsertOwnership
UpsertOwnership ([UpsertOwnershipRequest](#upsertownershiprequest)) [UpsertOwnershipResponse](#upsertownershipresponse)
Create or update an ownership under an owner. The ownership id is supplied
by the caller (a UUID). Assigning a data product that is already owned by a
different ownership moves it (the previous ownership of that product is
removed), matching the app.
#### ListOwnerships
ListOwnerships ([ListOwnershipsRequest](#listownershipsrequest)) [ListOwnershipsResponse](#listownershipsresponse)
List the ownerships of an owner, paginated.
#### BatchGetOwnerships
BatchGetOwnerships ([BatchGetOwnershipsRequest](#batchgetownershipsrequest)) [BatchGetOwnershipsResponse](#batchgetownershipsresponse)
Fetch multiple ownerships by id (across owners). Ids that do not exist (or,
unless `include_deleted` is set, are deleted) are omitted.
#### DeleteOwnership
DeleteOwnership ([DeleteOwnershipRequest](#deleteownershiprequest)) [DeleteOwnershipResponse](#deleteownershipresponse)
Delete an ownership by id. Idempotent — deleting an already-deleted or
unknown ownership succeeds. Pass `etag` to guard against deleting a
concurrently-edited ownership.
### UsersService
(synq.users.v1.UsersService)
#### ListUsers
ListUsers ([ListUsersRequest](#listusersrequest)) [ListUsersResponse](#listusersresponse)
#### BatchGetUsers
BatchGetUsers ([BatchGetUsersRequest](#batchgetusersrequest)) [BatchGetUsersResponse](#batchgetusersresponse)
#### GetByAlias
GetByAlias ([GetByAliasRequest](#getbyaliasrequest)) [GetByAliasResponse](#getbyaliasresponse)
#### GetByEmail
GetByEmail ([GetByEmailRequest](#getbyemailrequest)) [GetByEmailResponse](#getbyemailresponse)
#### UpsertUserAliases
UpsertUserAliases ([UpsertUserAliasesRequest](#upsertuseraliasesrequest)) [UpsertUserAliasesResponse](#upsertuseraliasesresponse)
#### DeleteUserAliases
DeleteUserAliases ([DeleteUserAliasesRequest](#deleteuseraliasesrequest)) [DeleteUserAliasesResponse](#deleteuseraliasesresponse)
#### GetUserAliases
GetUserAliases ([GetUserAliasesRequest](#getuseraliasesrequest)) [GetUserAliasesResponse](#getuseraliasesresponse)
#### GetUserIdentities
GetUserIdentities ([GetUserIdentitiesRequest](#getuseridentitiesrequest)) [GetUserIdentitiesResponse](#getuseridentitiesresponse)
Returns all canonical identity strings for a user.
If user\_id is omitted, returns identities for the currently authenticated user.
These identity strings can be passed to ListIssues(interacted\_by\_identities)
to filter issues the user has interacted with.
Format: "synq:\", "email:\", "slack:\", "msteams:\", etc.
### AtlanWorkflowService
(synq.extensions.atlan.workflows.v1.AtlanWorkflowService)
#### SetConnectionMappings
SetConnectionMappings ([SetConnectionMappingsRequest](#setconnectionmappingsrequest)) [SetConnectionMappingsResponse](#setconnectionmappingsresponse)
#### RemoveConnectionMappings
RemoveConnectionMappings ([RemoveConnectionMappingsRequest](#removeconnectionmappingsrequest)) [RemoveConnectionMappingsResponse](#removeconnectionmappingsresponse)
#### GetConnectionMappings
GetConnectionMappings ([GetConnectionMappingsRequest](#getconnectionmappingsrequest)) [GetConnectionMappingsResponse](#getconnectionmappingsresponse)
#### GetProductMappings
GetProductMappings ([GetProductMappingsRequest](#getproductmappingsrequest)) [GetProductMappingsResponse](#getproductmappingsresponse)
#### GetDomainMappings
GetDomainMappings ([GetDomainMappingsRequest](#getdomainmappingsrequest)) [GetDomainMappingsResponse](#getdomainmappingsresponse)
#### Synchronize
Synchronize ([SynchronizeRequest](#synchronizerequest)) [SynchronizeResponse](#synchronizeresponse)
Run a synchronization job for the integration.
#### FetchRuns
FetchRuns ([FetchRunsRequest](#fetchrunsrequest)) [FetchRunsResponse](#fetchrunsresponse)
#### SetMappingToggles
SetMappingToggles ([SetMappingTogglesRequest](#setmappingtogglesrequest)) [SetMappingTogglesResponse](#setmappingtogglesresponse)
#### GetMappingToggles
GetMappingToggles ([GetMappingTogglesRequest](#getmappingtogglesrequest)) [GetMappingTogglesResponse](#getmappingtogglesresponse)
### AtlanProviderService
(synq.extensions.atlan.provider.v1.AtlanProviderService)
#### GetAtlanConnections
GetAtlanConnections ([GetAtlanConnectionsRequest](#getatlanconnectionsrequest)) [GetAtlanConnectionsResponse](#getatlanconnectionsresponse)
#### GetAtlanDataProducts
GetAtlanDataProducts ([GetAtlanDataProductsRequest](#getatlandataproductsrequest)) [GetAtlanDataProductsResponse](#getatlandataproductsresponse)
#### GetAtlanDomains
GetAtlanDomains ([GetAtlanDomainsRequest](#getatlandomainsrequest)) [GetAtlanDomainsResponse](#getatlandomainsresponse)
### AtlanIntegrationService
(synq.extensions.atlan.integrations.v1.AtlanIntegrationService)
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Upserts an integration and validates it by checking if the provided API URL and token are valid.
#### Ping
Ping ([PingRequest](#pingrequest)) [PingResponse](#pingresponse)
Pings Atlan with the given connection credentials.
#### Get
Get ([GetRequest](#getrequest)) [GetResponse](#getresponse)
#### Remove
Remove ([RemoveRequest](#removerequest)) [RemoveResponse](#removeresponse)
#### Activate
Activate ([ActivateRequest](#activaterequest)) [ActivateResponse](#activateresponse)
Activate or deactivate the integration.
### CommitsService
(synq.git.commits.v1.CommitsService)
#### GetDiffByChangeId
GetDiffByChangeId ([GetDiffByChangeIdRequest](#getdiffbychangeidrequest)) [GetDiffByChangeIdResponse](#getdiffbychangeidresponse)
#### GetDiffByCommit
GetDiffByCommit ([GetDiffByCommitRequest](#getdiffbycommitrequest)) [GetDiffByCommitResponse](#getdiffbycommitresponse)
### CloudwatchService
(synq.ingest.cloudwatch.v1.CloudwatchService)
#### IngestCloudwatchLogsData
IngestCloudwatchLogsData ([IngestCloudwatchLogsDataRequest](#ingestcloudwatchlogsdatarequest)) [IngestCloudwatchLogsDataResponse](#ingestcloudwatchlogsdataresponse)
### DwhService
(synq.ingest.dwh.v1.DwhService)
#### IngestObjectInformation
IngestObjectInformation ([IngestObjectInformationRequest](#ingestobjectinformationrequest)) [IngestObjectInformationResponse](#ingestobjectinformationresponse)
#### IngestSqlDefinitions
IngestSqlDefinitions ([IngestSqlDefinitionsRequest](#ingestsqldefinitionsrequest)) [IngestSqlDefinitionsResponse](#ingestsqldefinitionsresponse)
#### IngestSchemas
IngestSchemas ([IngestSchemasRequest](#ingestschemasrequest)) [IngestSchemasResponse](#ingestschemasresponse)
#### IngestObjectMetrics
IngestObjectMetrics ([IngestObjectMetricsRequest](#ingestobjectmetricsrequest)) [IngestObjectMetricsResponse](#ingestobjectmetricsresponse)
#### IngestTaskResults
IngestTaskResults ([IngestTaskResultsRequest](#ingesttaskresultsrequest)) [IngestTaskResultsResponse](#ingesttaskresultsresponse)
#### IngestQueryLogs
IngestQueryLogs ([IngestQueryLogsRequest](#ingestquerylogsrequest)) [IngestQueryLogsResponse](#ingestquerylogsresponse)
#### IngestTableConstraints
IngestTableConstraints ([IngestTableConstraintsRequest](#ingesttableconstraintsrequest)) [IngestTableConstraintsResponse](#ingesttableconstraintsresponse)
#### IngestLineage
IngestLineage ([IngestLineageRequest](#ingestlineagerequest)) [IngestLineageResponse](#ingestlineageresponse)
IngestLineage pushes data-flow lineage between warehouse objects (and,
optionally, between their columns) into the platform. Send the lineage you
extract from the warehouse — for example from Snowflake's GET\_LINEAGE — as a
batch of directed edges. Use `replace_mode` to choose between an
incremental update (MERGE) and an authoritative refresh of a region of the
warehouse (REPLACE\_SCOPE); REPLACE\_SCOPE is what lets the platform expire
edges that no longer exist. Safe to retry: re-sending the same batch
converges to the same state.
### AirflowLogsService
(synq.ingest.airflow\.v1.AirflowLogsService)
#### IngestLog
IngestLog ([IngestLogRequest](#ingestlogrequest)) [IngestLogResponse](#ingestlogresponse)
#### IngestDatahubAspects
IngestDatahubAspects ([IngestDatahubAspectsRequest](#ingestdatahubaspectsrequest)) [IngestDatahubAspectsResponse](#ingestdatahubaspectsresponse)
### OpenlineageService
(synq.ingest.openlineage.v1.OpenlineageService)
#### Ingest
Ingest ([IngestRequest](#ingestrequest)) [IngestResponse](#ingestresponse)
### DbtService
(synq.ingest.dbt.v1.DbtService)
#### IngestInvocation
IngestInvocation ([IngestInvocationRequest](#ingestinvocationrequest)) [IngestInvocationResponse](#ingestinvocationresponse)
### SqlMeshService
(synq.ingest.sqlmesh.v1.SqlMeshService)
#### IngestMetadata
IngestMetadata ([IngestMetadataRequest](#ingestmetadatarequest)) [IngestMetadataResponse](#ingestmetadataresponse)
#### IngestExecution
IngestExecution ([IngestExecutionRequest](#ingestexecutionrequest)) [IngestExecutionResponse](#ingestexecutionresponse)
### ScheduleService
(synq.schedule.v1.ScheduleService)
ScheduleService provides schedule evaluation utilities.
#### PreviewSchedules
PreviewSchedules ([PreviewSchedulesRequest](#previewschedulesrequest)) [PreviewSchedulesResponse](#previewschedulesresponse)
PreviewSchedules returns the next occurrences for one or more schedule expressions.
Never fails at the RPC level; per-schedule errors are returned in the response items.
Response items match request items by index.
### SavedViewsService
(synq.savedviews.v1.SavedViewsService)
SavedViewsService manages saved views — named, reusable selections over your
entities (and other surfaces) with display configuration, sharing and
per-user pinning.
A saved view is owned by the user who created it. It can be kept private,
shared with the whole workspace, or granted to specific users. Reads return,
for the calling user, how each view relates to them (mine / shared / granted)
and what they are allowed to do with it. Workspace administrators can manage
any view in the workspace.
#### Upsert
Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse)
Create or update a saved view.
The view id is supplied by the caller (a UUID), which makes this operation
idempotent — repeating the same request converges to the same view rather
than creating a duplicate. Mutable fields are optional: a field that is set
is written, a field that is omitted is left unchanged. To guard against
overwriting a concurrent edit, pass the `etag` you last read.
#### Delete
Delete ([DeleteRequest](#deleterequest)) [DeleteResponse](#deleteresponse)
Delete a saved view. Idempotent — deleting an already-deleted or unknown
view succeeds. Pass `etag` to guard against deleting a concurrently-edited
view.
#### BatchGet
BatchGet ([BatchGetRequest](#batchgetrequest)) [BatchGetResponse](#batchgetresponse)
Fetch multiple saved views by id. Ids the caller cannot see, or that do not
exist, are omitted from the response rather than causing an error.
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
List the saved views the calling user can see. By default returns every
visible view (their own, workspace-owned, shared-with-workspace and
granted-to-them); narrow with `scopes`, `context` and `only_pinned`.
#### SetPin
SetPin ([SetPinRequest](#setpinrequest)) [SetPinResponse](#setpinresponse)
Pin or unpin a saved view to the calling user's main screen. Pinning is a
per-user preference: it applies only to the caller and does not modify the
view or its version, so any user who can see a view may pin it.
### TriggerService
(synq.datachecks.v1.TriggerService)
TriggerService provides synchronous execution of datachecks on entities.
#### TriggerDatachecks
TriggerDatachecks ([TriggerDatachecksRequest](#triggerdatachecksrequest)) [TriggerDatachecksResponse](#triggerdatachecksresponse)
TriggerDatachecks executes datachecks for the specified entities.
### SqlTestsService
(synq.datachecks.sqltests.v1.SqlTestsService)
SqlTestsService is a service for managing SqlTests.
#### BatchUpsertSqlTests
BatchUpsertSqlTests ([BatchUpsertSqlTestsRequest](#batchupsertsqltestsrequest)) [BatchUpsertSqlTestsResponse](#batchupsertsqltestsresponse)
Upsert SqlTests based on a unique ID.
#### ListSqlTests
ListSqlTests ([ListSqlTestsRequest](#listsqltestsrequest)) [ListSqlTestsResponse](#listsqltestsresponse)
List SqlTests for given annotations.
#### BatchGetSqlTests
BatchGetSqlTests ([BatchGetSqlTestsRequest](#batchgetsqltestsrequest)) [BatchGetSqlTestsResponse](#batchgetsqltestsresponse)
Get SqlTests by their IDs.
#### BatchDeleteSqlTests
BatchDeleteSqlTests ([BatchDeleteSqlTestsRequest](#batchdeletesqltestsrequest)) [BatchDeleteSqlTestsResponse](#batchdeletesqltestsresponse)
Delete SqlTests by their IDs.
#### GetSqlTestAudit
GetSqlTestAudit ([GetSqlTestAuditRequest](#getsqltestauditrequest)) [GetSqlTestAuditResponse](#getsqltestauditresponse)
Get SqlTest audit from a given execution ID in jwt token.
### TestSuggestionsService
(synq.datachecks.testsuggestions.v1.TestSuggestionsService)
#### BatchCreateTestSuggestions
BatchCreateTestSuggestions ([BatchCreateTestSuggestionsRequest](#batchcreatetestsuggestionsrequest)) [BatchCreateTestSuggestionsResponse](#batchcreatetestsuggestionsresponse)
#### BatchGetTestSuggestionsForEntities
BatchGetTestSuggestionsForEntities ([BatchGetTestSuggestionsForEntitiesRequest](#batchgettestsuggestionsforentitiesrequest)) [BatchGetTestSuggestionsForEntitiesResponse](#batchgettestsuggestionsforentitiesresponse)
#### BatchAcceptTestSuggestions
BatchAcceptTestSuggestions ([BatchAcceptTestSuggestionsRequest](#batchaccepttestsuggestionsrequest)) [BatchAcceptTestSuggestionsResponse](#batchaccepttestsuggestionsresponse)
#### BatchRejectTestSuggestions
BatchRejectTestSuggestions ([BatchRejectTestSuggestionsRequest](#batchrejecttestsuggestionsrequest)) [BatchRejectTestSuggestionsResponse](#batchrejecttestsuggestionsresponse)
### IntegrationsService
(synq.integrations.v1.IntegrationsService)
IntegrationsService manages connections from Coalesce Quality to your data
systems (warehouses, databases, and transformation tools).
Concurrency: every integration carries an opaque `etag`. Read it from
`GetIntegration` / `ListIntegrations`, then pass it back on
`UpdateIntegration` / `DeleteIntegration` to ensure you modify the version you
last saw. A stale etag is rejected with ABORTED (HTTP 409). Omit
the etag for last-write-wins.
Quota: each workspace has a limit on the number of integrations. Creating
beyond the limit is rejected with RESOURCE\_EXHAUSTED.
Secrets: credential fields (passwords, tokens, keys) are write-only. They are
masked (returned empty) on every read. On update, omit a secret to keep it,
send a new value to rotate it, or send an explicit empty string to clear it
(where the field is `optional`).
#### CreateIntegration
CreateIntegration ([CreateIntegrationRequest](#createintegrationrequest)) [CreateIntegrationResponse](#createintegrationresponse)
Create a new integration. The server assigns the id and returns the created
integration including any generated outputs.
The integration type is fixed by the populated `config` variant and cannot
be changed later. Counts against the per-workspace quota.
Not safe to blindly retry: the server mints a new id on each call, so a
retried create produces a second integration. On a transport error, list /
look up before retrying.
#### GetIntegration
GetIntegration ([GetIntegrationRequest](#getintegrationrequest)) [GetIntegrationResponse](#getintegrationresponse)
Fetch a single integration by id. Secret config fields are masked.
#### ListIntegrations
ListIntegrations ([ListIntegrationsRequest](#listintegrationsrequest)) [ListIntegrationsResponse](#listintegrationsresponse)
List all integrations in the workspace (optionally filtered by enabled
state). Secret config fields are masked. The full set is returned in one
response — a workspace has only a handful of integrations.
#### BatchGetIntegrations
BatchGetIntegrations ([BatchGetIntegrationsRequest](#batchgetintegrationsrequest)) [BatchGetIntegrationsResponse](#batchgetintegrationsresponse)
Fetch multiple integrations by id in one call. Ids not found (or not in the
workspace) are omitted from the response rather than erroring.
#### UpdateIntegration
UpdateIntegration ([UpdateIntegrationRequest](#updateintegrationrequest)) [UpdateIntegrationResponse](#updateintegrationresponse)
Update an integration. The `config` is replaced wholesale — send the
complete desired config (omitted secrets are preserved; see the
service-level secret semantics). `title` is patch-style: omit it to leave
it unchanged.
The `config` variant must match the existing integration's type; changing
the type is rejected with FAILED\_PRECONDITION.
Safe to retry: addresses an existing id and converges to the same state.
With an `etag` set, a retry after success returns ABORTED
(the version moved) — treat that as "already applied".
#### DeleteIntegration
DeleteIntegration ([DeleteIntegrationRequest](#deleteintegrationrequest)) [DeleteIntegrationResponse](#deleteintegrationresponse)
Delete an integration. The integration stops being scheduled and is removed
from listings. Safe to retry (deleting an already-deleted id is a no-op).
#### EnableIntegration
EnableIntegration ([EnableIntegrationRequest](#enableintegrationrequest)) [EnableIntegrationResponse](#enableintegrationresponse)
Enable a previously disabled integration. No-op if already enabled.
#### DisableIntegration
DisableIntegration ([DisableIntegrationRequest](#disableintegrationrequest)) [DisableIntegrationResponse](#disableintegrationresponse)
Disable an integration without deleting it. The configuration is kept but
the integration is no longer scheduled or refreshed. No-op if already
disabled.
#### RefreshIntegration
RefreshIntegration ([RefreshIntegrationRequest](#refreshintegrationrequest)) [RefreshIntegrationResponse](#refreshintegrationresponse)
Trigger an immediate, ad-hoc refresh of an integration. Available only for
types whose `Capabilities.can_refresh` is true; otherwise rejected with
FAILED\_PRECONDITION.
Not idempotent: each call enqueues a new refresh.
#### GetIntegrationHealth
GetIntegrationHealth ([GetIntegrationHealthRequest](#getintegrationhealthrequest)) [GetIntegrationHealthResponse](#getintegrationhealthresponse)
Return current health plus a paginated history of recent runs for an
integration. When pagination is omitted, a bounded recent window is
returned (the most recent runs from the last 7 days).
### IssuesService
(synq.issues.v2.IssuesService)
IssuesService is a service for managing Issues.
#### BatchGetIssues
BatchGetIssues ([BatchGetIssuesRequest](#batchgetissuesrequest)) [BatchGetIssuesResponse](#batchgetissuesresponse)
#### ListIssues
ListIssues ([ListIssuesRequest](#listissuesrequest)) [ListIssuesResponse](#listissuesresponse)
#### MarkInvestigating
MarkInvestigating ([MarkInvestigatingRequest](#markinvestigatingrequest)) [MarkInvestigatingResponse](#markinvestigatingresponse)
Mark issue as being investigated.
#### MarkFixed
MarkFixed ([MarkFixedRequest](#markfixedrequest)) [MarkFixedResponse](#markfixedresponse)
Mark issue as fixed.
#### MarkExpected
MarkExpected ([MarkExpectedRequest](#markexpectedrequest)) [MarkExpectedResponse](#markexpectedresponse)
Mark issue as expected.
#### MarkNoActionNeeded
MarkNoActionNeeded ([MarkNoActionNeededRequest](#marknoactionneededrequest)) [MarkNoActionNeededResponse](#marknoactionneededresponse)
Mark issue as no action needed.
#### ClearStatus
ClearStatus ([ClearStatusRequest](#clearstatusrequest)) [ClearStatusResponse](#clearstatusresponse)
Clear the triage status of an issue, returning it to an untriaged state.
Reverses a previous MarkInvestigating / MarkFixed / MarkExpected /
MarkNoActionNeeded so the issue shows up again in open/untriaged views.
#### PostComment
PostComment ([PostCommentRequest](#postcommentrequest)) [PostCommentResponse](#postcommentresponse)
Post a comment on an issue.
### IssuesService
(synq.issues.issues.v1.IssuesService)
IssuesService is a service for managing Issues.
#### BatchGetIssues
BatchGetIssues ([BatchGetIssuesRequest](#batchgetissuesrequest)) [BatchGetIssuesResponse](#batchgetissuesresponse)
#### ListIssues
ListIssues ([ListIssuesRequest](#listissuesrequest)) [ListIssuesResponse](#listissuesresponse)
#### MarkInvestigating
MarkInvestigating ([MarkInvestigatingRequest](#markinvestigatingrequest)) [MarkInvestigatingResponse](#markinvestigatingresponse)
Mark issue as being investigated.
#### MarkFixed
MarkFixed ([MarkFixedRequest](#markfixedrequest)) [MarkFixedResponse](#markfixedresponse)
Mark issue as fixed.
#### MarkExpected
MarkExpected ([MarkExpectedRequest](#markexpectedrequest)) [MarkExpectedResponse](#markexpectedresponse)
Mark issue as expected.
#### MarkNoActionNeeded
MarkNoActionNeeded ([MarkNoActionNeededRequest](#marknoactionneededrequest)) [MarkNoActionNeededResponse](#marknoactionneededresponse)
Mark issue as no action needed.
#### PostComment
PostComment ([PostCommentRequest](#postcommentrequest)) [PostCommentResponse](#postcommentresponse)
Post a comment on an issue.
### HistoryService
(synq.monitors.history.v1.HistoryService)
#### History
History ([HistoryRequest](#historyrequest)) [HistoryResponse](#historyresponse)
### MonitorInfoService
(synq.monitors.info.v1.MonitorInfoService)
#### MonitorInfo
MonitorInfo ([MonitorInfoRequest](#monitorinforequest)) [MonitorInfoResponse](#monitorinforesponse)
### CustomMonitorsService
(synq.monitors.custom\_monitors.v1.CustomMonitorsService)
#### BatchCreateMonitor
BatchCreateMonitor ([BatchCreateMonitorRequest](#batchcreatemonitorrequest)) [BatchCreateMonitorResponse](#batchcreatemonitorresponse)
#### BatchUpdateMonitor
BatchUpdateMonitor ([BatchUpdateMonitorRequest](#batchupdatemonitorrequest)) [BatchUpdateMonitorResponse](#batchupdatemonitorresponse)
#### BatchDeleteMonitor
BatchDeleteMonitor ([BatchDeleteMonitorRequest](#batchdeletemonitorrequest)) [BatchDeleteMonitorResponse](#batchdeletemonitorresponse)
#### BatchUpdateMonitorMode
BatchUpdateMonitorMode ([BatchUpdateMonitorModeRequest](#batchupdatemonitormoderequest)) [BatchUpdateMonitorModeResponse](#batchupdatemonitormoderesponse)
#### ConfigChangesOverview
ConfigChangesOverview ([ConfigChangesOverviewRequest](#configchangesoverviewrequest)) [ConfigChangesOverviewResponse](#configchangesoverviewresponse)
#### BatchUpdateMonitorSeverity
BatchUpdateMonitorSeverity ([BatchUpdateMonitorSeverityRequest](#batchupdatemonitorseverityrequest)) [BatchUpdateMonitorSeverityResponse](#batchupdatemonitorseverityresponse)
#### ListConfigsMonitors
ListConfigsMonitors ([ListConfigsMonitorsRequest](#listconfigsmonitorsrequest)) [ListConfigsMonitorsResponse](#listconfigsmonitorsresponse)
#### ListMonitors
ListMonitors ([ListMonitorsRequest](#listmonitorsrequest)) [ListMonitorsResponse](#listmonitorsresponse)
### MonitorPredictionsService
(synq.monitors.predictions.v1.MonitorPredictionsService)
Access to anomaly detection model predictions and raw metric timeseries.
#### GetMonitorPredictions
GetMonitorPredictions ([GetMonitorPredictionsRequest](#getmonitorpredictionsrequest)) [GetMonitorPredictionsResponse](#getmonitorpredictionsresponse)
Returns prediction timeseries for a monitor. The monitor must exist
and not be deleted. Defaults to the monitor's current metrics\_version.
#### GetEntityMetrics
GetEntityMetrics ([GetEntityMetricsRequest](#getentitymetricsrequest)) [GetEntityMetricsResponse](#getentitymetricsresponse)
Returns raw metric timeseries for an entity. Identity-aware: resolves
logical assets (e.g., dbt models) to their underlying physical tables.
#### BatchGetLatestEntityMetrics
BatchGetLatestEntityMetrics ([BatchGetLatestEntityMetricsRequest](#batchgetlatestentitymetricsrequest)) [BatchGetLatestEntityMetricsResponse](#batchgetlatestentitymetricsresponse)
Returns the most recent observed table-stats sample (row count, freshness) for each
requested entity. Identity-aware: resolves logical assets to their underlying physical
tables. Paths with no recent sample are omitted from the response rather than returned
with empty values — callers should treat a missing entry as "no data". Lookback matches
GetEntityMetrics (30 days).
### DeploymentRulesService
(synq.monitors.automated\_monitors.v1.DeploymentRulesService)
#### GetDeployOverview
GetDeployOverview ([GetDeployOverviewRequest](#getdeployoverviewrequest)) [GetDeployOverviewResponse](#getdeployoverviewresponse)
#### GetDeployDeleteOverview
GetDeployDeleteOverview ([GetDeployDeleteOverviewRequest](#getdeploydeleteoverviewrequest)) [GetDeployDeleteOverviewResponse](#getdeploydeleteoverviewresponse)
#### DeleteDeploymentRule
DeleteDeploymentRule ([DeleteDeploymentRuleRequest](#deletedeploymentrulerequest)) [DeleteDeploymentRuleResponse](#deletedeploymentruleresponse)
#### ListDeploymentRules
ListDeploymentRules ([ListDeploymentRulesRequest](#listdeploymentrulesrequest)) [ListDeploymentRulesResponse](#listdeploymentrulesresponse)
#### ListDeploymentRulesForAsset
ListDeploymentRulesForAsset ([ListDeploymentRulesForAssetRequest](#listdeploymentrulesforassetrequest)) [ListDeploymentRulesForAssetResponse](#listdeploymentrulesforassetresponse)
#### BatchGetDeploymentRules
BatchGetDeploymentRules ([BatchGetDeploymentRulesRequest](#batchgetdeploymentrulesrequest)) [BatchGetDeploymentRulesResponse](#batchgetdeploymentrulesresponse)
#### UpsertDeploymentRule
UpsertDeploymentRule ([UpsertDeploymentRuleRequest](#upsertdeploymentrulerequest)) [UpsertDeploymentRuleResponse](#upsertdeploymentruleresponse)
#### BatchUpdateDeploymentRuleTitle
BatchUpdateDeploymentRuleTitle ([BatchUpdateDeploymentRuleTitleRequest](#batchupdatedeploymentruletitlerequest)) [BatchUpdateDeploymentRuleTitleResponse](#batchupdatedeploymentruletitleresponse)
#### DeployDeploymentRule
DeployDeploymentRule ([DeployDeploymentRuleRequest](#deploydeploymentrulerequest)) [DeployDeploymentRuleResponse](#deploydeploymentruleresponse)
#### BatchDeployDeploymentRules
BatchDeployDeploymentRules ([BatchDeployDeploymentRulesRequest](#batchdeploydeploymentrulesrequest)) [BatchDeployDeploymentRulesResponse](#batchdeploydeploymentrulesresponse)
#### BatchUpsertDeploymentRules
BatchUpsertDeploymentRules ([BatchUpsertDeploymentRulesRequest](#batchupsertdeploymentrulesrequest)) [BatchUpsertDeploymentRulesResponse](#batchupsertdeploymentrulesresponse)
#### BatchDeleteDeploymentRules
BatchDeleteDeploymentRules ([BatchDeleteDeploymentRulesRequest](#batchdeletedeploymentrulesrequest)) [BatchDeleteDeploymentRulesResponse](#batchdeletedeploymentrulesresponse)
### ChecksCoverageService
(synq.entities.checks.v1.ChecksCoverageService)
ChecksCoverageService provides functionality to retrieve and analyze the coverage of checks
for entities in the system. It helps track which checks are applied to entities, including
both direct checks and propagated checks from upstream entities.
#### GetCoverage
GetCoverage ([GetCoverageRequest](#getcoveragerequest)) [GetCoverageResponse](#getcoverageresponse)
GetCoverage retrieves the coverage of checks for a specific entity.
This includes both direct checks applied to the entity and checks propagated
from upstream entities. The response provides detailed information about:
* Table-level checks
* Column-level checks
* Check propagation paths
* Column usage statistics
### ChecksCategoriesService
(synq.entities.checks.v1.ChecksCategoriesService)
ChecksCategoriesService lets workspace admins set explicit category
overrides on individual checks. An explicit category is the
authoritative category for a check — it takes precedence over the
categories computed by the workspace's categorisation rules.
It is a public API so customers can manage check categories
programmatically; the same service is also mounted on the internal
API. The workspace and the acting identity are always taken from the
request context, never from the payload.
#### UpsertCheckCategories
UpsertCheckCategories ([UpsertCheckCategoriesRequest](#upsertcheckcategoriesrequest)) [UpsertCheckCategoriesResponse](#upsertcheckcategoriesresponse)
UpsertCheckCategories sets (or replaces) the explicit category for
one or more checks. Each entry is the complete state for its check —
both dimensions — so an empty `category` / `governance_category` means
"no explicit value for that dimension".
#### DeleteCheckCategories
DeleteCheckCategories ([DeleteCheckCategoriesRequest](#deletecheckcategoriesrequest)) [DeleteCheckCategoriesResponse](#deletecheckcategoriesresponse)
DeleteCheckCategories clears the explicit category (both dimensions)
for the given checks. Checks fall back to their rule-computed
categories afterwards.
#### ListCheckCategories
ListCheckCategories ([ListCheckCategoriesRequest](#listcheckcategoriesrequest)) [ListCheckCategoriesResponse](#listcheckcategoriesresponse)
ListCheckCategories returns every explicit check category in the
caller's workspace.
### DatabaseCoordinatesService
(synq.entities.coordinates.v1.DatabaseCoordinatesService)
DatabaseCoordinatesService is a service for getting database coordinates of Entities.
#### BatchDatabaseCoordinates
BatchDatabaseCoordinates ([BatchDatabaseCoordinatesRequest](#batchdatabasecoordinatesrequest)) [BatchDatabaseCoordinatesResponse](#batchdatabasecoordinatesresponse)
Get multiple DatabaseCoordinates for identifiers.
#### BatchIdsByCoordinates
BatchIdsByCoordinates ([BatchIdsByCoordinatesRequest](#batchidsbycoordinatesrequest)) [BatchIdsByCoordinatesResponse](#batchidsbycoordinatesresponse)
Given database FQN return possible entity ids.
### OrchestrationService
(synq.entities.orchestration.v1.OrchestrationService)
OrchestrationService provides information about orchestration relationships between entities.
This includes relationships between Airflow tasks and transformation models (dbt, SQLMesh),
as well as task-to-task dependencies.
#### BatchOrchestration
BatchOrchestration ([BatchOrchestrationRequest](#batchorchestrationrequest)) [BatchOrchestrationResponse](#batchorchestrationresponse)
BatchOrchestration retrieves orchestration relationships for multiple entities.
For each entity, it returns both upstream entities (what orchestrates it) and
downstream entities (what it orchestrates).
### TableConstraintsService
(synq.entities.constraints.v1.TableConstraintsService)
TableConstraintsService provides access to table constraint and index information.
#### GetTableConstraints
GetTableConstraints ([GetTableConstraintsRequest](#gettableconstraintsrequest)) [GetTableConstraintsResponse](#gettableconstraintsresponse)
Get table constraints (primary keys, foreign keys, indexes, etc.) for a given entity.
### ImpactService
(synq.entities.impact.v1.ImpactService)
#### GetImpact
GetImpact ([GetImpactRequest](#getimpactrequest)) [GetImpactResponse](#getimpactresponse)
### IdentifierResolveService
(synq.entities.resolve.v1.IdentifierResolveService)
IdentifierResolveService resolves identifiers to their Coalesce Quality paths and identities.
#### BatchResolveIdentifiers
BatchResolveIdentifiers ([BatchResolveIdentifiersRequest](#batchresolveidentifiersrequest)) [BatchResolveIdentifiersResponse](#batchresolveidentifiersresponse)
Resolve multiple identifiers, returning their Coalesce Quality paths and identity groups.
### CodeService
(synq.entities.code.v1.CodeService)
CodeService is a service for retrieving code associated with entities in the system.
It provides functionality to access and manage code artifacts such as SQL queries,
Python scripts, dbt models, and other code configurations that are part of Coalesce Quality entities.
#### ListCode
ListCode ([ListCodeRequest](#listcoderequest)) [ListCodeResponse](#listcoderesponse)
ListCode retrieves all code artifacts associated with a specific entity.
This includes SQL queries, Python scripts, dbt models, and other code configurations
that define or are part of the entity's functionality.
### EntityExecutionsService
(synq.entities.executions.v1.EntityExecutionsService)
Deprecated: Use \[synq.entities.custom.v1.EntityExecutionsService] instead
#### UpsertExecution
UpsertExecution ([UpsertExecutionRequest](#upsertexecutionrequest)) [UpsertExecutionResponse](#upsertexecutionresponse)
Execution affects status of the custom entity
#### UpsertLogEntry
UpsertLogEntry ([UpsertLogEntryRequest](#upsertlogentryrequest)) [UpsertLogEntryResponse](#upsertlogentryresponse)
LogEntry is a log message for the custom entity
### EntityExecutionsService
(synq.entities.executions.v2.EntityExecutionsService)
EntityExecutionsService provides read-only access to entity execution history.
This service allows customers to retrieve information about all executions that happened on their entities,
including execution status, timing, and messages.
Use cases:
* Retrieve execution history for specific entities
* Filter executions by time range, status, or execution type
* Get aggregated summaries of execution activity
* Track execution trends and patterns
#### ListExecutions
ListExecutions ([ListExecutionsRequest](#listexecutionsrequest)) [ListExecutionsResponse](#listexecutionsresponse)
ListExecutions retrieves a paginated list of executions for one or more entities.
Executions are returned in reverse chronological order (newest first).
Supports filtering by:
* Entity identifiers (required)
* Time range
* Execution type(s)
* Status(es)
#### BatchGetExecutions
BatchGetExecutions ([BatchGetExecutionsRequest](#batchgetexecutionsrequest)) [BatchGetExecutionsResponse](#batchgetexecutionsresponse)
BatchGetExecutions retrieves multiple executions by their IDs.
This is useful when you already know the execution IDs and want to fetch their details.
#### GetExecutionsSummary
GetExecutionsSummary ([GetExecutionsSummaryRequest](#getexecutionssummaryrequest)) [GetExecutionsSummaryResponse](#getexecutionssummaryresponse)
GetExecutionsSummary provides aggregated statistics about executions for specified entities.
This is useful for quickly understanding execution patterns without fetching all execution details.
Returns:
* Counts by execution type
* Counts by status
* Time range of available executions
* Latest execution per entity
#### GetLatestExecutions
GetLatestExecutions ([GetLatestExecutionsRequest](#getlatestexecutionsrequest)) [GetLatestExecutionsResponse](#getlatestexecutionsresponse)
GetLatestExecutions retrieves the most recent execution for each specified entity.
IMPORTANT: Only returns executions where the entity appears in EntityExecution.entities (what executed).
This means it returns executions OF the entity (e.g., model runs, monitor runs, task runs),
NOT executions that merely reference the entity in targets or extra\_references.
For example, querying for a table won't return results because tables don't execute on their own -
they are created/updated by models (which do execute).
Optionally filter by execution status to get the latest execution with a specific status.
### ChecksRelationshipsService
(synq.entities.custom.v1.ChecksRelationshipsService)
#### UpsertCheckRelationships
UpsertCheckRelationships ([UpsertCheckRelationshipsRequest](#upsertcheckrelationshipsrequest)) [UpsertCheckRelationshipsResponse](#upsertcheckrelationshipsresponse)
Create or update relationships that attach a check (e.g. a SQL test) to the
entities it validates. Idempotent per (check, checked) pair: an existing
relationship is updated, otherwise it is created.
#### DeleteCheckRelationships
DeleteCheckRelationships ([DeleteCheckRelationshipsRequest](#deletecheckrelationshipsrequest)) [DeleteCheckRelationshipsResponse](#deletecheckrelationshipsresponse)
Delete relationships between checks and the entities they validate.
Relationships that do not exist are ignored.
### EntitiesService
(synq.entities.custom.v1.EntitiesService)
custom.EntitiesService is a service for managing custom entities. Entities can represent
various data platform concepts such as services, consumers, applications or data pipelines
that are not natively available in Coalesce Quality.
Entities are identified by a unique identifier and can be created, updated, read and deleted.
#### UpsertEntity
UpsertEntity ([UpsertEntityRequest](#upsertentityrequest)) [UpsertEntityResponse](#upsertentityresponse)
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
#### DeleteEntity
DeleteEntity ([DeleteEntityRequest](#deleteentityrequest)) [DeleteEntityResponse](#deleteentityresponse)
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
#### ListEntities
ListEntities ([ListEntitiesRequest](#listentitiesrequest)) [ListEntitiesResponse](#listentitiesresponse)
List all entities.
### RelationshipsService
(synq.entities.custom.v1.RelationshipsService)
RelationshipsService allow management of relationships between entities. Relationships can
be created, updated, and deleted between 2 custom entities, or between a custom entity and Coalesce Quality native entity.enum
There is no option to create relationships between 2 Coalesce Quality native entities (dbt model, BI dashboard, etc.).
#### UpsertRelationships
UpsertRelationships ([UpsertRelationshipsRequest](#upsertrelationshipsrequest)) [UpsertRelationshipsResponse](#upsertrelationshipsresponse)
Create or update relationships between entities. If the relationship already exists, it will be updated, otherwise it will be created.
#### DeleteRelationships
DeleteRelationships ([DeleteRelationshipsRequest](#deleterelationshipsrequest)) [DeleteRelationshipsResponse](#deleterelationshipsresponse)
Delete relationships between entities. If the relationship does not exist, it will be ignored.
#### ListRelationships
ListRelationships ([ListRelationshipsRequest](#listrelationshipsrequest)) [ListRelationshipsResponse](#listrelationshipsresponse)
Delete relationships between entities. If the relationship does not exist, it will be ignored.
### GroupsService
(synq.entities.custom.v1.GroupsService)
It eliminates the need to keep state on client side to remember which assets were already created
and which should be deleted. The server will keep track of the current state of the group and client
can always send the intended new state. The server will calculate the diff and entities that are
no longer present in the group will be removed.
Example:
1. group has entities A, B, C at time t1
2. client sends group with entities B, C, D at time t2
3. server will remove entity A from the system and update the current state of the group to B, C, D
The service is designed to be idempotent and can be called multiple times with the same state without
causing any side effects.
#### ListEntityGroups
ListEntityGroups ([ListEntityGroupsRequest](#listentitygroupsrequest)) [ListEntityGroupsResponse](#listentitygroupsresponse)
ListEntityGroups lists all groups.
#### UpsertEntitiesGroup
UpsertEntitiesGroup ([UpsertEntitiesGroupRequest](#upsertentitiesgrouprequest)) [UpsertEntitiesGroupResponse](#upsertentitiesgroupresponse)
UpsertEntitiesGroup updates current definition of group to the server. As part of the upsert operation
the difference of entity ids is calculated between past state and the current state and entities that are
no longer part of the group are removed.
#### DeleteEntitiesGroup
DeleteEntitiesGroup ([DeleteEntitiesGroupRequest](#deleteentitiesgrouprequest)) [DeleteEntitiesGroupResponse](#deleteentitiesgroupresponse)
DeleteEntitiesGroup deletes a group by its identifier. If the group does not exist, it will be a no-op.
### EntityExecutionsService
(synq.entities.custom.v1.EntityExecutionsService)
#### UpsertExecution
UpsertExecution ([UpsertExecutionRequest](#upsertexecutionrequest)) [UpsertExecutionResponse](#upsertexecutionresponse)
Execution affects status of the custom entity
#### UpsertLogEntry
UpsertLogEntry ([UpsertLogEntryRequest](#upsertlogentryrequest)) [UpsertLogEntryResponse](#upsertlogentryresponse)
LogEntry is a log message for the custom entity
### FeaturesService
(synq.entities.custom.v1.FeaturesService)
#### UpsertEntityFeature
UpsertEntityFeature ([UpsertEntityFeatureRequest](#upsertentityfeaturerequest)) [UpsertEntityFeatureResponse](#upsertentityfeatureresponse)
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
#### DeleteEntityFeature
DeleteEntityFeature ([DeleteEntityFeatureRequest](#deleteentityfeaturerequest)) [DeleteEntityFeatureResponse](#deleteentityfeatureresponse)
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
#### ListEntityFeatures
ListEntityFeatures ([ListEntityFeaturesRequest](#listentityfeaturesrequest)) [ListEntityFeaturesResponse](#listentityfeaturesresponse)
List all entities.
### TypesService
(synq.entities.custom.v1.TypesService)
TypesService is a service for managing custom entity types.
#### UpsertType
UpsertType ([UpsertTypeRequest](#upserttyperequest)) [UpsertTypeResponse](#upserttyperesponse)
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
#### DeleteType
DeleteType ([DeleteTypeRequest](#deletetyperequest)) [DeleteTypeResponse](#deletetyperesponse)
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
#### ListTypes
ListTypes ([ListTypesRequest](#listtypesrequest)) [ListTypesResponse](#listtypesresponse)
List all entities.
### LineageService
(synq.entities.lineage.v1.LineageService)
LineageService allows you to fetch:
* Entity level lineage from a starting point of one or more entities.
* Column Level lineage from a starting point of multiple columns of a single entity.
#### GetLineage
GetLineage ([GetLineageRequest](#getlineagerequest)) [GetLineageResponse](#getlineageresponse)
### ChangesService
(synq.entities.changes.v1.ChangesService)
ChangesService provides functionality to track and retrieve all types of changes to data entities.
This unified service returns ALL change types for an entity:
* Git commits: Changes to code files (dbt models, SQL files) tracked in version control
* Schema changes: Database schema modifications (columns added/removed/changed)
* SQL definition changes: View/materialized view definition updates detected by Coalesce Quality
Changes are returned with structured metadata including:
* For git commits: structured statistics (directories, file types, top changes)
* For schema changes: detailed column-level diffs
* For SQL changes: before/after SQL definitions
Use cases:
* "What changed in the last week for table X?" → Returns git commits, schema changes, SQL changes
* "Show me all commits affecting this dbt model" → Returns git commits with lineage context
* "What schema changes happened to this table?" → Returns schema changes detected by Coalesce Quality
#### List
List ([ListRequest](#listrequest)) [ListResponse](#listresponse)
Retrieves the complete change history for specified entities.
Returns all change types (git commits, schema changes, SQL changes) in chronological order (newest first).
Changes include lineage context showing upstream\_distance when changes affect dependencies.
#### BatchChange
BatchChange ([BatchChangeRequest](#batchchangerequest)) [BatchChangeResponse](#batchchangeresponse)
BatchChange retrieves multiple entity changes by their IDs in a single request.
This is an optimized endpoint for fetching specific changes when you already know their IDs,
rather than listing changes for an entity.
### SqlInsightsService
(synq.entities.sql\_insights.v1.SqlInsightsService)
SqlInsightsService exposes analytical information about the SQL used across a
workspace's entities. It answers questions such as "which SQL constructs are
used in my warehouse, and how often" and "what SQL constructs does this
specific entity use", without requiring the caller to re-parse any SQL.
#### ListSqlConstructs
ListSqlConstructs ([ListSqlConstructsRequest](#listsqlconstructsrequest)) [ListSqlConstructsResponse](#listsqlconstructsresponse)
ListSqlConstructs returns the distribution of SQL constructs across all
entities in the workspace, with an occurrence count per construct. The
result is workspace-scoped (derived from the authenticated request) — no
entity paths are supplied. Useful for building filter/autocomplete UIs and
for high-level "shape of our SQL" analytics.
#### BatchSqlDetails
BatchSqlDetails ([BatchSqlDetailsRequest](#batchsqldetailsrequest)) [BatchSqlDetailsResponse](#batchsqldetailsresponse)
BatchSqlDetails returns the SQL details (currently the set of detected SQL
constructs) for each of the requested entities, keyed by their synq path.
Entities with no SQL details are omitted from the response map.
### AnnotationsService
(synq.entities.annotations.v1.AnnotationsService)
AnnotationsService provides operations for managing and querying entity annotations.
Annotations are key-value pairs that can be attached to entities for categorization and filtering.
#### ListAnnotations
ListAnnotations ([ListAnnotationsRequest](#listannotationsrequest)) [ListAnnotationsResponse](#listannotationsresponse)
List all available annotations with their usage counts across entities.
### EntityIncidentsService
(synq.entities.status.v1.EntityIncidentsService)
EntityIncidentsService is the service which retrieves entity status.
#### GetIncidents
GetIncidents ([GetIncidentsRequest](#getincidentsrequest)) [GetIncidentsResponse](#getincidentsresponse)
Get specific entity status by its identifier.
#### BatchGetIncidents
BatchGetIncidents ([BatchGetIncidentsRequest](#batchgetincidentsrequest)) [BatchGetIncidentsResponse](#batchgetincidentsresponse)
Get multiple entity statuses by their identifiers.
### EntityIssuesService
(synq.entities.status.v1.EntityIssuesService)
EntityIssuesService is the service which retrieves entity issues status.
#### GetIssuesStatus
GetIssuesStatus ([GetIssuesStatusRequest](#getissuesstatusrequest)) [GetIssuesStatusResponse](#getissuesstatusresponse)
Get specific entity status by its identifier.
#### BatchGetIssuesStatus
BatchGetIssuesStatus ([BatchGetIssuesStatusRequest](#batchgetissuesstatusrequest)) [BatchGetIssuesStatusResponse](#batchgetissuesstatusresponse)
Get multiple entity statuses by their identifiers.
### FoldersService
(synq.entities.folders.v1.FoldersService)
FoldersService discovers and browses the folder / containment hierarchy of the
catalog: the roots data hangs from, the sub-folders under any folder, the
folders a given entity lives in, and the entities contained in a folder.
It is a read / navigation surface, not folder management — there are no
create, move, or delete operations.
Addressing: every folder has an opaque `folder_entity_id` (round-trip it
verbatim) and a structured `FolderRef{root_entity_id, folders[]}` (the
human-friendly form). Entities — both folder members and the ids you pass to
`GetFolderOf` — are named by their opaque entity id, the same id used across
the rest of the entities API.
Depth footgun: membership is SHALLOW by default. `Browse` returns only the
direct children of a folder, and `ListMembers` returns only the entities
placed directly in the folder. Set `deep = true` (or raise `Browse.depth`) to
recurse into sub-folders.
#### Browse
Browse ([BrowseRequest](#browserequest)) [BrowseResponse](#browseresponse)
Browse the hierarchy one level at a time. With no `parent`, returns the
roots (top-level integrations / containers). With a `parent` folder, returns
that folder's direct sub-folders and the entity ids of its direct,
non-folder members.
One level per call — sub-folders are returned as `Folder`s (each with a
`child_folder_count`), which you Browse into in turn; there is no nested
tree in the response. `filter` narrows the returned members to entities
matching a query.
#### GetFolderOf
GetFolderOf ([GetFolderOfRequest](#getfolderofrequest)) [GetFolderOfResponse](#getfolderofresponse)
Given entity ids, return the folder breadcrumb(s) each entity lives in —
ordered root first, leaf (immediate parent) last. An entity may appear in
more than one hierarchy; the response carries every folder along its
containing chain. Compose with `ListMembers` on an entity's immediate parent
to list its siblings.
#### ListMembers
ListMembers ([ListMembersRequest](#listmembersrequest)) [ListMembersResponse](#listmembersresponse)
List the entity ids contained in a folder, paginated. Direct members only by
default; set `deep = true` to include members of all nested sub-folders.
Narrow with `types` and/or `filter`.
Pagination is a stable client-side window over the folder's fully-resolved
member set: each page recomputes and re-orders that set, then returns the
requested slice. Results are consistent, but paging deep through a very
large folder repeats work — prefer a larger `page_size` over many small
pages.
### EntitiesService
(synq.entities.entities.v1.EntitiesService)
EntitiesService is a service for retriving any entity.
#### GetEntity
GetEntity ([GetEntityRequest](#getentityrequest)) [GetEntityResponse](#getentityresponse)
Get specific entity by its identifier.
#### BatchGetEntities
BatchGetEntities ([BatchGetEntitiesRequest](#batchgetentitiesrequest)) [BatchGetEntitiesResponse](#batchgetentitiesresponse)
Get multiple entities by their identifiers.
#### ListEntities
ListEntities ([ListEntitiesRequest](#listentitiesrequest)) [ListEntitiesResponse](#listentitiesresponse)
List entities matching the given filter
#### SearchEntities
SearchEntities ([SearchEntitiesRequest](#searchentitiesrequest)) [SearchEntitiesResponse](#searchentitiesresponse)
Search for entities.
### SchemaMismatchesService
(synq.entities.schemas.v1.SchemaMismatchesService)
SchemaMismatchesService provides access to schema drift information between
data platform tables and their definitions (e.g., dbt models).
#### BatchSchemaMismatches
BatchSchemaMismatches ([BatchSchemaMismatchesRequest](#batchschemamismatchesrequest)) [BatchSchemaMismatchesResponse](#batchschemamismatchesresponse)
Get schema mismatches for a batch of entities by their identifiers.
### SchemasService
(synq.entities.schemas.v1.SchemasService)
EntitiesService is a service for retriving any entity.
#### GetSchema
GetSchema ([GetSchemaRequest](#getschemarequest)) [GetSchemaResponse](#getschemaresponse)
Get schema of the entity its identifier.
## Messages
### AddIssuesToIncidentRequest
(synq.incidents.v1.AddIssuesToIncidentRequest)
| Field | Type | Description |
| ------------ | -------------------------- | ------------------------------------------------------------------ |
| incident\_id | [ string](#string) | ID of the incident to add issues to |
| actor | [ Actor](#actor) | Actor adding the issues |
| at | [ Timestamp](#timestamp) | Time at which the issues were added. Defaults to the current time. |
| issue\_ids | [repeated string](#string) | IDs of issues to add to the incident |
### AddIssuesToIncidentResponse
(synq.incidents.v1.AddIssuesToIncidentResponse)
### AssignIncidentOwnerRequest
(synq.incidents.v1.AssignIncidentOwnerRequest)
| Field | Type | Description |
| ------------ | ------------------ | ----------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to assign the owner to |
| owner\_email | [ string](#string) | none |
| actor | [ Actor](#actor) | none |
### AssignIncidentOwnerResponse
(synq.incidents.v1.AssignIncidentOwnerResponse)
### BatchGetIncidentsRequest
(synq.incidents.v1.BatchGetIncidentsRequest)
| Field | Type | Description |
| ------------- | -------------------------- | --------------------------- |
| incident\_ids | [repeated string](#string) | IDs of the incidents to get |
### BatchGetIncidentsResponse
(synq.incidents.v1.BatchGetIncidentsResponse)
| Field | Type | Description |
| --------- | ------------------------------------- | ---------------------------- |
| incidents | [map IncidentsEntry](#incidentsentry) | Incidents keyed by their IDs |
### BatchGetIncidentsResponse.IncidentsEntry
(synq.incidents.v1.BatchGetIncidentsResponse.IncidentsEntry)
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Incident](#incident) | none |
### CancelIncidentRequest
(synq.incidents.v1.CancelIncidentRequest)
| Field | Type | Description |
| ------------ | ------------------------ | ----------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to cancel |
| actor | [ Actor](#actor) | Actor cancelling the incident |
| at | [ Timestamp](#timestamp) | Time at which the incident was cancelled. Defaults to the current time. |
### CancelIncidentResponse
(synq.incidents.v1.CancelIncidentResponse)
### CloseIncidentRequest
(synq.incidents.v1.CloseIncidentRequest)
| Field | Type | Description |
| ------------ | ------------------------ | -------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to close |
| actor | [ Actor](#actor) | Actor closing the incident |
| at | [ Timestamp](#timestamp) | Time at which the incident was closed. Defaults to the current time. |
### CloseIncidentResponse
(synq.incidents.v1.CloseIncidentResponse)
### CreateIncidentRequest
(synq.incidents.v1.CreateIncidentRequest)
| Field | Type | Description |
| ------------ | -------------------------- | --------------------------------------------------------------------- |
| issue\_ids | [repeated string](#string) | IDs of issues to add to the incident |
| name | [ string](#string) | Name of the incident |
| actor | [ Actor](#actor) | Actor creating the incident |
| at | [ Timestamp](#timestamp) | Time at which the incident was created. Defaults to the current time. |
| group\_ids | [repeated string](#string) | Optional group IDs associated with the incident |
| owner\_email | [ string](#string) | none |
### CreateIncidentResponse
(synq.incidents.v1.CreateIncidentResponse)
| Field | Type | Description |
| -------- | ---------------------- | ----------- |
| incident | [ Incident](#incident) | none |
### ListIncidentsRequest
(synq.incidents.v1.ListIncidentsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | --------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time.time | [optional Time](#time) | Time range filter |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sort.sort | [optional Sort](#sort) | Sort options |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination |
| states | [repeated State](#state) | Filter by states |
| affected\_entities | [repeated Identifier](#identifier) | Filter by affected entities |
### ListIncidentsRequest.Sort
(synq.incidents.v1.ListIncidentsRequest.Sort)
| Field | Type | Description |
| -------- | ---------------- | ----------- |
| sort\_by | [ Field](#field) | none |
| order | [ Order](#order) | none |
### ListIncidentsRequest.Time
(synq.incidents.v1.ListIncidentsRequest.Time)
| Field | Type | Description |
| ----- | ------------------------ | ----------- |
| field | [ Field](#field) | none |
| from | [ Timestamp](#timestamp) | none |
| to | [ Timestamp](#timestamp) | none |
### ListIncidentsResponse
(synq.incidents.v1.ListIncidentsResponse)
| Field | Type | Description |
| --------- | ------------------------------ | ----------- |
| incidents | [repeated Incident](#incident) | none |
### MergeIncidentsRequest
(synq.incidents.v1.MergeIncidentsRequest)
| Field | Type | Description |
| -------------------- | -------------------------- | ---------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the primary incident to merge into |
| actor | [ Actor](#actor) | Actor performing the merge |
| at | [ Timestamp](#timestamp) | Time at which the incidents were merged. Defaults to the current time. |
| other\_incident\_ids | [repeated string](#string) | IDs of other incidents to merge into the primary incident |
### MergeIncidentsResponse
(synq.incidents.v1.MergeIncidentsResponse)
### PostCommentRequest
(synq.incidents.v1.PostCommentRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to post a comment on. |
| actor | [ Actor](#actor) | Actor posting the comment. |
| comment | [ string](#string) | Comment to post. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_at.at | [optional Timestamp](#timestamp) | Time at which the comment was posted. Defaults to the current time when not provided. |
### PostCommentResponse
(synq.incidents.v1.PostCommentResponse)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| comment\_id | [ string](#string) | none |
### RemoveIssuesFromIncidentRequest
(synq.incidents.v1.RemoveIssuesFromIncidentRequest)
| Field | Type | Description |
| ------------ | -------------------------- | -------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to remove issues from |
| actor | [ Actor](#actor) | Actor removing the issues |
| at | [ Timestamp](#timestamp) | Time at which the issues were removed. Defaults to the current time. |
| issue\_ids | [repeated string](#string) | IDs of issues to remove from the incident |
### RemoveIssuesFromIncidentResponse
(synq.incidents.v1.RemoveIssuesFromIncidentResponse)
### RenameIncidentRequest
(synq.incidents.v1.RenameIncidentRequest)
| Field | Type | Description |
| ------------ | ------------------------ | --------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to rename |
| actor | [ Actor](#actor) | Actor renaming the incident |
| at | [ Timestamp](#timestamp) | Time at which the incident was renamed. Defaults to the current time. |
| name | [ string](#string) | New name for the incident |
### RenameIncidentResponse
(synq.incidents.v1.RenameIncidentResponse)
### SplitIncidentRequest
(synq.incidents.v1.SplitIncidentRequest)
| Field | Type | Description |
| --------------------- | -------------------------- | ------------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the incident to split |
| actor | [ Actor](#actor) | Actor performing the split |
| at | [ Timestamp](#timestamp) | Time at which the incident was split. Defaults to the current time. |
| split\_issue\_ids | [repeated string](#string) | IDs of issues to move to the new incident |
| split\_incident\_name | [ string](#string) | Name for the new incident |
### SplitIncidentResponse
(synq.incidents.v1.SplitIncidentResponse)
| Field | Type | Description |
| --------------- | ---------------------- | ----------- |
| incident | [ Incident](#incident) | none |
| split\_incident | [ Incident](#incident) | none |
### UpdateIncidentStateRequest
(synq.incidents.v1.UpdateIncidentStateRequest)
| Field | Type | Description |
| ------------ | ------------------------ | --------------------------------------------------------------------------- |
| incident\_id | [ string](#string) | none |
| actor | [ Actor](#actor) | Actor updating the incident state |
| at | [ Timestamp](#timestamp) | Time at which the incident state was updated. Defaults to the current time. |
| state | [ State](#state) | New state for the incident |
### UpdateIncidentStateResponse
(synq.incidents.v1.UpdateIncidentStateResponse)
| Field | Type | Description |
| -------- | ---------------------- | ----------- |
| incident | [ Incident](#incident) | none |
### Incident
(synq.incidents.v1.Incident)
| Field | Type | Description |
| ----------- | -------------------------------------------- | ------------------------------------------------------ |
| id | [ string](#string) | ID of the incident. |
| index | [ int32](#int32) | Index of the incident (for human-readable references). |
| name | [ string](#string) | Name of the incident. |
| issue\_ids | [repeated string](#string) | IDs of issues associated with this incident. |
| created\_by | [ Actor](#actor) | Actor who created the incident. |
| owner | [ User](#user) | Owner of the incident. |
| created\_at | [ Timestamp](#timestamp) | Time at which the incident was created. |
| updated\_by | [ Actor](#actor) | Actor who last updated the incident. |
| updated\_at | [ Timestamp](#timestamp) | Time at which the incident was last updated. |
| state | [ State](#state) | State of the incident. |
| comments | [repeated IncidentComment](#incidentcomment) | List of comments posted on the incident. |
### IncidentComment
(synq.incidents.v1.IncidentComment)
| Field | Type | Description |
| ----------- | ------------------------ | ----------- |
| id | [ string](#string) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| actor | [ Actor](#actor) | none |
### IamRequest
(synq.auth.iam.v1.IamRequest)
### IamResponse
(synq.auth.iam.v1.IamResponse)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Workspace to which caller is authenticated |
| scopes | [repeated Scope](#scope) | What scopes are granted |
| scope\_names | [repeated string](#string) | Names of the scopes available |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Indicates that the token is scoped to a specific integration |
| subject | [ string](#string) | Identifier of the provided token |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_synq\_user\_id.synq\_user\_id | [optional string](#string) | Coalesce Quality user ID associated with the token, present for user-level credentials |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_client\_type.client\_type | [optional string](#string) | Indicates the client type through which the request was made |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user\_name.user\_name | [optional string](#string) | Human-readable name of the authenticated user. Populated only when the token is tied to a Coalesce Quality user (i.e. `synq_user_id` is set); empty for workspace-level or third-party tokens. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user\_email.user\_email | [optional string](#string) | Email address of the authenticated user. Populated only when the token is tied to a Coalesce Quality user (i.e. `synq_user_id` is set); empty for workspace-level or third-party tokens. |
### Config
(synq.agent.dwh.v1.Config)
Config represents the main configuration for the DWH agent
| Field | Type | Description |
| ----------- | ----------------------------------------- | --------------------------------------- |
| agent | [ Agent](#agent) | Agent configuration |
| synq | [ SYNQ](#synq) | Coalesce Quality platform configuration |
| connections | [map ConnectionsEntry](#connectionsentry) | Map of connection configurations |
### Config.Agent
(synq.agent.dwh.v1.Config.Agent)
Agent contains metadata about this agent instance
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------- |
| name | [ string](#string) | Name of the agent instance |
| tags | [repeated string](#string) | Tags to categorize and organize the agent |
| log\_level | [ LogLevel](#loglevel) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_log\_json.log\_json | [optional bool](#bool) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_log\_report\_caller.log\_report\_caller | [optional bool](#bool) | none |
### Config.ConnectionsEntry
(synq.agent.dwh.v1.Config.ConnectionsEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Connection](#connection) | none |
### AthenaConf
(synq.agent.dwh.v1.AthenaConf)
Amazon Athena specific configuration.
Athena is serverless: there is no host/port — the endpoint is implied by
the AWS region. Queries run inside a workgroup that owns the per-query
data-scan cap and the S3 query result location. The configured workgroup
MUST have ResultConfiguration.OutputLocation set, otherwise every Athena
query fails. Setting EnforceWorkGroupConfiguration=true on the workgroup
is strongly recommended so per-query overrides cannot escape the cap.
Authentication
AthenaConf carries an AWS credential source in one of three ways:
1. Static IAM access key — set access\_key\_id and secret\_access\_key
(and optionally session\_token if those keys are short-lived STS
credentials).
2. Shared-config profile — set aws\_profile to a named profile from
\~/.aws/credentials or \~/.aws/config. Useful when the agent host
already has AWS CLI configured.
3. AWS default credential chain — leave all of the above empty. The
AWS SDK then uses environment variables (AWS\_ACCESS\_KEY\_ID /
AWS\_SECRET\_ACCESS\_KEY / AWS\_PROFILE), shared config, or the EC2 /
ECS / EKS instance role attached to the agent host.
If more than one source is provided, they resolve in the order above —
explicit static keys win over a profile, profile wins over the chain.
role\_arn is independent of the source choice. When set, the executor
uses one of the three sources as the calling identity and assumes
role\_arn via STS for every Athena/Glue API call. external\_id is
included in the AssumeRole request when set; required by trust policies
that mandate it.
Validation: access\_key\_id and secret\_access\_key must be set as a pair
(one without the other is rejected); session\_token may only be set when
both keys are also set.
| Field | Type | Description |
| --------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| region | [ string](#string) | AWS region hosting the Athena service and Glue Data Catalog. |
| workgroup | [ string](#string) | Athena workgroup. Defaults to "primary" when empty. Must have a ResultConfiguration.OutputLocation configured. |
| catalog | [ string](#string) | Glue Data Catalog name. Defaults to "AwsDataCatalog" when empty. Override only when using federated catalogs backed by Lambda connectors. |
| access\_key\_id | [ string](#string) | AWS access key ID for static IAM credentials. Required together with secret\_access\_key. |
| secret\_access\_key | [ string](#string) | AWS secret access key. Required together with access\_key\_id. |
| session\_token | [ string](#string) | STS session token, set only when access\_key\_id and secret\_access\_key are short-lived STS credentials. Ignored otherwise. |
| aws\_profile | [ string](#string) | Named profile from the AWS shared credentials / config files (\~/.aws/credentials, \~/.aws/config). Useful when the agent host already has AWS CLI configured. |
| role\_arn | [ string](#string) | IAM role to assume via STS for every Athena / Glue API call. The calling identity comes from access\_key\_id, aws\_profile, or the default credential chain — whichever is configured. |
| external\_id | [ string](#string) | ExternalId included in the AssumeRole request. Set when the role's trust policy requires it. |
| role\_session\_name | [ string](#string) | Session name attached to the AssumeRole request. Defaults to "synq-athena-agent". |
| scope | [ ScopeFilter](#scopefilter) | Scope filter for include/exclude filtering by Glue catalog, Glue database, and table. Mapping (mirrors BigQuery's project/dataset shape): ScopeRule.database = Glue Data Catalog name (almost always 'AwsDataCatalog') ScopeRule.schema = Glue database — what users typically filter on ScopeRule.table = Glue table / view name When include rules constrain schemas, the IAM principal does not need catalog-wide glue:GetDatabases — only glue:GetDatabase on the listed names. |
| use\_show\_create\_table | [ bool](#bool) | Use SHOW CREATE TABLE to retrieve full table DDL (CTAS bodies, Iceberg TBLPROPERTIES, Hive external LOCATION/SerDe). One Athena query per table — billed at the 10MB scan minimum each. |
| use\_show\_create\_view | [ bool](#bool) | Use SHOW CREATE VIEW to retrieve full view DDL instead of the rewritten body from information\_schema.views.view\_definition. |
| use\_iceberg\_metrics\_scan | [ bool](#bool) | For Iceberg tables, fan out one Athena query per table to read row counts and total file size from the table's `$files` / `$snapshots` / `$partitions` metadata tables. Without this, Iceberg tables only have metrics when the customer has run ANALYZE TABLE COMPUTE STATISTICS (Glue parameters). Hive external tables are unaffected. Each call is one Athena query (\~\$0.00005 at the 10MB scan minimum). |
### BigQueryConf
(synq.agent.dwh.v1.BigQueryConf)
BigQuery specific configuration
| Field | Type | Description |
| --------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| project\_id | [ string](#string) | GCP project ID |
| service\_account\_key | [ string](#string) | Service account key JSON |
| service\_account\_key\_file | [ string](#string) | Location of service account key file |
| region | [ string](#string) | Region for BigQuery resources |
| datasets | [repeated string](#string) | Explicit list of dataset names to scrape (e.g., \['analytics', 'mart\_core']). When set, only these datasets are queried — the service account does not need project-level bigquery.datasets.list permission. When empty, all visible datasets in the project are discovered automatically. |
### ClickhouseConf
(synq.agent.dwh.v1.ClickhouseConf)
| Field | Type | Description |
| --------------- | ------------------ | ----------------------------------------------- |
| host | [ string](#string) | Host address |
| port | [ int32](#int32) | Port number (default: 9000 for native protocol) |
| database | [ string](#string) | Database name |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| allow\_insecure | [ bool](#bool) | Whether to use disable SSL for connection |
### DatabricksConf
(synq.agent.dwh.v1.DatabricksConf)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| workspace\_url | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_auth\_token.auth\_token | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_auth\_client.auth\_client | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_auth\_secret.auth\_secret | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_warehouse.warehouse | [optional string](#string) | none |
| refresh\_table\_metrics | [ bool](#bool) | none |
| refresh\_table\_metrics\_use\_scan | [ bool](#bool) | none |
| fetch\_table\_tags | [ bool](#bool) | none |
| use\_show\_create\_table | [ bool](#bool) | none |
### DuckDBConf
(synq.agent.dwh.v1.DuckDBConf)
DuckDB / MotherDuck specific configuration.
Supports two modes:
1. Local/embedded: set database to a file path (e.g. "/tmp/my.duckdb") or ":memory:"
2. MotherDuck (cloud): set motherduck\_account and motherduck\_token
| Field | Type | Description |
| ------------------- | ------------------ | ------------------------------------------------------------------------------------------- |
| database | [ string](#string) | Local database path (file path or ":memory:"). Mutually exclusive with motherduck\_account. |
| motherduck\_account | [ string](#string) | MotherDuck account name. Requires motherduck\_token. |
| motherduck\_token | [ string](#string) | MotherDuck authentication token. Required when motherduck\_account is set. |
### FabricConf
(synq.agent.dwh.v1.FabricConf)
Microsoft Fabric Warehouse / Lakehouse SQL analytics endpoint configuration.
Fabric speaks T-SQL over TDS (like SQL Server) but is deliberately its own
integration with a minimal, opinionated surface: the connection always uses
TLS on port 1433 and authenticates with a Microsoft Entra ID service principal
(Fabric rejects SQL logins entirely). Callers therefore only supply the
endpoint, the warehouse name, and the service-principal credentials — the
azuread ActiveDirectoryServicePrincipal workflow and encryption settings are
fixed internally so there is nothing to guess.
For hosted deployments that mint their own Entra token (managed identity /
workload-identity federation), set access\_token instead of client\_id +
client\_secret.
| Field | Type | Description |
| -------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| host | [ string](#string) | Workspace SQL analytics endpoint host, e.g. "\.datawarehouse.fabric.microsoft.com". |
| database | [ string](#string) | Default execution database — the context in which *unqualified* ad-hoc / monitor SQL resolves. Optional: defaults to "master" (the always-present workspace entry point). Metadata scrapping and generated metrics SQL are fully database-qualified via cross-database queries, so this only affects unqualified queries. It is a different axis from `databases` (which databases to scrape). |
| scope | [ ScopeFilter](#scopefilter) | Include/exclude filter over the workspace's databases/schemas/tables (ScopeRule.database = Fabric database/warehouse, .schema = schema, .table = table). The canonical scope encoding (as AthenaConf uses); unset means the whole workspace. A per-call scope can only narrow within this, never escape it. |
| client\_id | [ string](#string) | Entra application (client) ID of the service principal (default auth), or the user-assigned identity client ID when auth\_type is "managed\_identity". |
| client\_secret | [ string](#string) | Service principal client secret. |
| tenant\_id | [ string](#string) | Entra tenant (directory) ID. Optional: inferred from the endpoint when empty; set it when the server-supplied authority is not the SP's home tenant. |
| access\_token | [ string](#string) | Pre-acquired Entra OAuth access token for the SQL scope ([https://database.windows.net/.default](https://database.windows.net/.default)). When set, takes precedence over all other authentication methods — for managed identity / workload-identity hosts. |
| auth\_type | [ string](#string) | Authentication method, matched case-insensitively. Empty defaults to a service principal (client\_id + client\_secret). The ambient modes below authenticate as the host's own Azure identity with no stored credential and are intended for on-prem agents (opt-in — never engaged unless named): - "azure\_cli": reuse an interactive `az login` session (local execution) - "default": DefaultAzureCredential chain (managed identity → env → workload identity → az CLI) - "managed\_identity": Azure managed identity (set client\_id for a user-assigned identity) Canonical values are lower-case (the scrapper matches case-insensitively). |
### MSSQLConf
(synq.agent.dwh.v1.MSSQLConf)
Microsoft SQL Server / Azure SQL Database specific configuration.
SQL Server is database-scoped — each connection targets a single database.
Authentication methods (in priority order):
1. access\_token: pre-acquired Azure AD OAuth token
2. fed\_auth: Azure AD federated authentication (with optional username/password)
3. username + password: standard SQL Server Authentication
| Field | Type | Description |
| ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| host | [ string](#string) | Host address or IP. For Azure SQL: e.g. "yourserver.database.windows.net" |
| port | [ int32](#int32) | Port number (default: 1433) |
| database | [ string](#string) | Database name to connect to |
| username | [ string](#string) | Username for SQL Server Authentication or Azure AD. For Azure AD Service Principal, this is the Application (Client) ID. Leave empty when using access\_token or Azure AD Managed Identity. |
| password | [ string](#string) | Password for SQL Server Authentication or Azure AD client secret |
| trust\_cert | [ bool](#bool) | Skip TLS server certificate verification |
| encrypt | [ string](#string) | Connection encryption mode: "true" (default), "false", "disable" |
| fed\_auth | [ string](#string) | Azure AD federated authentication method. When set, the azuread driver is used instead of the standard sqlserver driver. Values: "ActiveDirectoryDefault", "ActiveDirectoryMSI", "ActiveDirectoryServicePrincipal", "ActiveDirectoryAzCli" |
| access\_token | [ string](#string) | Pre-acquired Azure AD OAuth access token. When set, takes precedence over all other authentication methods. |
| application\_client\_id | [ string](#string) | Azure AD Application (Client) ID. Used with ActiveDirectoryServicePrincipal and user-assigned MSI. |
### MySQLConf
(synq.agent.dwh.v1.MySQLConf)
MySQL specific configuration
| Field | Type | Description |
| --------------- | ------------------------------- | ------------------------------------- |
| host | [ string](#string) | Host address |
| port | [ int32](#int32) | Port number (default: 3306) |
| database | [ string](#string) | Database name |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| allow\_insecure | [ bool](#bool) | Whether to allow insecure connections |
| params | [map ParamsEntry](#paramsentry) | Additional connection parameters |
### MySQLConf.ParamsEntry
(synq.agent.dwh.v1.MySQLConf.ParamsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### OracleConf
(synq.agent.dwh.v1.OracleConf)
Oracle Database specific configuration.
Oracle connections are scoped to a Pluggable Database (PDB) via the service name.
Authentication methods:
1. wallet\_path: Oracle Wallet (mTLS) for OCI Autonomous Database
2. username + password: standard Oracle database authentication
Both can be combined (wallet for TLS + explicit credentials).
| Field | Type | Description |
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| host | [ string](#string) | Host address or IP. For OCI: e.g. "adb.eu-frankfurt-1.oraclecloud.com" |
| port | [ int32](#int32) | Listener port (default: 1521, OCI Autonomous DB with mTLS uses 1522) |
| service\_name | [ string](#string) | Service name (PDB name). For OCI Autonomous DB: e.g. "mydb\_high", "mydb\_low", "mydb\_tp" |
| username | [ string](#string) | Username for authentication (optional when wallet stores credentials) |
| password | [ string](#string) | Password for authentication (optional when wallet stores credentials) |
| ssl | [ bool](#bool) | Enable TLS/SSL encryption (TCPS protocol). Required for OCI Autonomous Database. Auto-enabled when wallet\_path is set. |
| ssl\_verify | [ bool](#bool) | Enable server certificate verification when SSL is enabled |
| wallet\_path | [ string](#string) | Path to Oracle Wallet directory for mTLS authentication (OCI Autonomous DB). Contains TLS certificates (cwallet.sso) and optionally stored credentials. |
| use\_diagnostics\_pack | [ bool](#bool) | Use Oracle Diagnostics Pack (AWR) for persistent query log history. When false, query logs come from V\$SQL (in-memory, no additional license). When true, query logs come from DBA\_HIST views (requires Diagnostics Pack license). |
### PostgresConf
(synq.agent.dwh.v1.PostgresConf)
Postgres specific configuration
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------- |
| host | [ string](#string) | Host address |
| port | [ int32](#int32) | Port number (default: 5432) |
| database | [ string](#string) | Database name |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| allow\_insecure | [ bool](#bool) | Whether to allow insecure connections |
### RedshiftConf
(synq.agent.dwh.v1.RedshiftConf)
Redshift specific configuration
| Field | Type | Description |
| ---------------------------- | ------------------ | -------------------------------------------- |
| host | [ string](#string) | Host address |
| port | [ int32](#int32) | Port number (default: 5439) |
| database | [ string](#string) | Database name |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| freshness\_from\_query\_logs | [ bool](#bool) | Estimate table freshness based on query logs |
### SnowflakeConf
(synq.agent.dwh.v1.SnowflakeConf)
Snowflake specific configuration
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| account | [ string](#string) | Snowflake account identifier |
| warehouse | [ string](#string) | Virtual warehouse to use |
| role | [ string](#string) | Role to assume |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| private\_key | [ string](#string) | Content of Private key used for Snowflake authentication |
| private\_key\_file | [ string](#string) | Location of the file containing Private key used for Snowflake authentication |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_private\_key\_passphrase.private\_key\_passphrase | [optional string](#string) | Passphrase used to decode Private key |
| databases | [repeated string](#string) | Database to connect to |
| use\_get\_ddl | [ bool](#bool) | Use GET\_DDL to determine queries used for table/view creation |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_account\_usage\_db.account\_usage\_db | [optional string](#string) | Name of the database where ACCOUNT\_USAGE schema is present, fallbacks to SNOWFLAKE |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_auth\_type.auth\_type | [optional string](#string) | Authentication type: empty (default, uses password or private\_key), "externalbrowser" (SSO via browser) When set to "externalbrowser", opens browser for SSO login and caches the token locally. |
### TrinoConf
(synq.agent.dwh.v1.TrinoConf)
Trino specific configuration
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| host | [ string](#string) | Host address |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Optional port to use, otherwise it will use the default port 8080 |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_plaintext.use\_plaintext | [optional bool](#bool) | Use non-SSL connection to Trino. This should only be enabled if the Trino cluster does not support SSL or if the connection is secured through other means (e.g., a VPN). Defaults to false (SSL enabled). |
| username | [ string](#string) | Username for authentication |
| password | [ string](#string) | Password for authentication |
| catalogs | [repeated string](#string) | To which catalogs to connect |
| no\_show\_create\_view | [ bool](#bool) | Use SHOW CREATE VIEW to get views DDLs |
| no\_show\_create\_table | [ bool](#bool) | Use SHOW CREATE TABLE to get tables DDLs |
| no\_materialized\_views | [ bool](#bool) | Should it fetch system.metadata.materialized\_views to get information about Trino MVs |
| fetch\_table\_comments | [ bool](#bool) | Fetch Trino table comments from system.metadata.table\_comments |
### AgentTask
(synq.agent.dwh.v1.AgentTask)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| connection\_id | [ string](#string) | none |
| task\_id | [ string](#string) | none |
| scheduled\_at | [ Timestamp](#timestamp) | When this task should execute, if none is specified it will use time of execution |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deadline\_at.deadline\_at | [optional Timestamp](#timestamp) | After what time this task should stop executing (even in case of errors, retries will be ignored after this time) |
| created\_at | [ Timestamp](#timestamp) | When the task was created |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) command.fetch\_full\_catalog | [ FetchFullCatalogCommand](#fetchfullcatalogcommand) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) command.fetch\_full\_metrics | [ FetchFullMetricsCommand](#fetchfullmetricscommand) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) command.fetch\_segments | [ FetchSegmentsCommand](#fetchsegmentscommand) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) command.fetch\_metrics | [ FetchMetricsCommand](#fetchmetricscommand) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) command.fetch\_table\_stats | [ FetchTableStatsCommand](#fetchtablestatscommand) | none |
### AgentTaskData
(synq.agent.dwh.v1.AgentTaskData)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.fetch\_segments\_result | [ FetchSegmentsResult](#fetchsegmentsresult) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.fetch\_metrics\_result | [ FetchMetricsResult](#fetchmetricsresult) | none |
### FetchFullCatalogCommand
(synq.agent.dwh.v1.FetchFullCatalogCommand)
### FetchFullMetricsCommand
(synq.agent.dwh.v1.FetchFullMetricsCommand)
### FetchMetricsCommand
(synq.agent.dwh.v1.FetchMetricsCommand)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------ | ----------------------------------------------------- |
| sql\_queries | [repeated SqlQuery](#sqlquery) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_command\_context.command\_context | [optional string](#string) | Application specific context around metrics retrieval |
### FetchMetricsResult
(synq.agent.dwh.v1.FetchMetricsResult)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------ |
| query\_rows | [repeated QueryRows](#queryrows) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_command\_context.command\_context | [optional string](#string) | Matches command\_context of FetchMetricsCommand / FetchTableStatsCommand |
### FetchMetricsResult.ColumnValue
(synq.agent.dwh.v1.FetchMetricsResult.ColumnValue)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | none |
| is\_null | [ bool](#bool) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.double\_value | [ double](#double) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.int\_value | [ int64](#int64) | Integer value for values that fit within the signed 64-bit range \[-9223372036854775808, 9223372036854775807]. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.time\_value | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.big\_int\_value | [ string](#string) | Arbitrary-precision integer encoded as a base-10 string, used for values that exceed the signed 64-bit range. Covers DuckDB HUGEINT (128-bit), ClickHouse Int128/UInt128/Int256/UInt256, and similar wide integer types from other warehouses. Consumers should parse this with an arbitrary-precision library (e.g., Go's math/big.Int, Java's BigInteger, Python's int). |
### FetchMetricsResult.MetricsRow
(synq.agent.dwh.v1.FetchMetricsResult.MetricsRow)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | ------------------------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segment.segment | [optional string](#string) | none |
| column\_values | [repeated ColumnValue](#columnvalue) | none |
### FetchMetricsResult.QueryRows
(synq.agent.dwh.v1.FetchMetricsResult.QueryRows)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| rows | [repeated MetricsRow](#metricsrow) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_query\_id.query\_id | [optional string](#string) | none |
### FetchSegmentsCommand
(synq.agent.dwh.v1.FetchSegmentsCommand)
| Field | Type | Description |
| ---------- | ---------------------- | ----------- |
| sql\_query | [ SqlQuery](#sqlquery) | none |
### FetchSegmentsResult
(synq.agent.dwh.v1.FetchSegmentsResult)
| Field | Type | Description |
| ----- | ---------------------------------- | ----------- |
| rows | [repeated SegmentRow](#segmentrow) | none |
### FetchSegmentsResult.SegmentRow
(synq.agent.dwh.v1.FetchSegmentsResult.SegmentRow)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ------------------------ | ----------- |
| segment | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_count.count | [optional int64](#int64) | none |
### FetchTableStatsCommand
(synq.agent.dwh.v1.FetchTableStatsCommand)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| scope\_filter | [ ScopeFilter](#scopefilter) | Scope filter defining which tables to collect stats for. For a single-table monitor, set a single include rule with exact database/schema/table. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_command\_context.command\_context | [optional string](#string) | Application-specific context, echoed back in the result (mirrors FetchMetricsCommand). |
### SqlQuery
(synq.agent.dwh.v1.SqlQuery)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| sql | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_limit\_results.limit\_results | [optional int64](#int64) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_query\_id.query\_id | [optional string](#string) | none |
### GenerateConnectionsYamlRequest
(synq.agent.dwh.v1.GenerateConnectionsYamlRequest)
Request to generate YAML configuration from data warehouse connections.
| Field | Type | Description |
| ----------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| connections | [map ConnectionsEntry](#connectionsentry) | Map of connection ID to Connection configuration. Typically obtained from ListConnectionsResponse. Note: Validation is disabled for this field since Connection values may have empty credentials (which will be replaced with env var placeholders). Connection ID validation is handled in the service implementation. |
### GenerateConnectionsYamlRequest.ConnectionsEntry
(synq.agent.dwh.v1.GenerateConnectionsYamlRequest.ConnectionsEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Connection](#connection) | none |
### GenerateConnectionsYamlResponse
(synq.agent.dwh.v1.GenerateConnectionsYamlResponse)
Response containing the generated YAML configuration.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| yaml | [ string](#string) | Generated YAML configuration string. Can be written directly to a file and used by DWH Agent or Coalesce Quality Scout. Includes header comments with documentation links. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error.error | [optional string](#string) | Error message if YAML generation failed. If set, the yaml field should be ignored. |
### ListConnectionsRequest
(synq.agent.dwh.v1.ListConnectionsRequest)
| Field | Type | Description |
| --------------- | -------------------------- | ------------------------------------------------------------------------------------------------------ |
| connection\_ids | [repeated string](#string) | Optional filter to only return connections with these ids. If empty, all DWH connections are returned. |
### ListConnectionsResponse
(synq.agent.dwh.v1.ListConnectionsResponse)
| Field | Type | Description |
| ----------- | ----------------------------------------- | ----------- |
| connections | [map ConnectionsEntry](#connectionsentry) | none |
### ListConnectionsResponse.ConnectionsEntry
(synq.agent.dwh.v1.ListConnectionsResponse.ConnectionsEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Connection](#connection) | none |
### AgentTaskResponse
(synq.agent.dwh.v1.AgentTaskResponse)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- |
| connection\_id | [ string](#string) | none |
| task\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error.error | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_task\_data.task\_data | [optional AgentTaskData](#agenttaskdata) | none |
### ConnectRequest
(synq.agent.dwh.v1.ConnectRequest)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) message.hello | [ Hello](#hello) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) message.log | [ Log](#log) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) message.task\_response | [ AgentTaskResponse](#agenttaskresponse) | none |
### ConnectResponse
(synq.agent.dwh.v1.ConnectResponse)
| Field | Type | Description |
| ----- | -------------------------------- | ----------- |
| tasks | [repeated AgentTask](#agenttask) | none |
### Hello
(synq.agent.dwh.v1.Hello)
| Field | Type | Description |
| ---------------------- | ---------------------------------------------------- | ----------- |
| name | [ string](#string) | none |
| build\_version | [ string](#string) | none |
| build\_time | [ string](#string) | none |
| available\_connections | [repeated AvailableConnection](#availableconnection) | none |
### Hello.AvailableConnection
(synq.agent.dwh.v1.Hello.AvailableConnection)
| Field | Type | Description |
| -------------- | -------------------------- | ----------------------------------------------------------------------------------- |
| connection\_id | [ string](#string) | Identifier which will receive commands |
| name | [ string](#string) | User provided connection name |
| disabled | [ bool](#bool) | Indicates that agent has that connection disabled |
| type | [ string](#string) | Type of the DWH, e.g. bigquery, duckdb, clickhouse |
| instance | [ string](#string) | This will be hostname in most cases |
| databases | [repeated string](#string) | Enabled databases to query if connection supports multiple databases, can be empty. |
### Log
(synq.agent.dwh.v1.Log)
| Field | Type | Description |
| ------- | ------------------------ | ----------- |
| time | [ Timestamp](#timestamp) | none |
| message | [ string](#string) | none |
| level | [ LogLevel](#loglevel) | none |
### Connection
(synq.agent.dwh.v1.Connection)
Connection represents a database connection configuration
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------ |
| name | [ string](#string) | Name of the connection |
| disabled | [ bool](#bool) | none |
| parallelism | [ int32](#int32) | How many queries to DWH can be executed in parallel, defaults to 2 |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.bigquery | [ BigQueryConf](#bigqueryconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.clickhouse | [ ClickhouseConf](#clickhouseconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.databricks | [ DatabricksConf](#databricksconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.mysql | [ MySQLConf](#mysqlconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.postgres | [ PostgresConf](#postgresconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.redshift | [ RedshiftConf](#redshiftconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.snowflake | [ SnowflakeConf](#snowflakeconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.trino | [ TrinoConf](#trinoconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.mssql | [ MSSQLConf](#mssqlconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.oracle | [ OracleConf](#oracleconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.duckdb | [ DuckDBConf](#duckdbconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.athena | [ AthenaConf](#athenaconf) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.fabric | [ FabricConf](#fabricconf) | none |
### ReconciliationRunState
(synq.agent.recon.v1.ReconciliationRunState)
ReconciliationRunState describes the lifecycle of a single reconciliation
run. Returned by RunStateService.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | Suite identifier this run belongs to. For managed suites this is the suite\_name; for ad-hoc suites this is the generated UUID. |
| deployment\_id | [ string](#string) | Deployment identifier (UUIDv7) if the run belongs to a promoted deployment. Empty for ad-hoc and legacy managed-suite runs. |
| run\_id | [ string](#string) | Stable opaque identifier of this specific run occurrence (UUIDv7). |
| status | [ ReconciliationRunStatus](#reconciliationrunstatus) | none |
| trigger | [ ReconciliationRunTrigger](#reconciliationruntrigger) | none |
| scheduled\_at | [ Timestamp](#timestamp) | When this run was scheduled to start (cron occurrence time, or now() for ad-hoc). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_at.started\_at | [optional Timestamp](#timestamp) | When the worker actually picked up the run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_finished\_at.finished\_at | [optional Timestamp](#timestamp) | When the run reached a terminal status (SUCCEEDED / FAILED / CANCELLED). |
| last\_updated\_at | [ Timestamp](#timestamp) | Last time this row was updated. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Actor that initiated the run (user or system). Populated for ADHOC and API triggers. |
| failure\_category | [ ReconciliationRunFailureCategory](#reconciliationrunfailurecategory) | Set only when status is FAILED. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_failure\_details.failure\_details | [optional string](#string) | Raw failure detail string. Set only when status is FAILED. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_invocation\_id.invocation\_id | [optional string](#string) | Identifier of the audit log this run produced. Empty when the run failed before the worker emitted an audit log (e.g. binding-resolution failure on a misconfigured deployment, or the run was cancelled). When set, pass to AuditLogService.GetAuditLog to retrieve the full per-reconciliation results for this run. |
### AggregateConfig
(synq.agent.recon.v1.AggregateConfig)
AggregateConfig defines aggregate comparison settings.
Used when mode is AGGREGATE to compare grouped measures between source and target.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| measures | [repeated Measure](#measure) | Measures to compare between source and target. Each measure defines a column and one or more aggregate functions to apply. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_thresholds.thresholds | [optional ThresholdConfig](#thresholdconfig) | Tolerance thresholds for aggregate comparisons. When not set, exact match is required for all measures. |
| group\_columns | [repeated string](#string) | Columns defining the drill-down hierarchy for aggregate comparison. Falls back to key\_column if not set. |
Single column: flat GROUP BY comparison. group\_columns: \["region"] → GROUP BY region
Multiple columns: cumulative GROUP BY drill-down, pruning matched groups at each level to focus on divergent branches. group\_columns: \["region", "city", "store"] → Level 0: GROUP BY region → Level 1: GROUP BY region, city (only for mismatched regions) → Level 2: GROUP BY region, city, store (only for mismatched cities) |
### BisectionConfig
(synq.agent.recon.v1.BisectionConfig)
BisectionConfig controls the bisection drill-down algorithm that recursively
splits the key range to locate individual mismatched rows.
Only used in ROW\_CHECKSUM mode.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| enabled | [ bool](#bool) | Whether bisection drill-down is enabled. When false, only the quick-check (count + checksum) runs — mismatches are detected but not localized to specific rows. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_factor.factor | [optional int32](#int32) | Branching factor: how many segments each level is split into. Higher values find mismatches faster (fewer levels) but issue more queries per level. Default: 32. Typical range: 4–64. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_threshold.threshold | [optional int32](#int32) | Row count threshold: stop bisecting when a segment has fewer rows than this. Lower values find more precise mismatch locations but issue more queries. Default: 16384. Set to 1 to drill down to individual rows. |
| strategy | [ SegmentationStrategy](#segmentationstrategy) | Segmentation strategy for splitting key ranges. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time\_column.time\_column | [optional string](#string) | Column for time-based partitioning. Required when strategy is TIME. Must be a timestamp, date, or datetime column in the dataset. |
| time\_granularity | [ TimeGranularity](#timegranularity) | Granularity for time-based segmentation. Default: DAY. Controls the width of each time bucket when strategy is TIME. |
### ConnectionQueries
(synq.agent.recon.v1.ConnectionQueries)
ConnectionQueries associates SQL queries with a specific connection.
Used for setup and teardown blocks at both suite and reconciliation level.
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| connection | [ string](#string) | Connection name to execute these queries on. Must reference a connection configured in the runner's connection map. |
| queries | [repeated string](#string) | SQL queries to execute in order on this connection. |
### ErrorHandlingConfig
(synq.agent.recon.v1.ErrorHandlingConfig)
ErrorHandlingConfig controls retry and timeout behavior for database queries.
Applies to all queries within a reconciliation (setup, comparison, teardown).
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_query\_timeout.query\_timeout | [optional Duration](#duration) | Per-query timeout. When a query exceeds this duration, it is cancelled. Default: no per-query limit (only the global run timeout applies). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_max\_retries.max\_retries | [optional int32](#int32) | Maximum retry attempts for transient query failures. The total number of attempts is max\_retries + 1 (initial + retries). Default: 2. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_retry\_initial\_delay.retry\_initial\_delay | [optional Duration](#duration) | Initial backoff delay before the first retry. Subsequent retries multiply this by retry\_backoff\_factor. Default: 1s. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_retry\_backoff\_factor.retry\_backoff\_factor | [optional double](#double) | Backoff multiplier applied after each retry. Delay for attempt N = retry\_initial\_delay \* retry\_backoff\_factor^(N-1). Must be ≥ 1.0 to ensure delays don't decrease. Default: 2.0. |
### Measure
(synq.agent.recon.v1.Measure)
Measure defines a column and aggregate function(s) to compare
between source and target datasets.
A single measure with multiple functions expands into multiple comparisons
(e.g., column="amount" functions=\[SUM, AVG] produces "SUM(amount)" and "AVG(amount)").
| Field | Type | Description |
| --------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| column | [ string](#string) | Column name to aggregate. Must exist in both source and target datasets (after column mapping is applied). |
| functions | [repeated AggregateFunction](#aggregatefunction) | Aggregate functions to apply to this column. Multiple functions produce multiple measure comparisons from one column. |
### Reconciliation
(synq.agent.recon.v1.Reconciliation)
Reconciliation defines a single reconciliation scenario comparing data
between a source and target dataset. Each reconciliation runs independently
and produces its own pass/mismatch/fail result.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Unique machine identifier within the suite. Alphanumerics, hyphens, and underscores. May be a UUID. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Human-readable title. Displayed in reports. Defaults to name when not set. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Optional longer description explaining what this reconciliation validates. |
| source | [ Dataset](#dataset) | Source dataset to compare from — the "expected" or "authoritative" side. |
| target | [ Dataset](#dataset) | Target dataset to compare against — the "actual" or "replicated" side. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_key\_column.key\_column | [optional string](#string) | Deprecated: use key\_columns instead. Single primary key column used for ordering and segmentation during bisection. Retained for backward compatibility — existing single-key configs and stored audit logs keep working. When key\_columns is set, this field is ignored. Readers should resolve the effective key via key\_columns first, falling back to this. |
| key\_columns | [repeated string](#string) | Ordered list of key columns used for ordering and segmentation during bisection. Supports composite (multi-column) keys; the bisection orders and range-filters on the column tuple so the engine can prune via a matching primary key / index. A single-element list is equivalent to setting key\_column. Required for ROW\_CHECKSUM and ROW\_COUNT modes (this or the deprecated key\_column). Optional in AGGREGATE mode when group\_columns provides the grouping key. |
| mode | [ ReconciliationMode](#reconciliationmode) | Comparison mode controlling how source and target are compared. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_hash\_algorithm.hash\_algorithm | [optional HashAlgorithm](#hashalgorithm) | Hash algorithm for row checksums in ROW\_CHECKSUM mode. When unset, auto-negotiates the best common algorithm between the source and target database dialects. |
| column\_mapping | [repeated ColumnMapping](#columnmapping) | Explicit column name mapping between source and target. Only columns with different names need mapping — identical names (or case-insensitive matches) are matched automatically. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_case\_insensitive.case\_insensitive | [optional bool](#bool) | When true, automatically matches columns differing only in letter case (e.g., user\_id matches USER\_ID). Defaults to true when not set. Set to false to require exact case matching. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bisection.bisection | [optional BisectionConfig](#bisectionconfig) | Bisection drill-down configuration for ROW\_CHECKSUM mode. Controls how the key range is recursively split to locate mismatches. When not set, uses sensible defaults (factor=32, threshold=16384). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reporting.reporting | [optional ReportingConfig](#reportingconfig) | Reporting output configuration controlling how much detail is included in the audit log for mismatched rows. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_aggregate.aggregate | [optional AggregateConfig](#aggregateconfig) | Aggregate comparison settings. Required when mode is AGGREGATE. Defines which measures to compare and tolerance thresholds. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error\_handling.error\_handling | [optional ErrorHandlingConfig](#errorhandlingconfig) | Error handling and retry configuration for database queries. Controls timeouts and retry behavior for transient failures. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_window\.window | [optional WindowConfig](#windowconfig) | Time window for incremental comparison. When set, automatically provides a \{\{window\_start}} template variable for filtering queries to a recent time range. |
| setup | [repeated ConnectionQueries](#connectionqueries) | Setup queries run before this specific reconciliation. Executes after suite-level setup but before data comparison. |
| teardown | [repeated ConnectionQueries](#connectionqueries) | Teardown queries run after this specific reconciliation completes. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_teardown\_on\_failure.teardown\_on\_failure | [optional bool](#bool) | Whether teardown runs on failure for this reconciliation. When not set, inherits from suite-level teardown\_on\_failure. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ignore\_setup\_errors.ignore\_setup\_errors | [optional bool](#bool) | When true, logs setup errors as warnings and continues. When not set, inherits from suite-level ignore\_setup\_errors. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cutoff.cutoff | [optional CutoffConfig](#cutoffconfig) | Dynamic cutoff filter for sync reconciliation. Derives a watermark from actual data to exclude rows not yet synced. Applied as WHERE filter to both source and target queries at runtime. |
| annotations | [repeated Annotation](#annotation) | Case-level annotations. Merged with suite-level annotations and deployment-level annotations at promote time, then exposed on the case asset (PromotedReconCaseMetadata). |
### ReconciliationSuite
(synq.agent.recon.v1.ReconciliationSuite)
ReconciliationSuite is the root configuration for a reconciliation suite.
It defines template variables and one or more reconciliation scenarios
that compare data between source and target databases.
Database connections are configured separately and referenced by name.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Short machine identifier for the suite. Unique machine identifier for the suite, used as the stable key for tracking runs over time. Alphanumerics, hyphens, and underscores. May be a UUID. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Human-readable title for the suite. Displayed in dashboards and reports. Defaults to name when not set. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Optional longer description of the suite's purpose. |
| reconciliations | [repeated Reconciliation](#reconciliation) | Reconciliation scenarios to execute. Each reconciliation compares data between a source and target dataset. |
| setup | [repeated ConnectionQueries](#connectionqueries) | Setup queries run once before all reconciliations begin. Use for creating temp tables, loading fixtures, or preparing the environment. Queries execute in order; all connections run sequentially. |
| teardown | [repeated ConnectionQueries](#connectionqueries) | Teardown queries run once after all reconciliations complete. Use for cleaning up temp tables or restoring state. |
| teardown\_on\_failure | [ bool](#bool) | Whether teardown runs even when reconciliations fail with infrastructure errors. When false (default), teardown is skipped on failure to preserve state for debugging. |
| ignore\_setup\_errors | [ bool](#bool) | When true, logs setup query errors as warnings and continues execution instead of aborting the run. Useful when setup creates IF NOT EXISTS objects. |
| variables | [map VariablesEntry](#variablesentry) | Template variables for query interpolation via \{\{variable\_name}} syntax. Values can be literal strings or template expressions: - Literal: "2026-01-01" - Time expression: "\{\{today - 30d}}", "\{\{now - 2h}}" - Built-in: "\{\{now}}", "\{\{today}}", "\{\{window\_start}}" Variables are resolved once at the start of the run and frozen. |
| strict\_time\_references | [ bool](#bool) | When true, time reference detection (e.g. NOW(), CURRENT\_DATE, GETDATE() in queries) returns an error instead of a warning. Prevents non-deterministic queries that produce different results on each run. |
| annotations | [repeated Annotation](#annotation) | Suite-level annotations. Each annotation is a name with zero or more string values. Applied to the deployed suite asset and inherited by every reconciliation case under the suite. Merged with per-case annotations and deployment-level annotations at promote time — the final, deduplicated list is exposed on PromotedReconSuiteMetadata / PromotedReconCaseMetadata and surfaced to the rest of the SYNQ platform via EntityAnnotations. |
### ReconciliationSuite.VariablesEntry
(synq.agent.recon.v1.ReconciliationSuite.VariablesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### ReportingConfig
(synq.agent.recon.v1.ReportingConfig)
ReportingConfig controls the level of detail included in reconciliation output
for mismatched rows. Higher detail levels reveal more data but may have
privacy implications.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| level | [ MismatchDetailLevel](#mismatchdetaillevel) | Output detail level for mismatched rows. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sample\_limit.sample\_limit | [optional int32](#int32) | Maximum number of sample rows to include in output per mismatch segment. Limits the size of the audit log when there are many mismatches. When not set, all mismatched rows within the reporting level are included. |
| consent\_acknowledged | [ bool](#bool) | Explicit acknowledgment that detailed row data may be included in the audit log. Required when level is DETAILED to prevent accidental exposure of sensitive data. The caller must set this to true to confirm they understand the privacy implications. |
### WindowConfig
(synq.agent.recon.v1.WindowConfig)
WindowConfig defines a time window for incremental comparison.
When configured, automatically provides a \{\{window\_start}} template variable
that resolves to (current\_time - lookback). Use this in query WHERE clauses
to limit comparison to recent data.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_column.column | [optional string](#string) | Column being windowed. Informational metadata for the audit trail — the actual filtering is done via the \{\{window\_start}} variable in your query WHERE clause. |
| lookback | [ Duration](#duration) | How far back to look from the current time. Defines the window as \[now - lookback, now]. Examples: "336h" (14 days), "2h", "720h" (30 days). |
| strategy | [ WindowStrategy](#windowstrategy) | Windowing strategy controlling how boundaries are computed. |
### CronSchedule
(synq.agent.recon.v1.CronSchedule)
| Field | Type | Description |
| ---------- | ------------------ | -------------------------------------------------- |
| expression | [ string](#string) | Standard cron expression (e.g. "0 \*/6 \* \* \*"). |
### ICalSchedule
(synq.agent.recon.v1.ICalSchedule)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| recurrence\_rule | [ string](#string) | RFC 5545 RRULE recurrence rule (e.g. "FREQ=MONTHLY;BYDAY=TH;BYSETPOS=-1"). DTSTART should be set via the dtstart field below rather than inline in the rule. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dtstart.dtstart | [optional Timestamp](#timestamp) | Anchor time for the recurrence rule. Wall-clock time interpreted in the schedule's timezone. Defines when the schedule starts and aligns occurrences. If not set and no DTSTART is present in the recurrence\_rule, defaults to now(). |
### ReconciliationConfigSummary
(synq.agent.recon.v1.ReconciliationConfigSummary)
Summary of a single reconciliation within a suite config (for listing without parsing full config).
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | none |
| source\_connection | [ string](#string) | none |
| target\_connection | [ string](#string) | none |
| mode | [ ReconciliationMode](#reconciliationmode) | none |
| annotations | [repeated Annotation](#annotation) | Resolved annotation list for this case. For suite-config summaries this is suite-level annotations + case-level annotations (deduped). For deployment summaries the deployment-level overlay is also merged in. Already deduplicated by (name, value); ready for direct display. |
### SuiteSchedule
(synq.agent.recon.v1.SuiteSchedule)
Schedule configuration for managed suites.
| Field | Type | Description |
| --------------------------------------------------------------------------------------- | ------------------------------ | --------------------------------------------------------------------- |
| timezone | [ string](#string) | IANA timezone, e.g. "Europe/Warsaw". Required when a schedule is set. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.cron | [ CronSchedule](#cronschedule) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.ical | [ ICalSchedule](#icalschedule) | none |
### ParseYamlRequest
(synq.agent.recon.v1.ParseYamlRequest)
| Field | Type | Description |
| ----- | ------------------ | ---------------------------- |
| yaml | [ string](#string) | YAML config string to parse. |
### ParseYamlResponse
(synq.agent.recon.v1.ParseYamlResponse)
| Field | Type | Description |
| ----- | -------------------------------------------- | ------------------------------- |
| suite | [ ReconciliationSuite](#reconciliationsuite) | The parsed suite configuration. |
### RenderYamlRequest
(synq.agent.recon.v1.RenderYamlRequest)
| Field | Type | Description |
| ----- | -------------------------------------------- | ------------------------------------------ |
| suite | [ ReconciliationSuite](#reconciliationsuite) | The suite configuration to render as YAML. |
### RenderYamlResponse
(synq.agent.recon.v1.RenderYamlResponse)
| Field | Type | Description |
| ----- | ------------------ | -------------------------------- |
| yaml | [ string](#string) | The rendered YAML config string. |
### ColumnMapping
(synq.agent.recon.v1.ColumnMapping)
ColumnMapping maps a source column name to a target column name.
Used when source and target use different naming conventions for the same data
(e.g., snake\_case vs SCREAMING\_SNAKE\_CASE, or completely different names).
Only columns with different names need explicit mapping — columns with
identical names (or case-insensitive matches when case\_insensitive is true)
are matched automatically.
| Field | Type | Description |
| ------ | ------------------ | ------------------------------------------------ |
| source | [ string](#string) | Column name in the source dataset. |
| target | [ string](#string) | Corresponding column name in the target dataset. |
### Dataset
(synq.agent.recon.v1.Dataset)
Dataset defines a source or target dataset for reconciliation.
A dataset specifies which connection to use and how to select data —
either via a raw SQL query or by referencing a table with optional column filtering.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| connection | [ string](#string) | Name of the connection to use. Must reference a connection configured in the runner's connection map. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data\_source.query | [ string](#string) | Raw SQL query returning the dataset. Should be a SELECT or WITH (CTE) statement. Supports template variable interpolation via \{\{variable\_name}} syntax. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data\_source.table | [ TableReference](#tablereference) | Table reference with optional column selection. Automatically generates a SELECT query from the table metadata. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_as\_of.as\_of | [optional string](#string) | Time-travel timestamp for snapshot queries (e.g., "2026-02-01 00:00:00"). When set, wraps the query with database-specific time-travel syntax: - Snowflake: AT(TIMESTAMP => '\') - BigQuery: FOR SYSTEM\_TIME AS OF TIMESTAMP '\' - Databricks: TIMESTAMP AS OF '\' Has no effect on databases that don't support time-travel. |
### TableReference
(synq.agent.recon.v1.TableReference)
TableReference specifies a table and optional column filtering.
Use this instead of a raw query when you want to compare all (or most) columns
of a table without writing SQL.
`name` is the table or view name (e.g., "orders", "fact\_sales").
`database` and `schema` are optional namespace qualifiers.
The actual SQL FQN is generated at runtime using the appropriate dialect quoting.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Table or view name (e.g., "orders", "fact\_sales"). Required — this is the actual object name. |
| columns | [repeated string](#string) | Explicit list of columns to include in the comparison. When set, only these columns are selected from the table. Mutually exclusive with exclude\_columns. |
| exclude\_columns | [repeated string](#string) | Columns to exclude from the comparison. All columns except these are selected (resolved at runtime via table metadata). Useful for skipping volatile columns (e.g., updated\_at, etl\_batch\_id). Mutually exclusive with columns. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database/catalog name (e.g., "PROD\_RAW", "my\_project"). Maps to: Snowflake database, BigQuery project, Databricks catalog. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schema.schema | [optional string](#string) | Schema/dataset name (e.g., "public", "analytics"). Maps to: Snowflake schema, BigQuery dataset, Databricks schema. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_where.where | [optional string](#string) | Row filter — appended as WHERE clause to the generated SELECT. Example: "created\_at ≥ '2024-01-01' AND status = 'active'" |
### AggregateDrillChild
(synq.agent.recon.v1.AggregateDrillChild)
AggregateDrillChild represents a single divergent group within a drill-down level.
| Field | Type | Description |
| --------------------- | ---------------------------------------------------- | ------------------------------------------------ |
| key | [ Struct](#struct) | Group key values (column name -> value). |
| type | [ AggregateDivergenceType](#aggregatedivergencetype) | Type of divergence. |
| source\_values | [map SourceValuesEntry](#sourcevaluesentry) | Source measure values (measure key -> value). |
| target\_values | [map TargetValuesEntry](#targetvaluesentry) | Target measure values (measure key -> value). |
| differences | [ MeasureDifferences](#measuredifferences) | All difference variants computed for this group. |
| threshold\_evaluation | [ ThresholdEvaluation](#thresholdevaluation) | Threshold evaluation results for this group. |
| source\_query | [ string](#string) | Investigation query for source data. |
| target\_query | [ string](#string) | Investigation query for target data. |
| drill\_down | [ AggregateDrillNode](#aggregatedrillnode) | Further drill-down into this divergent group. |
### AggregateDrillChild.SourceValuesEntry
(synq.agent.recon.v1.AggregateDrillChild.SourceValuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### AggregateDrillChild.TargetValuesEntry
(synq.agent.recon.v1.AggregateDrillChild.TargetValuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### AggregateDrillNode
(synq.agent.recon.v1.AggregateDrillNode)
AggregateDrillNode represents a node in the hierarchical aggregate drill-down tree.
| Field | Type | Description |
| --------------- | ---------------------------------------------------- | -------------------------------------------------- |
| level | [ int32](#int32) | Drill-down level (0-based). |
| group\_column | [ string](#string) | Group column used at this level. |
| total\_groups | [ int32](#int32) | Total groups at this level. |
| matched\_groups | [ int32](#int32) | Number of matched groups at this level. |
| children | [repeated AggregateDrillChild](#aggregatedrillchild) | Divergent children (mismatched or missing groups). |
### AggregateStageResult
(synq.agent.recon.v1.AggregateStageResult)
AggregateStageResult is the result for an aggregate\_check stage.
| Field | Type | Description |
| -------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| total\_groups | [ int32](#int32) | Top-level (first group column) total group count. With a multi-level drill-down this is the number of distinct first-level groups, NOT the number of leaf groups. Invariant: total\_groups == matched\_groups + divergent\_groups. |
| matched\_groups | [ int32](#int32) | Top-level groups that matched — directly, or because their whole subtree resolved. Same level as total\_groups. |
| mismatch\_groups | [ int32](#int32) | Leaf-level groups with value differences (deepest drill level). NOT comparable to total\_groups: one divergent top-level group can contain many divergent leaves. For a same-level "X of Y diverged" ratio use divergent\_groups / total\_groups; use these leaf counts for detail. |
| missing\_source | [ int32](#int32) | Leaf-level groups present in target but missing in source. |
| missing\_target | [ int32](#int32) | Leaf-level groups present in source but missing in target. |
| match | [ bool](#bool) | Overall match result. |
| early\_termination\_reason | [ string](#string) | Reason if aggregate check terminated early. |
| drill\_down | [ AggregateDrillNode](#aggregatedrillnode) | Hierarchical drill-down tree for aggregate comparison. |
| divergent\_groups | [ int32](#int32) | Top-level groups that diverged (counterpart of matched\_groups, same level as total\_groups). This is the same-level numerator for a "divergent\_groups of total\_groups diverged" summary — unlike the leaf-level mismatch\_groups / missing\_\* counts above, which can exceed total\_groups in a multi-level drill. |
### AuditLog
(synq.agent.recon.v1.AuditLog)
AuditLog is the root structure for a reconciliation run audit.
It captures all operations performed during a synq-recon reconciliation run.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| version | [ string](#string) | Schema version. Must be "1". |
| invocation\_id | [ string](#string) | Unique identifier for this invocation/run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_invocation\_id.parent\_invocation\_id | [optional string](#string) | Invocation ID of the parent run this continues from. Set when this run resumes or drills deeper into a previous run's results. |
| suite\_name | [ string](#string) | Suite machine identifier (promoted from suite.name). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_title.suite\_title | [optional string](#string) | Human-readable title (promoted from suite.title). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_description.suite\_description | [optional string](#string) | Suite description (promoted from suite.description). |
| started\_at | [ Timestamp](#timestamp) | When the run started. |
| completed\_at | [ Timestamp](#timestamp) | When the run completed. |
| duration | [ Duration](#duration) | Total run duration. |
| status | [ AuditOutcome](#auditoutcome) | Overall execution status derived from individual reconciliation outcomes. |
| summary | [ AuditSummary](#auditsummary) | Aggregated counts derived from individual reconciliation results. |
| reconciliations | [repeated ReconciliationAudit](#reconciliationaudit) | Audit records for each reconciliation executed. |
| meta | [ AuditMeta](#auditmeta) | Build and environment metadata for the synq-recon binary. |
| config\_file | [ string](#string) | Path to the configuration file used. |
| suite | [ ReconciliationSuite](#reconciliationsuite) | Full suite configuration snapshot as executed. Contains all reconciliation definitions, variables, thresholds, etc. |
| resolved\_variables | [map ResolvedVariablesEntry](#resolvedvariablesentry) | Resolved template variable values used for query interpolation. Contains the actual values after template evaluation (e.g. "\{\{today - 30d}}" resolved to "2026-01-27"). |
| warnings | [repeated string](#string) | Suite-level warnings detected during config validation. |
| total\_stats | [ QueryStats](#querystats) | Aggregated query execution statistics across all queries in this run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_environment.environment | [optional string](#string) | Name of the environment used for this run. Empty for direct/unmanaged runs where no environment was applied. |
| resolved\_table\_references | [map ResolvedTableReferencesEntry](#resolvedtablereferencesentry) | Effective table references after environment overrides were applied. Keyed by "reconciliation\_name.source" or "reconciliation\_name.target". Only populated when an environment was active and overrides were applied. The suite field (14) still contains the original pre-override config. |
### AuditLog.ResolvedTableReferencesEntry
(synq.agent.recon.v1.AuditLog.ResolvedTableReferencesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### AuditLog.ResolvedVariablesEntry
(synq.agent.recon.v1.AuditLog.ResolvedVariablesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### AuditMeta
(synq.agent.recon.v1.AuditMeta)
AuditMeta holds build and environment metadata for the synq-recon binary.
| Field | Type | Description |
| ----------- | ------------------ | ------------------------------------------------- |
| version | [ string](#string) | Module version or tag (e.g. v1.2.3). |
| vcs\_commit | [ string](#string) | VCS revision hash. |
| vcs\_time | [ string](#string) | VCS commit timestamp (RFC3339). |
| vcs\_dirty | [ bool](#bool) | True if the working tree had uncommitted changes. |
| go\_version | [ string](#string) | Go toolchain version used to build the binary. |
### AuditSummary
(synq.agent.recon.v1.AuditSummary)
AuditSummary holds aggregated counts derived from individual reconciliation results.
| Field | Type | Description |
| -------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| overall\_match | [ bool](#bool) | True when every reconciliation matched (exactly or within threshold). False when any reconciliation failed or had an exceeding mismatch. |
| total | [ int32](#int32) | Total number of reconciliations executed. |
| matched | [ int32](#int32) | Number of reconciliations that completed and matched exactly. |
| matched\_within\_threshold | [ int32](#int32) | Number of reconciliations that had differences within configured thresholds. These are warning-level outcomes — data differs but within acceptable tolerance. |
| mismatched | [ int32](#int32) | Number of reconciliations that completed but found data differences exceeding thresholds (or no thresholds configured). |
| failed | [ int32](#int32) | Number of reconciliations that encountered an infrastructure error. |
| errors | [repeated string](#string) | Error messages collected from failed reconciliations. |
### BisectionStageResult
(synq.agent.recon.v1.BisectionStageResult)
BisectionStageResult is the result for a bisection\_drill stage.
| Field | Type | Description |
| -------------------------- | -------------------------------------------------- | ----------------------------------------------------------- |
| total\_segments | [ int32](#int32) | Total number of segments processed. |
| mismatch\_count | [ int32](#int32) | Number of mismatched leaf segments. |
| error\_count | [ int32](#int32) | Number of segments that encountered errors. |
| max\_depth | [ int32](#int32) | Maximum depth reached in the segment tree. |
| early\_termination\_reason | [ string](#string) | Reason if bisection terminated early. |
| statistics | [ BisectionStatistics](#bisectionstatistics) | Detailed tree statistics. |
| mismatch\_leaves | [repeated MismatchLeafDetail](#mismatchleafdetail) | Details for each mismatched leaf segment. |
| investigation\_queries | [repeated InvestigationQuery](#investigationquery) | Merged investigation queries for adjacent mismatch regions. |
### BisectionStatistics
(synq.agent.recon.v1.BisectionStatistics)
BisectionStatistics holds statistics about the bisection segment tree.
| Field | Type | Description |
| ---------------------- | ----------------------------------------------------- | -------------------------------------------------- |
| total\_nodes | [ int32](#int32) | none |
| matched\_nodes | [ int32](#int32) | none |
| mismatched\_nodes | [ int32](#int32) | none |
| leaf\_nodes | [ int32](#int32) | none |
| intermediate\_nodes | [ int32](#int32) | none |
| matched\_leaves | [ int32](#int32) | none |
| mismatched\_leaves | [ int32](#int32) | none |
| depth\_distribution | [map DepthDistributionEntry](#depthdistributionentry) | Number of segments at each depth level. |
| mismatch\_by\_depth | [map MismatchByDepthEntry](#mismatchbydepthentry) | Number of mismatched segments at each depth level. |
| per\_depth | [map PerDepthEntry](#perdepthentry) | Detailed per-depth statistics. |
| total\_source\_rows | [ int64](#int64) | none |
| total\_target\_rows | [ int64](#int64) | none |
| mismatch\_source\_rows | [ int64](#int64) | none |
| mismatch\_target\_rows | [ int64](#int64) | none |
### BisectionStatistics.DepthDistributionEntry
(synq.agent.recon.v1.BisectionStatistics.DepthDistributionEntry)
| Field | Type | Description |
| ----- | ---------------- | ----------- |
| key | [ int32](#int32) | none |
| value | [ int32](#int32) | none |
### BisectionStatistics.MismatchByDepthEntry
(synq.agent.recon.v1.BisectionStatistics.MismatchByDepthEntry)
| Field | Type | Description |
| ----- | ---------------- | ----------- |
| key | [ int32](#int32) | none |
| value | [ int32](#int32) | none |
### BisectionStatistics.PerDepthEntry
(synq.agent.recon.v1.BisectionStatistics.PerDepthEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ DepthStats](#depthstats) | none |
### CutoffResult
(synq.agent.recon.v1.CutoffResult)
CutoffResult captures the runtime resolution of a cutoff filter.
Stored in the audit log to provide full transparency into how the cutoff
was derived and applied.
| Field | Type | Description |
| ----------------- | ------------------ | ------------------------------------------------------------------------------------------------------------- |
| source\_watermark | [ string](#string) | Watermark value derived from the source dataset. Empty when cutoff was configured for target-only derivation. |
| target\_watermark | [ string](#string) | Watermark value derived from the target dataset. Empty when cutoff was configured for source-only derivation. |
| cutoff\_value | [ string](#string) | Final cutoff value after combining source/target watermarks and applying truncation and offset transforms. |
| source\_where | [ string](#string) | WHERE clause applied to the source query. |
| target\_where | [ string](#string) | WHERE clause applied to the target query. |
### DatasetInfo
(synq.agent.recon.v1.DatasetInfo)
DatasetInfo captures runtime information about a source or target dataset.
| Field | Type | Description |
| ---------- | ------------------ | -------------------------------------------------------------------- |
| connection | [ string](#string) | Connection name used. |
| dialect | [ string](#string) | Database dialect detected at runtime (e.g. "postgres", "snowflake"). |
| query | [ string](#string) | Resolved SQL query actually executed (after variable interpolation). |
### DepthStats
(synq.agent.recon.v1.DepthStats)
DepthStats holds per-depth-level statistics for the bisection tree.
| Field | Type | Description |
| -------------------- | ---------------- | ----------- |
| total\_rows | [ int64](#int64) | none |
| mismatched\_rows | [ int64](#int64) | none |
| segments | [ int32](#int32) | none |
| mismatched\_segments | [ int32](#int32) | none |
### DiffQueries
(synq.agent.recon.v1.DiffQueries)
DiffQueries holds investigation queries for a mismatch leaf.
| Field | Type | Description |
| ------------ | ------------------ | ---------------------------------------------------------- |
| source\_rows | [ string](#string) | SQL query to retrieve source rows in the mismatch segment. |
| target\_rows | [ string](#string) | SQL query to retrieve target rows in the mismatch segment. |
### InvestigationQuery
(synq.agent.recon.v1.InvestigationQuery)
InvestigationQuery represents a merged diff query covering one or more
adjacent mismatch leaves.
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------------------ |
| min\_key | [ Value](#value) | Minimum key (inclusive). |
| max\_key | [ Value](#value) | Maximum key (exclusive). |
| time\_bucket | [ string](#string) | Time bucket label (for time-based segmentation). |
| leaves\_covered | [ int32](#int32) | Number of mismatch leaves covered by this query. |
| source\_query | [ string](#string) | SQL query to retrieve source rows. |
| target\_query | [ string](#string) | SQL query to retrieve target rows. |
### MeasureDifferences
(synq.agent.recon.v1.MeasureDifferences)
MeasureDifferences holds all difference variants for measure comparisons.
| Field | Type | Description | | | | | | |
| --------------- | ------------------------------------------- | ----------------------------------------------------------------------------------- | --------------- | --- | ------ | - | ------ | -- |
| relative | [map RelativeEntry](#relativeentry) | Relative difference per measure (target - source). Positive means target is larger. | | | | | | |
| absolute | [map AbsoluteEntry](#absoluteentry) | Absolute difference per measure: | target - source | . | | | | |
| pct\_vs\_source | [map PctVsSourceEntry](#pctvssourceentry) | Percentage difference relative to source: | diff | / | source | . | | |
| pct\_vs\_target | [map PctVsTargetEntry](#pctvstargetentry) | Percentage difference relative to target: | diff | / | target | . | | |
| pct\_symmetric | [map PctSymmetricEntry](#pctsymmetricentry) | Symmetric percentage difference: 2\* | diff | / ( | source | + | target | ). |
### MeasureDifferences.AbsoluteEntry
(synq.agent.recon.v1.MeasureDifferences.AbsoluteEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### MeasureDifferences.PctSymmetricEntry
(synq.agent.recon.v1.MeasureDifferences.PctSymmetricEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### MeasureDifferences.PctVsSourceEntry
(synq.agent.recon.v1.MeasureDifferences.PctVsSourceEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### MeasureDifferences.PctVsTargetEntry
(synq.agent.recon.v1.MeasureDifferences.PctVsTargetEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### MeasureDifferences.RelativeEntry
(synq.agent.recon.v1.MeasureDifferences.RelativeEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ double](#double) | none |
### MeasureVerdict
(synq.agent.recon.v1.MeasureVerdict)
MeasureVerdict captures the threshold evaluation result for a single measure.
| Field | Type | Description |
| ---------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------- |
| exceeded | [ bool](#bool) | True when the measure difference exceeds all configured thresholds. |
| reason | [ MeasureVerdictReason](#measureverdictreason) | Explains why the measure was considered within or outside thresholds. |
| effective\_absolute | [ double](#double) | Absolute threshold applied to this measure (may differ via per\_measure config). |
| effective\_percentage | [ double](#double) | Percentage threshold applied to this measure. |
| effective\_percentage\_basis | [ string](#string) | Percentage basis applied to this measure, as a PercentageBasis value name. |
### MismatchLeafDetail
(synq.agent.recon.v1.MismatchLeafDetail)
MismatchLeafDetail holds detailed information about a single mismatch leaf.
| Field | Type | Description |
| -------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| segment | [ SegmentInfo](#segmentinfo) | Segment boundaries. |
| source\_count | [ int64](#int64) | none |
| target\_count | [ int64](#int64) | none |
| source\_checksum | [ int64](#int64) | none |
| target\_checksum | [ int64](#int64) | none |
| count\_difference | [ int64](#int64) | none |
| mismatch\_types | [repeated SegmentMismatchType](#segmentmismatchtype) | Types of mismatch detected. |
| drill\_stop\_reason | [ DrillStopReason](#drillstopreason) | Why bisection stopped at this leaf. |
| diff\_queries | [ DiffQueries](#diffqueries) | Investigation queries to inspect this mismatch. |
| row\_mismatches | [repeated RowMismatchDetail](#rowmismatchdetail) | Per-row mismatch details (when reporting level allows). |
| row\_mismatch\_count | [ int32](#int32) | Total number of row mismatches (may exceed row\_mismatches length due to sample\_limit). |
### Normalization
(synq.agent.recon.v1.Normalization)
Normalization records the column expressions used after cross-DB type alignment.
| Field | Type | Description |
| --------------- | -------------------------- | ---------------------------------------------- |
| source\_columns | [repeated string](#string) | Source column expressions after normalization. |
| target\_columns | [repeated string](#string) | Target column expressions after normalization. |
### QueryRecord
(synq.agent.recon.v1.QueryRecord)
QueryRecord captures a single SQL query execution.
| Field | Type | Description |
| -------------- | -------------------------- | -------------------------------------------------------- |
| id | [ string](#string) | Unique query identifier within this run. |
| role | [ QueryRole](#queryrole) | Whether this query ran against source or target. |
| connection | [ string](#string) | Connection name used. |
| dialect | [ string](#string) | Database dialect. |
| sql | [ string](#string) | SQL query text. |
| started\_at | [ Timestamp](#timestamp) | When the query started. |
| duration | [ Duration](#duration) | Query execution duration. |
| rows\_returned | [ int32](#int32) | Number of result rows returned. |
| error | [ string](#string) | Error message if the query failed. |
| retry\_attempt | [ int32](#int32) | Retry attempt number (0 for first attempt). |
| stats | [ QueryStats](#querystats) | Execution statistics collected from the database driver. |
### QueryStats
(synq.agent.recon.v1.QueryStats)
QueryStats holds execution statistics collected from the database driver.
Fields are optional — absent means the metric is not available for the driver.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------- |
| query\_id | [ string](#string) | Database-assigned query identifier for auditing. Available for BigQuery (job ID), Snowflake, ClickHouse. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_rows\_read.rows\_read | [optional int64](#int64) | Number of rows read/scanned by the query engine. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_read.bytes\_read | [optional int64](#int64) | Number of bytes read/scanned by the query engine. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_rows\_produced.rows\_produced | [optional int64](#int64) | Number of result rows returned to the caller. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cache\_hit.cache\_hit | [optional bool](#bool) | Whether the query result was served from cache. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_billed.bytes\_billed | [optional int64](#int64) | Number of bytes billed (BigQuery). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_slot\_millis.slot\_millis | [optional int64](#int64) | Slot time consumed (BigQuery). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_blocks.blocks | [optional int64](#int64) | Number of data blocks read (ClickHouse). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_completed\_splits.completed\_splits | [optional int64](#int64) | Number of completed splits (Trino). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cpu\_time\_millis.cpu\_time\_millis | [optional int64](#int64) | CPU time consumed (Trino). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_wall\_time\_millis.wall\_time\_millis | [optional int64](#int64) | Wall time reported by the engine (Trino). |
### QuickCheckStageResult
(synq.agent.recon.v1.QuickCheckStageResult)
QuickCheckStageResult is the result for a quick\_check stage.
| Field | Type | Description |
| ----------------- | ------------------ | ----------- |
| source\_count | [ int64](#int64) | none |
| target\_count | [ int64](#int64) | none |
| source\_checksum | [ int64](#int64) | none |
| target\_checksum | [ int64](#int64) | none |
| match | [ bool](#bool) | none |
| count\_difference | [ int64](#int64) | none |
| error | [ string](#string) | none |
### ReconciliationAudit
(synq.agent.recon.v1.ReconciliationAudit)
ReconciliationAudit captures the configuration and runtime execution data
for a single reconciliation.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| reconciliation | [ Reconciliation](#reconciliation) | The reconciliation configuration as executed. |
| source | [ DatasetInfo](#datasetinfo) | Runtime dataset information (resolved queries, detected dialects). |
| target | [ DatasetInfo](#datasetinfo) | none |
| original\_source\_query | [ string](#string) | Source query before variable interpolation (differs from suite query when variables are used). |
| original\_target\_query | [ string](#string) | Target query before variable interpolation. |
| columns | [repeated string](#string) | Column names discovered at runtime via QueryShape. |
| normalization | [ Normalization](#normalization) | Column normalization expressions applied after cross-DB type alignment. |
| stages | [repeated StageAudit](#stageaudit) | Execution stages (quick\_check, bisection\_drill, aggregate\_check). |
| warnings | [repeated string](#string) | Per-reconciliation warnings. |
| status | [ ReconciliationOutcome](#reconciliationoutcome) | Outcome status of this reconciliation. Distinguishes infrastructure errors from data mismatches and threshold-based outcomes. |
| overall\_match | [ bool](#bool) | Whether source and target matched overall. True when data matched exactly or differences were within configured thresholds. |
| error | [ string](#string) | Error message if the reconciliation failed due to an infrastructure error. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cutoff\_result.cutoff\_result | [optional CutoffResult](#cutoffresult) | Cutoff resolution details (when cutoff was configured). Captures the derived watermark values, final cutoff, and WHERE clauses so the run can be fully understood and reproduced. |
### RowMismatchAudit
(synq.agent.recon.v1.RowMismatchAudit)
RowMismatchAudit captures a single row-level mismatch in the segment tree.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | ----------------------------------------------- |
| pk | [ Value](#value) | Primary key value. |
| type | [ RowMismatchType](#rowmismatchtype) | Type of row mismatch. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source\_row\_hash.source\_row\_hash | [optional int64](#int64) | Source row hash (when available). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_target\_row\_hash.target\_row\_hash | [optional int64](#int64) | Target row hash (when available). |
| source\_values | [map SourceValuesEntry](#sourcevaluesentry) | Source column values (detailed reporting only). |
| target\_values | [map TargetValuesEntry](#targetvaluesentry) | Target column values (detailed reporting only). |
### RowMismatchAudit.SourceValuesEntry
(synq.agent.recon.v1.RowMismatchAudit.SourceValuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### RowMismatchAudit.TargetValuesEntry
(synq.agent.recon.v1.RowMismatchAudit.TargetValuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### RowMismatchDetail
(synq.agent.recon.v1.RowMismatchDetail)
RowMismatchDetail holds per-row mismatch detail.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------- |
| pk | [ Value](#value) | Primary key value. |
| type | [ RowMismatchType](#rowmismatchtype) | Type of row mismatch. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source\_row\_hash.source\_row\_hash | [optional int64](#int64) | Source row hash (when available). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_target\_row\_hash.target\_row\_hash | [optional int64](#int64) | Target row hash (when available). |
### SegmentAuditNode
(synq.agent.recon.v1.SegmentAuditNode)
SegmentAuditNode represents a node in the bisection segment tree.
| Field | Type | Description |
| --------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------- |
| segment | [ SegmentInfo](#segmentinfo) | Segment boundaries. |
| source\_count | [ int64](#int64) | none |
| target\_count | [ int64](#int64) | none |
| source\_checksum | [ int64](#int64) | none |
| target\_checksum | [ int64](#int64) | none |
| match | [ bool](#bool) | Whether source and target matched for this segment. |
| is\_leaf | [ bool](#bool) | Whether this is a leaf node (no further splitting). |
| drill\_stop\_reason | [ DrillStopReason](#drillstopreason) | Why bisection stopped at this node. |
| mismatch\_rows\_in\_subtree | [ int64](#int64) | Sum of mismatched rows in this subtree. |
| total\_rows\_in\_subtree | [ int64](#int64) | Sum of all rows in this subtree. |
| query\_ids | [repeated string](#string) | References to QueryRecord.id values for queries that populated this node. |
| children | [repeated SegmentAuditNode](#segmentauditnode) | Child segments (empty for leaf nodes). |
| row\_mismatches | [repeated RowMismatchAudit](#rowmismatchaudit) | Row-level mismatches (only for leaf nodes with detailed reporting). |
### SegmentInfo
(synq.agent.recon.v1.SegmentInfo)
SegmentInfo identifies a key range segment.
| Field | Type | Description |
| ------------ | ------------------ | ------------------------------------------------ |
| min\_key | [ Value](#value) | Minimum key (inclusive). Unset means unbounded. |
| max\_key | [ Value](#value) | Maximum key (exclusive). Unset means unbounded. |
| depth | [ int32](#int32) | Depth in the bisection tree. |
| index | [ int32](#int32) | Index within the depth level. |
| time\_bucket | [ string](#string) | Time bucket label (for time-based segmentation). |
### StageAudit
(synq.agent.recon.v1.StageAudit)
StageAudit captures one reconciliation stage execution.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------- |
| stage | [ StageType](#stagetype) | Stage type. |
| started\_at | [ Timestamp](#timestamp) | When the stage started. |
| completed\_at | [ Timestamp](#timestamp) | When the stage completed. |
| duration | [ Duration](#duration) | Stage duration. |
| queries | [repeated QueryRecord](#queryrecord) | SQL queries executed during this stage. |
| segment\_tree | [ SegmentAuditNode](#segmentauditnode) | Bisection segment tree (only for bisection\_drill stage). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) result.quick\_check\_result | [ QuickCheckStageResult](#quickcheckstageresult) | Result for quick\_check stage. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) result.bisection\_result | [ BisectionStageResult](#bisectionstageresult) | Result for bisection\_drill stage. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) result.aggregate\_result | [ AggregateStageResult](#aggregatestageresult) | Result for aggregate\_check stage. |
### ThresholdEvaluation
(synq.agent.recon.v1.ThresholdEvaluation)
ThresholdEvaluation captures the effective thresholds applied and per-measure verdicts.
| Field | Type | Description |
| --------------------- | ----------------------------------- | ------------------------------------------------------------------- |
| absolute\_threshold | [ double](#double) | Configured maximum absolute difference, or 0 if not set. |
| percentage\_threshold | [ double](#double) | Configured maximum percentage difference, or 0 if not set. |
| percentage\_basis | [ string](#string) | Which percentage formula was used, as a PercentageBasis value name. |
| measures | [map MeasuresEntry](#measuresentry) | Per-measure threshold evaluation results. |
### ThresholdEvaluation.MeasuresEntry
(synq.agent.recon.v1.ThresholdEvaluation.MeasuresEntry)
| Field | Type | Description |
| ----- | ---------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ MeasureVerdict](#measureverdict) | none |
### DeleteSuiteConfigRequest
(synq.agent.recon.v1.DeleteSuiteConfigRequest)
| Field | Type | Description |
| --------- | ------------------ | -------------------------------------- |
| suite\_id | [ string](#string) | Suite ID to delete. |
| actor | [ Actor](#actor) | Actor performing the delete. Required. |
### DeleteSuiteConfigResponse
(synq.agent.recon.v1.DeleteSuiteConfigResponse)
### GetSuiteConfigRequest
(synq.agent.recon.v1.GetSuiteConfigRequest)
| Field | Type | Description |
| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | Suite ID to look up. For managed suites this equals the suite name, for ad-hoc suites this is the generated UUID. |
### GetSuiteConfigResponse
(synq.agent.recon.v1.GetSuiteConfigResponse)
| Field | Type | Description |
| ------------- | ---------------------------- | ----------- |
| suite\_config | [ SuiteConfig](#suiteconfig) | none |
### GetSuiteConfigVersionRequest
(synq.agent.recon.v1.GetSuiteConfigVersionRequest)
| Field | Type | Description |
| --------- | ------------------------ | ------------------ |
| suite\_id | [ string](#string) | Suite ID. |
| state\_at | [ Timestamp](#timestamp) | Version timestamp. |
### GetSuiteConfigVersionResponse
(synq.agent.recon.v1.GetSuiteConfigVersionResponse)
| Field | Type | Description |
| ------- | ------------------------------------------ | ----------- |
| version | [ SuiteConfigVersion](#suiteconfigversion) | none |
### ListSuiteConfigVersionsRequest
(synq.agent.recon.v1.ListSuiteConfigVersionsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------ |
| suite\_id | [ string](#string) | Suite ID to get version history for. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination parameters. |
### ListSuiteConfigVersionsResponse
(synq.agent.recon.v1.ListSuiteConfigVersionsResponse)
| Field | Type | Description |
| ---------- | -------------------------------------------------- | ------------------------------------------- |
| versions | [repeated SuiteConfigVersion](#suiteconfigversion) | none |
| page\_info | [ PageInfo](#pageinfo) | Pagination info for fetching the next page. |
### ListSuiteConfigsRequest
(synq.agent.recon.v1.ListSuiteConfigsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_connection\_name.connection\_name | [optional string](#string) | Filter suites using a specific connection name. When empty, returns all. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination parameters. |
| include\_adhoc | [ bool](#bool) | When true, also include ad-hoc suite configs in the results. By default only managed suites are returned. |
### ListSuiteConfigsResponse
(synq.agent.recon.v1.ListSuiteConfigsResponse)
| Field | Type | Description |
| -------------- | ------------------------------------ | ------------------------------------------- |
| suite\_configs | [repeated SuiteConfig](#suiteconfig) | none |
| page\_info | [ PageInfo](#pageinfo) | Pagination info for fetching the next page. |
### ResumeFromRun
(synq.agent.recon.v1.ResumeFromRun)
ResumeFromRun turns an ad-hoc submission into a replay of a previous run:
either a re-validation ("do the differences it found still exist") or a
deeper drill of the mismatches it stopped at.
The suite comes from the parent run's audit log, not from a config load, so
the replay compares the same data the parent compared — template variables
keep the values they resolved to and a cutoff keeps the watermark it derived.
Credentials never come from an audit log: it records connection names only,
and those are bound to integrations exactly as for any other ad-hoc run
(connection\_mappings, else a workspace integration of the same name).
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| parent\_invocation\_id | [ string](#string) | Invocation id of the run to continue from. It must be a completed run in the caller's workspace whose audit log carries a suite snapshot. |
| mode | [ ResumeMode](#resumemode) | What to do with the parent's results. |
| reconciliations | [repeated string](#string) | Restrict the replay to these reconciliation names. Empty replays every reconciliation of the parent that is eligible for the mode. |
| reresolve | [ bool](#bool) | Re-derive every query from the suite instead of replaying the SQL the parent executed. This moves the comparison window to the current clock, so it answers "does the suite pass now" rather than "is that difference still there". Needed for a time-travel snapshot, which can otherwise never turn green. |
| include\_passed | [ bool](#bool) | RESUME\_MODE\_RECHECK only: re-run reconciliations that already passed. The default narrows to the ones that did not, which is the point of a re-validation. |
| drill\_still\_mismatched | [ bool](#bool) | RESUME\_MODE\_RECHECK only: drill into whatever still mismatches, as an ordinary run with run\_bisection does. A re-validation usually only needs the quick check, so this is opt-in. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_threshold.threshold | [optional int32](#int32) | RESUME\_MODE\_DRILL\_DEEPER only: row count at which drilling stops, overriding the reconciliation's own. Lowering it is the usual reason to resume a bisection drill — the parent stopped at a coarser threshold. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_extra\_depth.extra\_depth | [optional int32](#int32) | RESUME\_MODE\_DRILL\_DEEPER only: how many further levels to drill below the resumed segments. Counted from the deepest resumed segment, so it means "this much deeper" rather than a budget the parent already spent. Absent leaves it unbounded. |
| additional\_group\_columns | [repeated string](#string) | RESUME\_MODE\_DRILL\_DEEPER only: extra group columns to break each divergent aggregate group down by. An aggregate drill already visits every configured group column, so resuming an aggregate reconciliation needs at least one more column to make progress. |
### SubmitAdhocSuiteRequest
(synq.agent.recon.v1.SubmitAdhocSuiteRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite.suite | [optional ReconciliationSuite](#reconciliationsuite) | Inline suite configuration. Required when neither suite\_id nor resume\_from\_run is set. |
| invocation\_id | [ string](#string) | Client-generated invocation ID for idempotency. If an execution with this ID already exists, the call is a no-op. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_id.suite\_id | [optional string](#string) | Reference to an existing managed suite (alternative to inline suite). When set, the suite config is loaded from the database. |
| connection\_mappings | [repeated ConnectionMapping](#connectionmapping) | Maps each connection name referenced by the suite to the integration that should provide credentials at execution time. |
When omitted, the server attempts to resolve each connection name against a workspace integration of the same name (legacy behaviour). When the suite references connection names that the server cannot resolve, the call fails with FAILED\_PRECONDITION + a ConnectionResolutionFailure detail listing every unresolved name and candidate integrations, so the caller can prompt the user to bind them.
Both workspace-level (integration\_id) and user-level (user\_integration\_id) credentials are accepted here: - integration\_id requires SCOPE\_INTEGRATION\_EDIT on the caller. - user\_integration\_id requires a user identity in the calling context and the integration's allow\_reconciliation\_adhoc gate enabled. |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | When true (default), the runner drills into each mismatched reconciliation via bisection after the quick check fails. Set to false to stop after the quick check — useful for cheap smoke runs, or when the caller plans to trigger a manual drill later.
Per-reconciliation `bisection.enabled` still gates whether a given recon is eligible for drill, so this flag is the run-level off switch layered on top. |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | Maximum wall-clock time for this ad-hoc run (quick check plus any bisection drill). A run that exceeds it is cancelled and marked failed. Absent uses the server default; the server clamps the effective value to a supported range. |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_resume\_from\_run.resume\_from\_run | [optional ResumeFromRun](#resumefromrun) | Continue a previous run instead of executing a suite from its config. Mutually compatible with neither suite nor suite\_id being set: the suite is rebuilt from the parent run's audit log. |
\| actor | [ Actor](#actor) | Actor submitting the run. Required. |
### SubmitAdhocSuiteResponse
(synq.agent.recon.v1.SubmitAdhocSuiteResponse)
| Field | Type | Description |
| ------------- | ---------------------------- | ------------------------------------------------------------------- |
| suite\_config | [ SuiteConfig](#suiteconfig) | The stored suite config (includes the invocation\_id as suite\_id). |
### SuiteConfig
(synq.agent.recon.v1.SuiteConfig)
SuiteConfig represents the latest version of a reconciliation suite configuration.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | Unique identifier. Equals suite\_name for managed suites, UUID for ad-hoc. |
| suite\_name | [ string](#string) | Human-readable suite name from ReconciliationSuite.name. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_title.suite\_title | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_description.suite\_description | [optional string](#string) | none |
| suite\_type | [ string](#string) | "managed" or "adhoc". |
| suite | [ ReconciliationSuite](#reconciliationsuite) | The full suite configuration. |
| connection\_names | [repeated string](#string) | Deduplicated connection names referenced by this suite. |
| reconciliation\_summaries | [repeated ReconciliationConfigSummary](#reconciliationconfigsummary) | Summary of each reconciliation in the suite. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_updated\_by.updated\_by | [optional Actor](#actor) | Who last updated this config. |
| state\_at | [ Timestamp](#timestamp) | When this version was created. |
### SuiteConfigVersion
(synq.agent.recon.v1.SuiteConfigVersion)
SuiteConfigVersion represents a historical version of a suite config.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------- |
| suite\_id | [ string](#string) | none |
| suite\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_title.suite\_title | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_description.suite\_description | [optional string](#string) | none |
| suite\_type | [ string](#string) | none |
| suite | [ ReconciliationSuite](#reconciliationsuite) | The full suite configuration at this version. |
| connection\_names | [repeated string](#string) | Connection names at this version. |
| reconciliation\_summaries | [repeated ReconciliationConfigSummary](#reconciliationconfigsummary) | Reconciliation summaries at this version. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_updated\_by.updated\_by | [optional Actor](#actor) | Who made this change. |
| state\_at | [ Timestamp](#timestamp) | When this version was created. |
| deleted | [ bool](#bool) | Whether this version represents a deletion. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | Human-readable summary of what changed. |
### UpsertSuiteConfigRequest
(synq.agent.recon.v1.UpsertSuiteConfigRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------ |
| suite | [ ReconciliationSuite](#reconciliationsuite) | The suite configuration to store. suite\_id will equal suite.name. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | Human-readable summary of what changed in this version. |
| actor | [ Actor](#actor) | Actor performing the upsert. Required. |
### UpsertSuiteConfigResponse
(synq.agent.recon.v1.UpsertSuiteConfigResponse)
| Field | Type | Description |
| ------------- | ---------------------------- | ------------------------ |
| suite\_config | [ SuiteConfig](#suiteconfig) | The stored suite config. |
### ConnectionEnvironmentOverride
(synq.agent.recon.v1.ConnectionEnvironmentOverride)
ConnectionEnvironmentOverride applies to all datasets using a given connection.
Provides a default table path override for all datasets on that connection.
| Field | Type | Description |
| ----------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| table\_path | [ TablePathOverride](#tablepathoverride) | Default table path override for all datasets on this connection. Can be further overridden by dataset-level overrides. |
### DatasetEnvironmentOverride
(synq.agent.recon.v1.DatasetEnvironmentOverride)
DatasetEnvironmentOverride applies to a specific dataset in a specific reconciliation.
Takes precedence over connection-level overrides.
| Field | Type | Description |
| ----------- | ---------------------------------------- | ---------------------------------------------- |
| table\_path | [ TablePathOverride](#tablepathoverride) | Table path override for this specific dataset. |
### ReconEnvironment
(synq.agent.recon.v1.ReconEnvironment)
ReconEnvironment defines overrides applied to a suite before execution.
Environments allow the same suite definition to run against different
database locations (e.g., dev vs production schemas) without modifying
the suite itself.
Used both in synq-recon CLI (loaded from .env.yaml files) and in
kernel-recon cloud (managed as workspace-level configurations).
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Environment name (e.g., "dev-lukasz", "staging", "production"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Human-readable description of this environment. |
| connections | [map ConnectionsEntry](#connectionsentry) | Connection-level overrides, keyed by connection name. Applied to all datasets using the specified connection. |
| datasets | [map DatasetsEntry](#datasetsentry) | Dataset-level overrides, keyed by "reconciliation\_name.source" or "reconciliation\_name.target". Takes precedence over connection-level overrides for the matching dataset. |
| variables | [map VariablesEntry](#variablesentry) | Variable overrides merged on top of suite-level variables. Takes precedence over suite variables but is overridden by CLI --var flags. |
### ReconEnvironment.ConnectionsEntry
(synq.agent.recon.v1.ReconEnvironment.ConnectionsEntry)
| Field | Type | Description |
| ----- | ---------------------------------------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ ConnectionEnvironmentOverride](#connectionenvironmentoverride) | none |
### ReconEnvironment.DatasetsEntry
(synq.agent.recon.v1.ReconEnvironment.DatasetsEntry)
| Field | Type | Description |
| ----- | ---------------------------------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ DatasetEnvironmentOverride](#datasetenvironmentoverride) | none |
### ReconEnvironment.VariablesEntry
(synq.agent.recon.v1.ReconEnvironment.VariablesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### TablePathOverride
(synq.agent.recon.v1.TablePathOverride)
TablePathOverride remaps components of a fully-qualified table name.
Only set fields are overridden — unset fields keep the suite's original value.
Applied to TableReference fields in datasets when an environment is active.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Replace the database/catalog component. e.g., "PROD\_DB" → "DEV\_LUKASZ\_DB" |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schema.schema | [optional string](#string) | Replace the schema/dataset component. e.g., "analytics" → "dev\_lukasz\_analytics" |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_table\_prefix.table\_prefix | [optional string](#string) | Prefix to prepend to the table name. e.g., "dev\_" → "dev\_orders" instead of "orders" |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_table\_suffix.table\_suffix | [optional string](#string) | Suffix to append to the table name. e.g., "\_staging" → "orders\_staging" instead of "orders" |
### ConnectionMapping
(synq.agent.recon.v1.ConnectionMapping)
Maps a reconciliation-connection name (as referenced in the suite config)
to a concrete SYNQ integration. Used at execution time to resolve DWH
credentials.
Two credential planes are defined on the wire:
* integration\_id: workspace-level integration. Required for deployment
paths and acceptable for adhoc submission when the caller has
SCOPE\_INTEGRATION\_EDIT.
* user\_integration\_id: per-user OAuth-backed integration. Accepted
only on adhoc submission, and only when a user identity is present
in the calling context. Deployment paths reject this branch
unconditionally — scheduled runs must be able to fire without any
particular user being available, so they always run with workspace
credentials.
Wire-compatible with the previous shape: the original `integration_id`
(field 2) is preserved as one branch of the oneof so existing serialized
rows decode unchanged.
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| connection\_name | [ string](#string) | Connection name as it appears in the suite config (e.g. ReconciliationSuite.reconciliations\[].source.connection). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) source.integration\_id | [ string](#string) | Workspace-level integration (credentials owned by the workspace). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) source.user\_integration\_id | [ string](#string) | Per-user integration ID (user-level credentials). Server requires a user identity in the calling context to accept this branch. |
### ConnectionResolutionFailure
(synq.agent.recon.v1.ConnectionResolutionFailure)
Error-details payload attached to FAILED\_PRECONDITION when a recon
request cannot be honoured because one or more suite connection names
have no usable mapping. The caller should prompt the user to bind every
listed connection and retry.
| Field | Type | Description |
| ---------- | ------------------------------------------------------ | ----------- |
| unresolved | [repeated UnresolvedConnection](#unresolvedconnection) | none |
### GetSuiteDeploymentRequest
(synq.agent.recon.v1.GetSuiteDeploymentRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | ------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.deployment\_id | [ string](#string) | none |
### GetSuiteDeploymentResponse
(synq.agent.recon.v1.GetSuiteDeploymentResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### ListSuiteDeploymentHistoryRequest
(synq.agent.recon.v1.ListSuiteDeploymentHistoryRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.deployment\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | none |
### ListSuiteDeploymentHistoryResponse
(synq.agent.recon.v1.ListSuiteDeploymentHistoryResponse)
| Field | Type | Description |
| ---------- | -------------------------------------------------------------------- | ----------- |
| entries | [repeated SuiteDeploymentHistoryEntry](#suitedeploymenthistoryentry) | none |
| page\_info | [ PageInfo](#pageinfo) | none |
### ListSuiteDeploymentsRequest
(synq.agent.recon.v1.ListSuiteDeploymentsRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Return only deployments wired to this SYNQ integration (match against the deployment's connection\_mappings). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_triggerable\_by\_api.triggerable\_by\_api | [optional bool](#bool) | Filter by triggerable\_by\_api flag. |
| active\_only | [ bool](#bool) | When true (default), only active deployments are returned. |
| include\_paused | [ bool](#bool) | When false (default), paused deployments are excluded. |
### ListSuiteDeploymentsResponse
(synq.agent.recon.v1.ListSuiteDeploymentsResponse)
| Field | Type | Description |
| ----------- | -------------------------------------------- | ----------- |
| deployments | [repeated SuiteDeployment](#suitedeployment) | none |
| page\_info | [ PageInfo](#pageinfo) | none |
### PauseDeploymentRequest
(synq.agent.recon.v1.PauseDeploymentRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------- |
| suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_until.until | [optional Timestamp](#timestamp) | Absent = pause indefinitely. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reason.reason | [optional string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the pause. Required. |
### PauseDeploymentResponse
(synq.agent.recon.v1.PauseDeploymentResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### PromoteSuiteRequest
(synq.agent.recon.v1.PromoteSuiteRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | Suite to promote. For managed suites pass the suite name; for ad-hoc pass the UUID suite\_id. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_state\_at.state\_at | [optional Timestamp](#timestamp) | Specific version to promote. Absent = latest. |
| connection\_mappings | [repeated ConnectionMapping](#connectionmapping) | Mappings for suite connections that don't already resolve to a workspace integration by name. Connections whose name matches a workspace integration can be omitted; they are resolved automatically. Promotion fails if any connection in the suite cannot be resolved. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schedule.schedule | [optional SuiteSchedule](#suiteschedule) | Optional cron/iCal schedule. Absent on a re-promote preserves the existing deployment's schedule (cron or iCal) verbatim; absent on a fresh promote means no schedule. To remove a schedule from an existing deployment use UpdateDeploymentSchedule (clear), not a re-promote. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_triggerable\_by\_api.triggerable\_by\_api | [optional bool](#bool) | When true, a TriggerDeployment RPC may execute this deployment on demand. Optional so re-promotes can omit it: an absent value preserves the existing deployment's setting (a fresh promote defaults to false). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | Whether runs of this deployment drill into mismatched reconciliations after the quick check. Absent preserves the existing deployment's setting on a re-promote, or defaults to true on a fresh promote. Set false for quick-check-only deployments. Each reconciliation's own `bisection.enabled` still controls whether it is eligible to drill. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | Maximum wall-clock time for a single run of this deployment. Absent on a fresh promote uses the server default; absent on a re-promote preserves the existing deployment's setting. The server clamps the effective value to a supported range. Set a lower value to bound cost on expensive warehouses, or a higher value for large tables whose drill legitimately needs longer than the default. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deployment\_id.deployment\_id | [optional string](#string) | Optional client-supplied deployment id (UUID). Use this to make PromoteSuite idempotent across retries: if the original request wrote a row but the response was lost, the client re-issues with the same deployment\_id and the second call resolves to the same deployment. |
Server semantics: - absent : reuse the existing deployment for this suite\_id, or generate a fresh UUIDv7 - present, no row exists for (workspace, deployment\_id) : adopt as-is - present, row exists with same suite\_id : idempotent retry - present, row exists with different suite\_id : ALREADY\_EXISTS |
\| actor | [ Actor](#actor) | Actor performing the promotion. Required. |
\| deployment\_annotations | [repeated Annotation](#annotation) | Initial deployment-level annotation overlay. Merged with suite-level and case-level annotations from the frozen suite snapshot. Use UpdateDeploymentAnnotations to mutate later without re-promoting. |
\| reconciliation\_failure\_impacts | [map ReconciliationFailureImpactsEntry](#reconciliationfailureimpactsentry) | Per-case override controlling how the tables referenced by each reconciliation case propagate onto runs. Keyed by case `name` from the suite config. When a key is omitted on re-promote, the prior deployment's value is retained — operators only set keys they want to change, and the FE can offer an "apply to all" action by sending the same value under every case name. New cases (not present in any previous deployment of this suite\_id) default to RAISE\_ISSUE\_ON\_TABLES when unset.
Sending RECONCILIATION\_FAILURE\_IMPACT\_UNSPECIFIED for a known case is treated as "no opinion, keep current"; to actively reset to the default, either omit the case or send RAISE\_ISSUE\_ON\_TABLES. |
### PromoteSuiteRequest.ReconciliationFailureImpactsEntry
(synq.agent.recon.v1.PromoteSuiteRequest.ReconciliationFailureImpactsEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ ReconciliationFailureImpact](#reconciliationfailureimpact) | none |
### PromoteSuiteResponse
(synq.agent.recon.v1.PromoteSuiteResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### ResumeDeploymentRequest
(synq.agent.recon.v1.ResumeDeploymentRequest)
| Field | Type | Description |
| --------- | ------------------ | -------------------------------------- |
| suite\_id | [ string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the resume. Required. |
### ResumeDeploymentResponse
(synq.agent.recon.v1.ResumeDeploymentResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### SuiteDeployment
(synq.agent.recon.v1.SuiteDeployment)
SuiteDeployment is the latest state of a deployment (current row).
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| deployment\_id | [ string](#string) | Stable platform identity (UUIDv7). Preserved across re-promotes, pause/resume, and unpromote → re-promote cycles. Downstream AssetCommand / RunCommand reference this. |
| suite\_id | [ string](#string) | Suite this deployment came from. |
| suite\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_title.suite\_title | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_description.suite\_description | [optional string](#string) | none |
| active | [ bool](#bool) | False after UnpromoteSuite. Scheduler and triggers stop. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_paused\_until.paused\_until | [optional Timestamp](#timestamp) | When set and in the future, scheduled/triggered runs are suppressed. An indefinite pause uses a far-future sentinel timestamp. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_paused\_reason.paused\_reason | [optional string](#string) | none |
| suite | [ ReconciliationSuite](#reconciliationsuite) | Frozen snapshot of the suite config at promote time. |
| connection\_mappings | [repeated ConnectionMapping](#connectionmapping) | Mapping used at execution time to resolve DWH credentials. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schedule.schedule | [optional SuiteSchedule](#suiteschedule) | Schedule (if any). Absent = no cron; use triggerable\_by\_api. |
| triggerable\_by\_api | [ bool](#bool) | When true, this deployment can be run on demand via TriggerDeployment, in addition to any cron schedule. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | When true (the default), runs of this deployment drill into mismatched reconciliations via bisection after the quick check to locate the differing rows; when false, runs stop at the quick check. Each reconciliation's own `bisection.enabled` still controls whether it is eligible to drill, so this acts as the deployment-wide switch on top. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | Maximum wall-clock time for a single run of this deployment (the quick check plus any bisection drill). A run that exceeds it is cancelled and marked failed. Absent means the server default applies; the effective value is clamped to a supported range. Lower it to bound cost on expensive warehouses where a deep drill can run for a long time. |
| connection\_names | [repeated string](#string) | Denormalized summaries so listing callers don't need to parse the snapshot. |
| integration\_ids | [repeated string](#string) | none |
| reconciliation\_summaries | [repeated ReconciliationConfigSummary](#reconciliationconfigsummary) | none |
| source\_suite\_type | [ string](#string) | Where this deployment's snapshot came from. |
"managed" or "adhoc" |
\| source\_config\_state\_at | [ Timestamp](#timestamp) | none |
\| state\_at | [ Timestamp](#timestamp) | Most recent event timestamp. |
\| last\_action | [ DeploymentAction](#deploymentaction) | none |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_actor.last\_actor | [optional Actor](#actor) | none |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_change\_summary.last\_change\_summary | [optional string](#string) | none |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_next\_run\_at.next\_run\_at | [optional Timestamp](#timestamp) | Next cron occurrence computed live from `schedule` at response time. Absent when there's no schedule, when the deployment is inactive/paused, or when the schedule expression no longer yields an upcoming occurrence (e.g. an iCal RRULE that has finished). Use this for "Next run: …" UI hints — it's the authoritative upcoming-tick source, independent of any pre-materialised execution\_jobs / run\_state rows. |
\| deployment\_annotations | [repeated Annotation](#annotation) | Deployment-level annotation overlay. Applied on top of the suite-level and case-level annotations baked into the frozen suite snapshot. The merged, deduplicated list lives on PromotedReconSuiteMetadata / PromotedReconCaseMetadata — this field exposes only the deployment's own overlay so callers can render and edit it independently. |
\| reconciliation\_failure\_impacts | [map ReconciliationFailureImpactsEntry](#reconciliationfailureimpactsentry) | Effective per-case ReconciliationFailureImpact map currently in force for this deployment. Keyed by case `name`. Cases without an entry behave as RAISE\_ISSUE\_ON\_TABLES. Drives whether the runner attaches each case's referenced tables to Run.target (issue-raising) or Run.extra\_references (visibility only) — see PromotedReconCaseMetadata.error\_tables / shown\_tables for the resolved table lists. |
### SuiteDeployment.ReconciliationFailureImpactsEntry
(synq.agent.recon.v1.SuiteDeployment.ReconciliationFailureImpactsEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ ReconciliationFailureImpact](#reconciliationfailureimpact) | none |
### SuiteDeploymentHistoryEntry
(synq.agent.recon.v1.SuiteDeploymentHistoryEntry)
SuiteDeploymentHistoryEntry is a single event in the deployment's history.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| deployment\_id | [ string](#string) | none |
| suite\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | none |
| action | [ DeploymentAction](#deploymentaction) | none |
| active | [ bool](#bool) | State of the deployment at the moment of this event. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_paused\_until.paused\_until | [optional Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_paused\_reason.paused\_reason | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schedule.schedule | [optional SuiteSchedule](#suiteschedule) | none |
| triggerable\_by\_api | [ bool](#bool) | none |
| connection\_mappings | [repeated ConnectionMapping](#connectionmapping) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | The run\_bisection setting in force at the time of this event. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | The execution\_timeout in force at the time of this event. Absent means the server default applied. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite.suite | [optional ReconciliationSuite](#reconciliationsuite) | Only filled for PROMOTED / REPROMOTED events (snapshot changes). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source\_config\_state\_at.source\_config\_state\_at | [optional Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| deployment\_annotations | [repeated Annotation](#annotation) | Deployment-level annotation overlay at this point in time. Filled on every history entry (annotation changes carry the full new list, other events carry the snapshot at the time of the event). |
| reconciliation\_failure\_impacts | [map ReconciliationFailureImpactsEntry](#reconciliationfailureimpactsentry) | Effective per-case ReconciliationFailureImpact map at this point in time. Snapshot semantics — every history entry carries the full map in force right after the event was recorded. |
### SuiteDeploymentHistoryEntry.ReconciliationFailureImpactsEntry
(synq.agent.recon.v1.SuiteDeploymentHistoryEntry.ReconciliationFailureImpactsEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ ReconciliationFailureImpact](#reconciliationfailureimpact) | none |
### TriggerDeploymentRequest
(synq.agent.recon.v1.TriggerDeploymentRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) lookup.deployment\_id | [ string](#string) | none |
| actor | [ Actor](#actor) | Actor triggering the run. Required. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | Per-run override for the deployment's stored run\_bisection setting. Unset (the default) inherits the deployment's value, so an on-demand run behaves like a scheduled one. Set false for a cheap quick-check-only run with no bisection drill-down. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | Per-run override for the deployment's stored execution\_timeout. Unset (the default) inherits the deployment's value. Set it to bound this one run to a shorter or longer wall-clock budget; the server clamps the effective value to a supported range. |
### TriggerDeploymentResponse
(synq.agent.recon.v1.TriggerDeploymentResponse)
| Field | Type | Description |
| -------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| deployment\_id | [ string](#string) | Identity of the deployment that was triggered (canonical form even when the request used `suite_id`). |
| run\_id | [ string](#string) | Stable opaque identifier of the enqueued run. Pass this to RunStateService to track lifecycle. |
| scheduled\_at | [ Timestamp](#timestamp) | When the run is scheduled to start. For TriggerDeployment this is \~now(); the worker will pick it up shortly. |
### UnpromoteSuiteRequest
(synq.agent.recon.v1.UnpromoteSuiteRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------- |
| suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reason.reason | [optional string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the unpromote. Required. |
### UnpromoteSuiteResponse
(synq.agent.recon.v1.UnpromoteSuiteResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### UnresolvedConnection
(synq.agent.recon.v1.UnresolvedConnection)
One entry per connection name the server failed to resolve. Returned
inside ConnectionResolutionFailure as the structured error detail of a
FAILED\_PRECONDITION on adhoc submission or deployment promote/update.
| Field | Type | Description |
| --------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connection\_name | [ string](#string) | Connection name as referenced by the suite config. |
| reason | [ UnresolvedConnectionReason](#unresolvedconnectionreason) | Why the server could not satisfy the mapping. |
| message | [ string](#string) | Optional human-readable elaboration ("integration X has reconciliation adhoc disabled by workspace admin", etc.). Already includes workspace / suite context — safe to surface verbatim. |
| candidate\_integration\_ids | [repeated string](#string) | Suggested integration ids the caller could pick from. Filtered by the capability the failing call needs (RECONCILIATION\_ADHOC for adhoc, RECONCILIATION\_DEPLOY for deployment) so the UI can render a picker directly without re-querying. |
### UpdateDeploymentAnnotationsRequest
(synq.agent.recon.v1.UpdateDeploymentAnnotationsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | none |
| deployment\_annotations | [repeated Annotation](#annotation) | Full replacement for the deployment-level annotation overlay. Pass an empty list to clear all deployment-level annotations (suite/case annotations from the frozen snapshot still apply). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the annotation update. Required. |
### UpdateDeploymentAnnotationsResponse
(synq.agent.recon.v1.UpdateDeploymentAnnotationsResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### UpdateDeploymentCaseImpactsRequest
(synq.agent.recon.v1.UpdateDeploymentCaseImpactsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | none |
| reconciliation\_failure\_impacts | [map ReconciliationFailureImpactsEntry](#reconciliationfailureimpactsentry) | Partial patch of the per-case impact map. See UpdateDeploymentCaseImpacts RPC docs for merge / clear semantics. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the update. Required. |
### UpdateDeploymentCaseImpactsRequest.ReconciliationFailureImpactsEntry
(synq.agent.recon.v1.UpdateDeploymentCaseImpactsRequest.ReconciliationFailureImpactsEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ ReconciliationFailureImpact](#reconciliationfailureimpact) | none |
### UpdateDeploymentCaseImpactsResponse
(synq.agent.recon.v1.UpdateDeploymentCaseImpactsResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### UpdateDeploymentMappingsRequest
(synq.agent.recon.v1.UpdateDeploymentMappingsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | none |
| connection\_mappings | [repeated ConnectionMapping](#connectionmapping) | Same shape as PromoteSuiteRequest.connection\_mappings — entries are optional and apply only to connections that don't resolve by name. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| actor | [ Actor](#actor) | Actor performing the mapping update. Required. |
### UpdateDeploymentMappingsResponse
(synq.agent.recon.v1.UpdateDeploymentMappingsResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### UpdateDeploymentScheduleRequest
(synq.agent.recon.v1.UpdateDeploymentScheduleRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schedule.schedule | [optional SuiteSchedule](#suiteschedule) | Presence-based: - absent = preserve current schedule - present, empty = clear the schedule (an empty SuiteSchedule has no cron, which the deployment row stores as no schedule) - present, with cron = replace the schedule |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_triggerable\_by\_api.triggerable\_by\_api | [optional bool](#bool) | Absent = preserve current setting. Otherwise update triggerable\_by\_api. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_bisection.run\_bisection | [optional bool](#bool) | Absent = preserve current setting. Otherwise update the deployment's run\_bisection flag. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_timeout.execution\_timeout | [optional Duration](#duration) | Absent = preserve current setting. Otherwise update the deployment's execution\_timeout (maximum wall-clock budget for a single run). The server clamps the effective value to a supported range at run time. |
| actor | [ Actor](#actor) | Actor performing the schedule update. Required. |
### UpdateDeploymentScheduleResponse
(synq.agent.recon.v1.UpdateDeploymentScheduleResponse)
| Field | Type | Description |
| ---------- | ------------------------------------ | ----------- |
| deployment | [ SuiteDeployment](#suitedeployment) | none |
### ColumnThresholdOverride
(synq.agent.recon.v1.ColumnThresholdOverride)
ColumnThresholdOverride associates threshold overrides with a specific
group\_column level in the aggregate drill-down hierarchy.
| Field | Type | Description |
| ---------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| column | [ string](#string) | Group column name this override applies to. Must match one of the group\_columns in the AggregateConfig. |
| thresholds | [ ThresholdConfig](#thresholdconfig) | Threshold overrides for this group column level. Values here override the parent ThresholdConfig for reconciliation groups at this drill-down level. May include per\_measure for further specificity. |
### MeasureThresholdOverride
(synq.agent.recon.v1.MeasureThresholdOverride)
MeasureThresholdOverride associates threshold overrides with a specific
measure (aggregate function + column combination).
| Field | Type | Description |
| ---------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| function | [ AggregateFunction](#aggregatefunction) | Aggregate function this override applies to. |
| column | [ string](#string) | Column name this override applies to. Together with function, forms the measure key (e.g., SUM + "amount" = "SUM(amount)"). |
| thresholds | [ ThresholdConfig](#thresholdconfig) | Threshold overrides for this specific measure. Values here override the parent ThresholdConfig (and any per\_column override) for this measure only. |
### ThresholdConfig
(synq.agent.recon.v1.ThresholdConfig)
ThresholdConfig defines tolerance thresholds for aggregate comparisons.
A difference is reported as a mismatch only when it exceeds ALL configured
thresholds (AND logic: both absolute AND percentage must be exceeded).
Thresholds can be overridden at finer granularity:
* per\_column: override thresholds for a specific group\_column drill-down level.
* per\_measure: override thresholds for a specific measure (e.g., "SUM(amount)").
* Nesting: per\_column entries may contain per\_measure overrides (most specific wins).
When no thresholds are configured at any level, exact match is required.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_absolute.absolute | [optional double](#double) | Maximum allowed absolute difference per measure. When set, differences ≤ this value are considered within tolerance. Example: absolute = 0.01 accepts sub-cent rounding differences. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_percentage.percentage | [optional double](#double) | Maximum allowed percentage difference per measure. Expressed as a decimal fraction: 0.1 = 10%, 0.01 = 1%. The formula used depends on percentage\_basis. When set, differences ≤ this percentage are considered within tolerance. |
| percentage\_basis | [ PercentageBasis](#percentagebasis) | Which percentage formula to use for threshold evaluation. Only relevant when percentage is set. |
| per\_column | [repeated ColumnThresholdOverride](#columnthresholdoverride) | Per group\_column level threshold overrides. Allows different tolerance for different levels of the drill-down hierarchy. For example, tighter thresholds at the city level than at the region level. Entries may themselves contain per\_measure overrides for maximum specificity. |
| per\_measure | [repeated MeasureThresholdOverride](#measurethresholdoverride) | Per measure threshold overrides. Allows different tolerance for different measures within the same reconciliation. For example, allow 1% tolerance for SUM(amount) but require exact COUNT match. |
### BatchReconciliationRunStateRequest
(synq.agent.recon.v1.BatchReconciliationRunStateRequest)
| Field | Type | Description |
| ------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_ids | [repeated string](#string) | none |
| include\_adhoc\_children | [ bool](#bool) | When true, the response also includes adhoc test runs spawned from the queried suites — i.e. rows whose parent\_suite\_id matches. Use this for the "development" view where adhoc activity is part of the iteration loop. Production / deployment-centric views leave it false to see only deployment-driven runs. |
### BatchReconciliationRunStateResponse
(synq.agent.recon.v1.BatchReconciliationRunStateResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ----------------------------------------------------------------- |
| states | [map StatesEntry](#statesentry) | Map keyed by suite\_id; suites with no recorded runs are omitted. |
### BatchReconciliationRunStateResponse.StatesEntry
(synq.agent.recon.v1.BatchReconciliationRunStateResponse.StatesEntry)
| Field | Type | Description |
| ----- | ---------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ SuiteRunStates](#suiterunstates) | none |
### CancelReconciliationRunRequest
(synq.agent.recon.v1.CancelReconciliationRunRequest)
| Field | Type | Description |
| --------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_id | [ string](#string) | The suite the run belongs to. Required because run rows are keyed by (workspace, suite\_id, run\_id) — clients pass the suite\_id they already know from the run state listing alongside the run\_id. |
| run\_id | [ string](#string) | Run identifier. UUIDv7 returned by BatchReconciliationRunState / ListReconciliationRunState. |
### CancelReconciliationRunResponse
(synq.agent.recon.v1.CancelReconciliationRunResponse)
| Field | Type | Description |
| ----- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| state | [ ReconciliationRunState](#reconciliationrunstate) | The current state of the run after the cancel attempt. Status will be CANCELLED if the run was SCHEDULED/IN\_PROGRESS at call time, or unchanged if it had already reached a terminal status. |
### ListReconciliationRunStateRequest
(synq.agent.recon.v1.ListReconciliationRunStateRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| suite\_ids | [repeated string](#string) | Optional filter: limit to these suite\_ids. Combined with deployment\_ids via OR — a row matches if either list contains it (both empty = no suite/deployment filter). |
| statuses | [repeated ReconciliationRunStatus](#reconciliationrunstatus) | Optional filter: only return runs in these statuses. Empty = no status filter. |
| deployment\_ids | [repeated string](#string) | Optional filter: limit to runs belonging to these deployment\_ids. Use this to scope the listing to a single promoted deployment cycle — suite\_id alone may overlap multiple deployment\_ids when a suite has been promoted, unpromoted, and re-promoted. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scheduled\_after.scheduled\_after | [optional Timestamp](#timestamp) | Only return runs scheduled at or after this timestamp (inclusive). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scheduled\_before.scheduled\_before | [optional Timestamp](#timestamp) | Only return runs scheduled before this timestamp (exclusive). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination parameters. The cursor encodes (scheduled\_at, run\_id) and is opaque to clients — pass page\_info.next\_cursor verbatim. |
| triggers | [repeated ReconciliationRunTrigger](#reconciliationruntrigger) | Optional filter: only return runs created via these triggers. Empty = no trigger filter. Use this to separate API-triggered runs from cron-scheduled occurrences from ad-hoc submissions in the listing. |
| actor\_identities | [repeated string](#string) | Optional filter: limit to runs initiated by these actor identities. Identities use the canonical actor-identity string format defined alongside the public Actor type (e.g. `email:foo@example.com`, `slack:U12345`, `client_id:`). Empty list = no actor filter. Useful for "show only my ad-hoc runs" views — clients construct their own identity from the authenticated user (typically `email:`) and pass it here. |
### ListReconciliationRunStateResponse
(synq.agent.recon.v1.ListReconciliationRunStateResponse)
| Field | Type | Description |
| ---------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| states | [repeated ReconciliationRunState](#reconciliationrunstate) | Sorted newest-first by scheduled\_at, then by run\_id desc as a stable tiebreaker. |
| page\_info | [ PageInfo](#pageinfo) | Pagination info for fetching the next page. |
### SuiteRunStates
(synq.agent.recon.v1.SuiteRunStates)
SuiteRunStates groups the most relevant run rows for a single suite.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_latest\_concluded.latest\_concluded | [optional ReconciliationRunState](#reconciliationrunstate) | Most recent run that has reached a terminal status (SUCCEEDED, FAILED, CANCELLED). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ongoing.ongoing | [optional ReconciliationRunState](#reconciliationrunstate) | Most recent run whose target tick has arrived (scheduled\_at ≤ now) and that is still SCHEDULED or IN\_PROGRESS. Pre-scheduled future rows are not surfaced here — see `next_run_at` on SuiteDeployment for the upcoming cron occurrence. |
### AuditLogEntry
(synq.agent.recon.v1.AuditLogEntry)
AuditLogEntry is a summary of an audit log for listing purposes.
Use GetAuditLog to retrieve the full audit log data.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| invocation\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_invocation\_id.parent\_invocation\_id | [optional string](#string) | none |
| suite\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_title.suite\_title | [optional string](#string) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| completed\_at | [ Timestamp](#timestamp) | none |
| duration | [ Duration](#duration) | none |
| status | [ AuditOutcome](#auditoutcome) | none |
| summary | [ AuditSummary](#auditsummary) | none |
| reconciliations | [repeated ReconciliationSummary](#reconciliationsummary) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_id.suite\_id | [optional string](#string) | Stable suite identifier assigned by the platform — same value as the suite\_id on RunStateService.ReconciliationRunState, suitable for joining a run row to its audit log. Empty for legacy logs ingested before run-state correlation was added. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deployment\_id.deployment\_id | [optional string](#string) | Deployment identifier this run belongs to (UUIDv7). Empty for adhoc submissions and for legacy logs ingested before run-state correlation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_run\_id.run\_id | [optional string](#string) | Stable run identifier (UUIDv7) assigned at scheduling time. Empty for legacy logs / direct agent submissions made outside the platform job queue. |
### GetAuditLogRequest
(synq.agent.recon.v1.GetAuditLogRequest)
| Field | Type | Description |
| -------------- | ------------------ | ------------------------------------------- |
| invocation\_id | [ string](#string) | Invocation ID of the audit log to retrieve. |
### GetAuditLogResponse
(synq.agent.recon.v1.GetAuditLogResponse)
| Field | Type | Description |
| ---------- | ---------------------- | ----------- |
| audit\_log | [ AuditLog](#auditlog) | none |
### IngestAuditLogRequest
(synq.agent.recon.v1.IngestAuditLogRequest)
| Field | Type | Description |
| ---------- | ---------------------- | ----------------------- |
| audit\_log | [ AuditLog](#auditlog) | The audit log to store. |
### IngestAuditLogResponse
(synq.agent.recon.v1.IngestAuditLogResponse)
### ListAuditLogsRequest
(synq.agent.recon.v1.ListAuditLogsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ----------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite\_name.suite\_name | [optional string](#string) | Filter by suite name. When empty, returns all suites. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_after.started\_after | [optional Timestamp](#timestamp) | Only return audit logs started after this timestamp (inclusive). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_before.started\_before | [optional Timestamp](#timestamp) | Only return audit logs started before this timestamp (exclusive). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination parameters. |
| statuses | [repeated AuditOutcome](#auditoutcome) | Filter by audit status. When empty, returns all statuses. |
### ListAuditLogsResponse
(synq.agent.recon.v1.ListAuditLogsResponse)
| Field | Type | Description |
| ----------- | ---------------------------------------- | ------------------------------------------- |
| audit\_logs | [repeated AuditLogEntry](#auditlogentry) | none |
| page\_info | [ PageInfo](#pageinfo) | Pagination info for fetching the next page. |
### ReconciliationSummary
(synq.agent.recon.v1.ReconciliationSummary)
ReconciliationSummary is a compact summary of a single reconciliation within an audit log entry.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------- |
| name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | none |
| source\_connection | [ string](#string) | Source connection name. |
| target\_connection | [ string](#string) | Target connection name. |
| status | [ ReconciliationOutcome](#reconciliationoutcome) | none |
| overall\_match | [ bool](#bool) | none |
| error | [ string](#string) | Error message if the reconciliation failed. |
### AggregateDrillTarget
(synq.agent.recon.v1.AggregateDrillTarget)
AggregateDrillTarget specifies how to extend or drill deeper into aggregate results.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| groups | [repeated GroupTarget](#grouptarget) | Specific group key values to drill into. When empty, all mismatched groups from the parent audit are drilled. |
| additional\_group\_columns | [repeated string](#string) | Additional group columns to add to the drill-down hierarchy. Appended after the existing group\_columns from the reconciliation config. |
| additional\_measures | [repeated Measure](#measure) | Additional measures to compute that weren't in the original config. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_threshold\_overrides.threshold\_overrides | [optional ThresholdConfig](#thresholdconfig) | Override thresholds for this drill pass. |
### BisectionDrillTarget
(synq.agent.recon.v1.BisectionDrillTarget)
BisectionDrillTarget specifies which mismatch leaves to drill deeper into.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| segments | [repeated SegmentTarget](#segmenttarget) | Specific segments to drill into. Each segment is identified by its boundaries. When empty, all mismatch leaves from the parent audit are drilled. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_factor.factor | [optional int32](#int32) | Override the bisection factor for this drill pass. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_threshold.threshold | [optional int32](#int32) | Override the row count threshold for this drill pass. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_mismatch\_detail\_level.mismatch\_detail\_level | [optional MismatchDetailLevel](#mismatchdetaillevel) | Override the reporting level for this drill pass. |
### GroupTarget
(synq.agent.recon.v1.GroupTarget)
GroupTarget identifies a specific group to drill into by its key values.
| Field | Type | Description |
| ----- | ------------------ | ----------------------------------------------------------------- |
| key | [ Struct](#struct) | Group key values that identify this group (column name -> value). |
### ReconciliationFilter
(synq.agent.recon.v1.ReconciliationFilter)
ReconciliationFilter controls which reconciliations are included or excluded.
| Field | Type | Description |
| ------- | -------------------------- | -------------------------------------------------------------------------- |
| include | [repeated string](#string) | Run only these reconciliations (by name). Mutually exclusive with exclude. |
| exclude | [repeated string](#string) | Skip these reconciliations (by name). Mutually exclusive with include. |
### ReconciliationOverride
(synq.agent.recon.v1.ReconciliationOverride)
ReconciliationOverride provides per-reconciliation instructions for a run.
Used to drill into specific mismatches, adjust config, or extend comparisons.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------- |
| name | [ string](#string) | Name of the reconciliation this override applies to. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.bisection\_drill | [ BisectionDrillTarget](#bisectiondrilltarget) | Drill into specific bisection mismatch leaves from a prior run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.aggregate\_drill | [ AggregateDrillTarget](#aggregatedrilltarget) | Drill into specific aggregate groups or add new dimensions from a prior run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.rerun | [ RerunAction](#rerunaction) | Re-run the reconciliation from scratch, optionally with config changes. |
### ReconciliationRunRequest
(synq.agent.recon.v1.ReconciliationRunRequest)
ReconciliationRunRequest describes what to execute in a reconciliation run.
It can start a fresh run, continue from a previous audit, or drill deeper
into specific mismatches found in a prior run.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite.suite | [optional ReconciliationSuite](#reconciliationsuite) | Suite to execute. Required for fresh runs. When continuing from a parent audit, can be omitted to reuse the parent's suite. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_audit.parent\_audit | [optional AuditLog](#auditlog) | Parent audit log to continue from. When set, this run resumes or drills deeper into the parent's results. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_filter.filter | [optional ReconciliationFilter](#reconciliationfilter) | Filter which reconciliations to execute. When empty, all reconciliations in the suite are executed. |
| variable\_overrides | [map VariableOverridesEntry](#variableoverridesentry) | Variable overrides applied on top of suite-level variables. |
| overrides | [repeated ReconciliationOverride](#reconciliationoverride) | Per-reconciliation drill-down and override instructions. |
### ReconciliationRunRequest.VariableOverridesEntry
(synq.agent.recon.v1.ReconciliationRunRequest.VariableOverridesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### RerunAction
(synq.agent.recon.v1.RerunAction)
RerunAction re-runs a reconciliation from scratch with optional config overrides.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_mode.mode | [optional ReconciliationMode](#reconciliationmode) | Override the comparison mode. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bisection.bisection | [optional BisectionConfig](#bisectionconfig) | Override the bisection configuration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reporting.reporting | [optional ReportingConfig](#reportingconfig) | Override the reporting configuration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_aggregate.aggregate | [optional AggregateConfig](#aggregateconfig) | Override the aggregate configuration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error\_handling.error\_handling | [optional ErrorHandlingConfig](#errorhandlingconfig) | Override the error handling configuration. |
### SegmentTarget
(synq.agent.recon.v1.SegmentTarget)
SegmentTarget identifies a specific segment to drill into.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_min\_key.min\_key | [optional Value](#value) | Minimum key (inclusive). Unset means unbounded. |
The encoding matches SegmentInfo in the audit log, and is deliberately not self-describing: a numeric key appears as a JSON number when it fits the exact double range and as a JSON string above it, while a textual key always appears as a JSON string. A composite key is a JSON list, one element per key column. Only the key column's own type distinguishes the cases, so the runner types these bounds after resolving the query shape. |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_max\_key.max\_key | [optional Value](#value) | Maximum key (exclusive). Unset means unbounded. |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time\_bucket.time\_bucket | [optional string](#string) | Time bucket (for time-based segmentation). |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_seed\_depth.seed\_depth | [optional int32](#int32) | Depth this segment sat at in the run being resumed.
Carried so a resumed drill reports true absolute depth and can budget its own depth limit as "this many further levels" rather than re-spending a budget the previous run already consumed. |
### CutoffApplyConfig
(synq.agent.recon.v1.CutoffApplyConfig)
CutoffApplyConfig controls how the resolved cutoff value is applied as a WHERE filter.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_column.column | [optional string](#string) | Column to filter on. When not set, uses the derivation column from that side. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_operator.operator | [optional string](#string) | Comparison operator. Default: "≤". |
### CutoffConfig
(synq.agent.recon.v1.CutoffConfig)
CutoffConfig defines a dynamic cutoff filter for sync reconciliation.
It derives a watermark value from the actual data (e.g., MAX(created\_at))
to automatically exclude rows that haven't been synced yet.
The cutoff is resolved at runtime before comparison queries run:
1. Derive watermark(s) from source and/or target via aggregate queries.
2. Combine them (default: MIN of both sides).
3. Optionally truncate to a time boundary and apply an offset.
4. Apply as WHERE filter to both source and target queries.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source.source | [optional CutoffSideConfig](#cutoffsideconfig) | Per-side watermark derivation config for source. When not set, derives from target only. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_target.target | [optional CutoffSideConfig](#cutoffsideconfig) | Per-side watermark derivation config for target. When not set, derives from source only. |
| combine | [ CutoffCombineStrategy](#cutoffcombinestrategy) | How to combine watermarks when both sides are configured. Default: MIN (use the smaller watermark for safety). Ignored when only one side has a watermark. |
| truncate | [ CutoffTruncateUnit](#cutofftruncateunit) | Truncate the combined watermark to a time boundary. Example: HOUR truncates 08:47:12 to 08:00:00. Applied after combining, before offset. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_offset.offset | [optional Duration](#duration) | Time offset applied after truncation. Negative durations subtract from the cutoff (safety buffer). Example: "-30m" shifts the cutoff 30 minutes earlier. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_apply\_source.apply\_source | [optional CutoffApplyConfig](#cutoffapplyconfig) | How to apply the cutoff as a WHERE filter on the source side. When not set, uses the source derivation column with ≤ operator. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_apply\_target.apply\_target | [optional CutoffApplyConfig](#cutoffapplyconfig) | How to apply the cutoff as a WHERE filter on the target side. When not set, uses the target derivation column with ≤ operator. |
### CutoffSideConfig
(synq.agent.recon.v1.CutoffSideConfig)
CutoffSideConfig configures watermark derivation for one side (source or target).
There are two modes:
1. Column + aggregate (default): auto-generates a watermark query from the dataset.
For table-based datasets, queries the table directly (the column does NOT need
to be in the reconciliation column list). For query-based datasets, wraps the
query as a subquery (the column MUST be in the query's SELECT list).
2. Custom query: provide a SQL query that returns a single row with a "watermark" column.
Use this when the auto-generated query doesn't work (e.g., complex joins, custom logic).
After resolution at runtime, the `query` field is always populated with the actual SQL
that was executed, regardless of which mode was used. This ensures the audit log captures
the exact query for reproducibility.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| column | [ string](#string) | Column to derive the watermark from (e.g., "created\_at", "synced\_at"). Required when query is not set. |
| aggregate | [ CutoffAggregateFunction](#cutoffaggregatefunction) | Aggregate function to derive the watermark. Default: MAX. Only used when query is not set. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_query.query | [optional string](#string) | Custom SQL query for watermark derivation. Must return a single row with a "watermark" column. When not set, auto-generated from the dataset at runtime. After resolution, this field is populated with the actual query that was executed. |
### SYNQ
(synq.agent.v1.SYNQ)
SYNQ contains authentication and connection details for the Coalesce Quality platform
| Field | Type | Description |
| ---------------- | ------------------ | ------------------------------------------------ |
| client\_id | [ string](#string) | Client ID for OAuth authentication |
| client\_secret | [ string](#string) | Client secret for OAuth authentication |
| endpoint | [ string](#string) | Coalesce Quality API agent endpoint (host:port) |
| ingest\_endpoint | [ string](#string) | Coalesce Quality API ingest endpoint (host:port) |
| oauth\_url | [ string](#string) | OAuth authentication URL |
### AnalysisEvidence
(synq.agent.sre.v1.AnalysisEvidence)
AnalysisEvidence contains detailed analysis of the issue based on collected data.
This should only be used as a last resort when no other more specialized evidence types
(history, root cause, related issues, or changes) could be collected.
It provides a comprehensive understanding of the problem and its implications.
| Field | Type | Description |
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| analysis | [ string](#string) | Detailed analysis of the issue, including observations, patterns, and potential implications. This should provide clear reasoning for the conclusions drawn. |
| sql\_queries | [repeated string](#string) | SQL queries which were executed to investigate the issue and collect the evidence. |
### ChangeEvidence
(synq.agent.sre.v1.ChangeEvidence)
ChangeEvidence documents recent changes that may have contributed to the issue.
This helps in understanding if the issue is related to recent modifications.
| Field | Type | Description |
| --------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| entities | [repeated Identifier](#identifier) | List of entities (e.g., services, configurations) that have recently changed and may be related to the current issue. |
| entities\_synq\_paths | [repeated string](#string) | Read-only list of paths matching entities. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| change\_description | [ string](#string) | Detailed description of the changes that were detected and their potential impact on the current issue. |
| change\_ids | [repeated string](#string) | When available identifiers of specific change IDs |
### CodeChange
(synq.agent.sre.v1.CodeChange)
CodeChange represents a specific change in a file within a commit.
| Field | Type | Description |
| ------------------- | ------------------ | ------------------------------------------------ |
| file\_path | [ string](#string) | Path to the file that was changed. |
| start\_line | [ int32](#int32) | Starting line number of the change (inclusive). |
| end\_line | [ int32](#int32) | Ending line number of the change (inclusive). |
| change\_description | [ string](#string) | Description of what was changed in this section. |
### CommitEvidence
(synq.agent.sre.v1.CommitEvidence)
CommitEvidence documents code changes that may have contributed to the issue.
This helps in understanding if the issue is related to recent code modifications.
| Field | Type | Description |
| ----------------------- | ---------------------------------- | -------------------------------------------------------- |
| change\_id | [ string](#string) | ID of the change that introduced the code modifications. |
| relevant\_code\_changes | [repeated CodeChange](#codechange) | List of relevant code changes in the commit. |
### DataQueryEvidenceItem
(synq.agent.sre.v1.DataQueryEvidenceItem)
DataQueryEvidenceItem represents a single SQL query and its analysis.
| Field | Type | Description |
| -------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| query\_id | [ string](#string) | DEPRECATED: Previously held the SQL query string despite being named query\_id. Use the `sql` field instead. Kept for backward compatibility — readers should prefer `sql` when present, falling back to `query_id` for older evidence. |
| data\_analysis | [ string](#string) | Analysis specific to this query's results and their implications. |
| sql | [ string](#string) | The SQL query that was executed. |
### DataQueryEvidenceV2
(synq.agent.sre.v1.DataQueryEvidenceV2)
DataQueryEvidenceV2 contains SQL queries and their analysis results with query IDs.
This helps in understanding the issue through data analysis with query tracking.
| Field | Type | Description |
| ----- | -------------------------------------------------------- | ------------------------------------------------------------------------------- |
| items | [repeated DataQueryEvidenceItem](#dataqueryevidenceitem) | List of data query evidence items, each containing a query ID and its analysis. |
### EvidenceItem
(synq.agent.sre.v1.EvidenceItem)
EvidenceItem represents a single piece of evidence collected during the triage investigation.
Each evidence item must have a title and one of the specific evidence types.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| evidence\_id | [ string](#string) | Unique identifier of the evidence item. |
| issue\_ids | [repeated string](#string) | List of issue IDs that should be annotated with the provided evidence. Each ID must be a valid UUID. |
| title | [ string](#string) | Brief, descriptive title summarizing the type of evidence collected. This helps in quickly understanding the nature of the evidence. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.issue\_history | [ HistoryEvidence](#historyevidence) | Historical evidence showing similar past issues that may help understand the current situation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.root\_cause | [ RootCauseEvidence](#rootcauseevidence) | Evidence pointing to the likely root cause of the issue. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.related\_issue | [ RelatedIssueEvidence](#relatedissueevidence) | Evidence showing related issues that may be connected to the current investigation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.change | [ ChangeEvidence](#changeevidence) | Evidence of recent changes that may have contributed to the issue. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.analysis | [ AnalysisEvidence](#analysisevidence) | Evidence containing detailed analysis of the issue. DEPRECATED: This type will be gradually retired in favor of more specific evidence types like DataQueryEvidenceV2 and OtherEvidence. Please use those types for new evidence. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.commit | [ CommitEvidence](#commitevidence) | Evidence containing code changes and commit information. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.data\_query\_v2 | [ DataQueryEvidenceV2](#dataqueryevidencev2) | Evidence containing SQL queries and data analysis results with query IDs. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.other | [ OtherEvidence](#otherevidence) | Evidence containing general analysis that doesn't fit into other specialized types. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.impacted\_dataproduct | [ ImpactedDataproductEvidence](#impacteddataproductevidence) | Evidence of impact on important dataproduct |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) evidence.impacted\_owner | [ ImpactedOwnerEvidence](#impactedownerevidence) | Evidence of serious impact on business owner |
### HistoryEvidence
(synq.agent.sre.v1.HistoryEvidence)
HistoryEvidence represents historical context from similar past issues.
This helps in understanding if the current issue is recurring or has known patterns.
| Field | Type | Description |
| ---------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs that are similar to the currently triaged issue. These historical issues can provide insights into resolution patterns. |
### ImpactedDataproductEvidence
(synq.agent.sre.v1.ImpactedDataproductEvidence)
ImpactedDataproduct documents Data Products that are significantly affected by the issue.
This helps in understanding the business impact and prioritizing resolution efforts.
| Field | Type | Description |
| ---------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| impact\_reason | [ string](#string) | Detailed explanation of how and why the dataproduct is impacted by the issue. This should provide clear reasoning for the impact assessment. |
| dataproduct\_ids | [repeated string](#string) | List of dataproduct IDs that are affected by the issue. These IDs should reference existing dataproducts in the system. |
### ImpactedOwnerEvidence
(synq.agent.sre.v1.ImpactedOwnerEvidence)
ImpactedOwner documents business owners or teams that are seriously affected by the issue.
This helps in understanding stakeholder impact and communication requirements.
| Field | Type | Description |
| -------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| impact\_reason | [ string](#string) | Detailed explanation of how and why the owner is impacted by the issue. This should provide clear reasoning for the impact assessment. |
| owner\_ids | [repeated string](#string) | List of owner IDs that are affected by the issue. These IDs should reference existing owners or teams in the system. |
### OtherEvidence
(synq.agent.sre.v1.OtherEvidence)
OtherEvidence contains general analysis that doesn't fit into other specialized evidence types.
This should be used when the analysis doesn't involve SQL queries, code changes, or other
specialized evidence types.
| Field | Type | Description |
| -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| analysis | [ string](#string) | Detailed analysis of the issue, including observations, patterns, and potential implications. This should provide clear reasoning for the conclusions drawn. |
### RelatedIssueEvidence
(synq.agent.sre.v1.RelatedIssueEvidence)
RelatedIssueEvidence identifies other issues that may be connected to the current investigation.
This helps in understanding broader context and potential dependencies.
| Field | Type | Description |
| ---------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs that are related to the current investigation. These issues may be symptoms of the same underlying problem or have dependencies. |
### RootCauseEvidence
(synq.agent.sre.v1.RootCauseEvidence)
RootCauseEvidence identifies the likely root cause of the issue being investigated.
This helps in understanding the fundamental reason behind the problem.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_issue\_id.issue\_id | [optional string](#string) | ID of the issue that is believed to be the root cause of the current issue. |
| entity\_ids | [repeated string](#string) | IDs of entities that are identified as the root cause. |
| execution\_ids | [repeated string](#string) | IDs of executions that are identified as the root cause. |
| analysis | [ string](#string) | Analysis text describing the root cause. |
### AcceptFeedback
(synq.agent.sre.v1.AcceptFeedback)
### ConclusionFeedback
(synq.agent.sre.v1.ConclusionFeedback)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------------------- | ----------- |
| user | [ string](#string) | none |
| feedback\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feedback.accept | [ AcceptFeedback](#acceptfeedback) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feedback.dismiss | [ DismissFeedback](#dismissfeedback) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feedback.retriage | [ ReTriageFeedback](#retriagefeedback) | none |
### DismissFeedback
(synq.agent.sre.v1.DismissFeedback)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_comment.comment | [optional string](#string) | none |
### ReTriageFeedback
(synq.agent.sre.v1.ReTriageFeedback)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| instruction | [ string](#string) | none |
### LlmConfig
(synq.agent.sre.v1.LlmConfig)
| Field | Type | Description |
| ------------------------------ | ------------------------ | ------------------------------------------------------ |
| openai | [ OpenAIApi](#openaiapi) | none |
| triage\_parallelism | [ int32](#int32) | How many Issue triages can run in parallel |
| test\_suggestions\_parallelism | [ int32](#int32) | How many test suggestions can be processed in parallel |
### OpenAIApi
(synq.agent.sre.v1.OpenAIApi)
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------------------------------------------------------------------- |
| base\_url | [ string](#string) | Base URL of the OpenAPI compatible endpoint |
| api\_key | [ string](#string) | API key to use for the interaction with the API |
| thinking\_model | [ string](#string) | Model to use for complex operations |
| summary\_model | [ string](#string) | Model to use for simpler operations, e.g. summary generation or improving the format of messages. |
### SubmitFeatureRequestRequest
(synq.agent.sre.v1.SubmitFeatureRequestRequest)
Request to submit a feature request. Should only be used as a last resort when no
existing tool can handle the user's request.
| Field | Type | Description |
| ----------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| description | [ string](#string) | A clear description of what the user needs, including context about what they were trying to accomplish and why the current tools are insufficient. This should only be populated when no existing tool can fulfill the request. |
### SubmitFeatureRequestResponse
(synq.agent.sre.v1.SubmitFeatureRequestResponse)
Response for the SubmitFeatureRequest operation.
### AddToIncidentConclusion
(synq.agent.sre.v1.AddToIncidentConclusion)
AddToIncidentConclusion indicates that the issue should be added to an existing incident.
This conclusion should be supported by evidence showing the connection to the existing incident.
| Field | Type | Description |
| ------------ | ------------------ | --------------------------------------------------------------- |
| incident\_id | [ string](#string) | ID of the existing incident that this issue should be added to. |
### DeclareIncidentConclusion
(synq.agent.sre.v1.DeclareIncidentConclusion)
DeclareIncidentConclusion indicates that the issue requires immediate attention as an incident.
This conclusion should be supported by evidence showing significant impact or risk.
| Field | Type | Description |
| ----------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| title | [ string](#string) | Suggested title for the incident that will be created. Should be clear and concise to quickly communicate the situation. |
| description | [ string](#string) | Detailed description of the incident situation, including: - What is happening - Potential impact - Affected systems or services - Any immediate actions needed |
### IssueConclusion
(synq.agent.sre.v1.IssueConclusion)
IssueConclusion represents the final determination made by the LLM agent about an issue.
Each conclusion type must be supported by appropriate evidence collected during investigation.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| conclusion\_id | [ string](#string) | Unique identifier of the conclusion. |
| issue\_ids | [repeated string](#string) | List of issue IDs that should be concluded with the specified conclusion. |
| title | [ string](#string) | Brief, single-line description summarizing the triage conclusion. Max 5 words. |
| summary | [ string](#string) | Detailed markdown-formatted description explaining the conclusion and the reasoning based on all collected evidence. |
| concluded\_at | [ Timestamp](#timestamp) | Timestamp when the conclusion was made. |
| is\_final\_conclusion | [ bool](#bool) | Indicates that this is final conclusion and SRE agent won't change it unless new evidence is provided to change it. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.set\_expected | [ SetExpectedConclusion](#setexpectedconclusion) | Conclusion that the issue is expected behavior. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.set\_no\_action\_needed | [ SetNoActionNeededConclusion](#setnoactionneededconclusion) | Conclusion that no action is needed as the issue will resolve itself. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.set\_fixed | [ SetFixedConclusion](#setfixedconclusion) | Conclusion that the issue has been fixed and can be closed. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.declare\_incident | [ DeclareIncidentConclusion](#declareincidentconclusion) | Conclusion that the issue requires incident declaration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.add\_to\_incident | [ AddToIncidentConclusion](#addtoincidentconclusion) | Conclusion that the issue should be added to an existing incident. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.request\_for\_human\_review | [ RequestForHumanReviewConclusion](#requestforhumanreviewconclusion) | Conclusion that human review is needed for further investigation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) conclusion.unexplained | [ UnexplainedConclusion](#unexplainedconclusion) | Conclusion that the issue cannot be explained and needs urgent human attention. |
### IssueConclusionWithEvidence
(synq.agent.sre.v1.IssueConclusionWithEvidence)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| conclusion | [ IssueConclusion](#issueconclusion) | IssueConclusion represents the final determination made by the LLM agent about an issue. |
| original\_issue\_ids | [repeated string](#string) | List of issues for which original conclusion was created. |
| evidence | [repeated EvidenceItem](#evidenceitem) | Collection of structured evidence items collected during the investigation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user\_feedback.user\_feedback | [optional ConclusionFeedback](#conclusionfeedback) | Optional feedback given by the user on the SRE generated conclusion. |
### RequestForHumanReviewConclusion
(synq.agent.sre.v1.RequestForHumanReviewConclusion)
RequestForHumanReviewConclusion indicates that the issue needs human review.
This conclusion should be used when:
* The agent has collected some evidence but cannot make a definitive conclusion
* The issue requires human judgment or expertise
* The impact is unclear or needs human assessment
### SetExpectedConclusion
(synq.agent.sre.v1.SetExpectedConclusion)
SetExpectedConclusion indicates that the issue is expected behavior and no action is needed.
This conclusion should be supported by evidence showing this is normal operation.
### SetFixedConclusion
(synq.agent.sre.v1.SetFixedConclusion)
SetFixedConclusion indicates that the issue has already been resolved and can be closed.
This conclusion should be supported by evidence showing the fix has been applied and verified.
### SetNoActionNeededConclusion
(synq.agent.sre.v1.SetNoActionNeededConclusion)
SetNoActionNeededConclusion indicates that the issue will resolve itself without intervention.
This conclusion should be supported by evidence showing the issue is temporary or self-healing.
### UnexplainedConclusion
(synq.agent.sre.v1.UnexplainedConclusion)
UnexplainedConclusion indicates that the agent was unable to collect sufficient evidence
to understand or explain the issue. This conclusion requires high-priority human review
as it may indicate a serious or complex problem that needs immediate attention.
### AcceptPromptSuggestionRequest
(synq.agent.sre.v1.AcceptPromptSuggestionRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_edited\_value.edited\_value | [optional string](#string) | If set, the user edited the suggestion before accepting. The server records both `suggested_value` (unchanged) and `applied_value` (= `edited_value`). Hard-capped at 16384 bytes to match the SRE agent prompt field limits. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_note.note | [optional string](#string) | Optional short free-text note recorded with the decision. Capped at 512 bytes — it is a one-line annotation for the audit trail, not a place to restate the prompt. |
### AcceptPromptSuggestionResponse
(synq.agent.sre.v1.AcceptPromptSuggestionResponse)
| Field | Type | Description |
| ---------- | -------------------------------------- | ----------- |
| suggestion | [ PromptSuggestion](#promptsuggestion) | none |
### AgentTask
(synq.agent.sre.v1.AgentTask)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| task\_id | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deadline\_at.deadline\_at | [optional Timestamp](#timestamp) | Deadline after which the task should not be processed. If set, the agent should skip or abort tasks past this time. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) task.triage | [ TriageTask](#triagetask) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) task.suggest\_tests | [ SuggestTestsTask](#suggestteststask) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) task.evaluate | [ EvaluateTask](#evaluatetask) | none |
### AgentTaskResponse
(synq.agent.sre.v1.AgentTaskResponse)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------- |
| task\_id | [ string](#string) | none |
| message | [ string](#string) | Human visible message |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error.error | [optional string](#string) | Error message indicating a problem |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) result.evaluate\_response | [ EvaluateResponse](#evaluateresponse) | none |
### ConnectRequest
(synq.agent.sre.v1.ConnectRequest)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) message.hello | [ Hello](#hello) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) message.task\_response | [ AgentTaskResponse](#agenttaskresponse) | none |
### ConnectResponse
(synq.agent.sre.v1.ConnectResponse)
| Field | Type | Description |
| ----- | -------------------------------- | ----------- |
| tasks | [repeated AgentTask](#agenttask) | none |
### DismissPromptSuggestionRequest
(synq.agent.sre.v1.DismissPromptSuggestionRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reason.reason | [optional string](#string) | Optional short free-text reason recorded with the decision. Capped at 512 bytes — a one-line justification for the audit trail. |
### DismissPromptSuggestionResponse
(synq.agent.sre.v1.DismissPromptSuggestionResponse)
| Field | Type | Description |
| ---------- | -------------------------------------- | ----------- |
| suggestion | [ PromptSuggestion](#promptsuggestion) | none |
### DwhConnection
(synq.agent.sre.v1.DwhConnection)
| Field | Type | Description |
| ---------------------- | --------------------------------------- | -------------------------------------------------------------------------------- |
| connection\_id | [ string](#string) | This will be connection in the agent or integration\_id when managed |
| instance | [ string](#string) | What is the instance of this, e.g. BigQuery project or Databricks workspace |
| type | [ string](#string) | Type of the DWH connection |
| databases | [repeated string](#string) | Databases in this instance, this would be BigQuery dataset or Databricks catalog |
| parameters | [map ParametersEntry](#parametersentry) | Extra parameters present on the connection |
| agent\_access\_enabled | [ bool](#bool) | Indicates that Coalesce Quality managed agent can access this connection |
### DwhConnection.ParametersEntry
(synq.agent.sre.v1.DwhConnection.ParametersEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### EvaluateTask
(synq.agent.sre.v1.EvaluateTask)
Task to evaluate an LLM request on the agent side (for self-hosted agents).
| Field | Type | Description |
| ------- | ------------------------------------ | -------------------------------------------------------------- |
| request | [ EvaluateRequest](#evaluaterequest) | The evaluate request to be processed by the agent's local LLM. |
### GetConfigRequest
(synq.agent.sre.v1.GetConfigRequest)
### GetConfigResponse
(synq.agent.sre.v1.GetConfigResponse)
| Field | Type | Description |
| ------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Workspace to which agent is authenticated |
| triage\_system\_prompt | [ string](#string) | Extra instructions used while triaging and concluding issues. |
| tester\_system\_prompt | [ string](#string) | Extra instructions used while suggesting tests. |
| workspace\_system\_prompt | [ string](#string) | Extra instructions describing workspace to which agent is connected. |
| synq\_dwh\_connections | [repeated DwhConnection](#dwhconnection) | Description of all DWH connections/integrations configured in Coalesce Quality. Will indicate to the agent that it can't access all the data sources if agent has no connections enabled. |
| issue\_grouping\_system\_prompt | [ string](#string) | Extra instructions describing how issues should be grouped |
| issue\_grouping\_disabled | [ bool](#bool) | Indicates that SRE shouldn't group any issues |
### Hello
(synq.agent.sre.v1.Hello)
| Field | Type | Description |
| -------------- | ------------------ | ----------- |
| name | [ string](#string) | none |
| build\_version | [ string](#string) | none |
### ListPromptSuggestionsRequest
(synq.agent.sre.v1.ListPromptSuggestionsRequest)
| Field | Type | Description |
| -------- | ---------------------------------------------------------- | --------------------------- |
| fields | [repeated PromptField](#promptfield) | Empty = include all fields. |
| statuses | [repeated PromptSuggestionStatus](#promptsuggestionstatus) | Empty = pending only. |
### ListPromptSuggestionsResponse
(synq.agent.sre.v1.ListPromptSuggestionsResponse)
| Field | Type | Description |
| ----------- | ---------------------------------------------- | ----------- |
| suggestions | [repeated PromptSuggestion](#promptsuggestion) | none |
### PromptSuggestion
(synq.agent.sre.v1.PromptSuggestion)
| Field | Type | Description |
| ---------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Server-assigned UUID. |
| workspace | [ string](#string) | Workspace the suggestion belongs to. Always populated, always matches the caller's workspace for customer-facing reads. |
| field | [ PromptField](#promptfield) | none |
| status | [ PromptSuggestionStatus](#promptsuggestionstatus) | none |
| baseline\_value | [ string](#string) | Value of the targeted prompt field as it was at the moment the suggestion was produced. Used to detect drift on Accept. |
| suggested\_value | [ string](#string) | Value proposed by the analyser. A full replacement for the targeted prompt; diffed against `baseline_value` in the review UI (see the producer guidance on `RecordPromptSuggestionRequest.suggested_value`). |
| rationale | [ string](#string) | Short markdown explanation produced by the analyser (≤ 2048 bytes), rendered as a "why" callout above the diff in the review UI. |
| evidence\_json | [ bytes](#bytes) | Opaque JSON encoded by the producer (e.g. references to source entities and incidents). Returned only to producer-scoped callers; customer reads see an empty value. |
| source | [ string](#string) | Producer identifier + version, e.g. `"offline_audit_v1"`. |
| produced\_at | [ Timestamp](#timestamp) | none |
| reviewed\_by | [ string](#string) | Identity of whoever reviewed the suggestion (derived from the JWT actor). Empty while the suggestion is pending. |
| reviewed\_at | [ Timestamp](#timestamp) | none |
| decision\_note | [ string](#string) | Optional short reason on dismiss, or note on accept (≤ 512 bytes). A one-line annotation captured for the audit trail. |
| applied\_value | [ string](#string) | Value actually written to the prompt field. Differs from `suggested_value` when the user edited before accepting. |
### RecordPromptSuggestionRequest
(synq.agent.sre.v1.RecordPromptSuggestionRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| field | [ PromptField](#promptfield) | Targets the workspace from the JWT (back-office producers select the workspace via the standard x-synq-workspace-override header). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suggested\_value.suggested\_value | [optional string](#string) | Full replacement value for the targeted prompt field, hard-capped at 16384 bytes to match the SRE agent prompt field limit. |
Explicit-presence (`optional`) so the field can carry an empty string with meaning. An empty value is a deliberate proposal to REMOVE the prompt entirely (clear the override back to the built-in default), distinct from omitting the field. Use this when a customised prompt is judged counter-productive and the workspace is better off with no override at all.
`required` is intentionally NOT set: that rule rejects the empty string, which would make a removal proposal un-expressible. Presence (the field must be set at all) is enforced by the handler via a nil check, so an omitted field is still rejected while an explicit "" is accepted.
Producer guidance — propose the *smallest* change that achieves the goal. Start from the current prompt value and append, delete, or rewrite only the relevant section; do not regenerate the whole prompt from scratch. The reviewer is shown a Current-vs-Suggested diff, so a surgical edit is far easier to approve than a wholesale rewrite that rewords every line.
Keep individual lines short and break content into paragraphs separated by newlines instead of collapsing everything onto one long line. The review UI diffs line by line, so well-broken text produces a readable, minimal diff; a single monster line shows up as one giant replaced block. |
\| rationale | [ string](#string) | Short markdown explanation of why the change is proposed, capped at 2048 bytes. Shown to the reviewer as a "why" callout above the diff, so keep it to a few tight sentences or bullet points — it justifies the change, it does not restate the prompt. As with `suggested_value`, prefer short lines / paragraphs over one long line. |
\| evidence\_json | [ bytes](#bytes) | Opaque JSON: structured pointers the analyser used to produce the suggestion (top entities, sample issues, etc.). Stored verbatim for traceability. |
\| source | [ string](#string) | Producer identifier + version, e.g. `"offline_audit_v1"`. A short slug, not free text — capped at 128 bytes. |
### RecordPromptSuggestionResponse
(synq.agent.sre.v1.RecordPromptSuggestionResponse)
| Field | Type | Description |
| ---------- | -------------------------------------- | ----------------------------------------------------------------------- |
| suggestion | [ PromptSuggestion](#promptsuggestion) | Empty when the live baseline already matches `suggested_value` (no-op). |
### SuggestTestsTask
(synq.agent.sre.v1.SuggestTestsTask)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| entity\_ids | [repeated Identifier](#identifier) | none |
### TriageTask
(synq.agent.sre.v1.TriageTask)
| Field | Type | Description |
| ---------- | -------------------------- | ----------- |
| issue\_ids | [repeated string](#string) | none |
### IssueTriageState
(synq.agent.sre.v1.IssueTriageState)
IssueTriageState represents the current state of an issue in the SRE agent's investigation workflow.
This state is used to track the progress of automated triage and coordinate between different parts of the system.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | Unique identifier of the issue being investigated by the SRE agent |
| status | [ IssueTriageStatus](#issuetriagestatus) | Current status of the issue in the triage workflow, indicating the stage of investigation |
| last\_updated\_at | [ Timestamp](#timestamp) | Timestamp indicating when the issue triage state was last updated |
| failure\_category | [ TriageFailureCategory](#triagefailurecategory) | Structured failure category for the frontend to render appropriate messages, only set when status is FAILED |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_failure\_details.failure\_details | [optional string](#string) | Raw error details for debugging, only set when status is FAILED. Visible to Coalesce Quality admins. |
### BatchLatestConclusionsRequest
(synq.agent.sre.v1.BatchLatestConclusionsRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ----------------------------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs for which latest conclusion should be returned. |
### BatchLatestConclusionsResponse
(synq.agent.sre.v1.BatchLatestConclusionsResponse)
| Field | Type | Description |
| ----------- | -------------------------------------------------------------------- | ----------- |
| conclusions | [repeated IssueConclusionWithEvidence](#issueconclusionwithevidence) | none |
### BatchTriageStateRequest
(synq.agent.sre.v1.BatchTriageStateRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs for which triage status should be returned. |
### BatchTriageStateResponse
(synq.agent.sre.v1.BatchTriageStateResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ----------- |
| states | [map StatesEntry](#statesentry) | none |
### BatchTriageStateResponse.StatesEntry
(synq.agent.sre.v1.BatchTriageStateResponse.StatesEntry)
| Field | Type | Description |
| ----- | -------------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ IssueTriageState](#issuetriagestate) | none |
### ConcludeRequest
(synq.agent.sre.v1.ConcludeRequest)
Request to conclude the triage investigation for one or more issues.
| Field | Type | Description |
| ----------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| session\_id | [ string](#string) | Unique identifier of the triaging session, used to group related operations. |
| conclusion | [ IssueConclusion](#issueconclusion) | IssueConclusion represents the final determination made by the LLM agent about an issue. Each conclusion type must be supported by appropriate evidence collected during investigation. |
| evidence | [repeated EvidenceItem](#evidenceitem) | Collection of evidence items supporting the conclusion. Evidences previously recorded should not be added here. |
### ConcludeResponse
(synq.agent.sre.v1.ConcludeResponse)
Response for the Conclude operation. Empty as the operation is fire-and-forget.
### ListTriageStateRequest
(synq.agent.sre.v1.ListTriageStateRequest)
| Field | Type | Description |
| -------- | ------------------------------------------------ | ----------- |
| statuses | [repeated IssueTriageStatus](#issuetriagestatus) | none |
### ListTriageStateResponse
(synq.agent.sre.v1.ListTriageStateResponse)
| Field | Type | Description |
| ------ | ---------------------------------------------- | ----------- |
| states | [repeated IssueTriageState](#issuetriagestate) | none |
### MarkAsInProgressRequest
(synq.agent.sre.v1.MarkAsInProgressRequest)
| Field | Type | Description |
| ---------- | -------------------------- | --------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs for which work has started. |
### MarkAsInProgressResponse
(synq.agent.sre.v1.MarkAsInProgressResponse)
| Field | Type | Description |
| ------------------ | -------------------------- | ----------- |
| marked\_issue\_ids | [repeated string](#string) | none |
### MarkFailedRequest
(synq.agent.sre.v1.MarkFailedRequest)
| Field | Type | Description |
| -------------- | -------------------------- | -------------------------------------------- |
| issue\_ids | [repeated string](#string) | List of issue IDs for which work has failed. |
| error\_message | [ string](#string) | none |
### MarkFailedResponse
(synq.agent.sre.v1.MarkFailedResponse)
| Field | Type | Description |
| ------------------ | -------------------------- | ----------- |
| marked\_issue\_ids | [repeated string](#string) | none |
### RecordEvidenceRequest
(synq.agent.sre.v1.RecordEvidenceRequest)
Request to record evidence collected during the triage investigation.
| Field | Type | Description |
| ----------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| session\_id | [ string](#string) | Unique identifier of the triaging session, used to group related operations. |
| evidence | [repeated EvidenceItem](#evidenceitem) | Collection of structured evidence items collected during the investigation. Must contain at least one evidence item. |
### RecordEvidenceResponse
(synq.agent.sre.v1.RecordEvidenceResponse)
Response for the RecordEvidence operation. Empty as the operation is fire-and-forget.
### BatchSuggestionStatesRequest
(synq.agent.sre.v1.BatchSuggestionStatesRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### BatchSuggestionStatesResponse
(synq.agent.sre.v1.BatchSuggestionStatesResponse)
| Field | Type | Description |
| ------------------------ | ---------------------------------------------------- | ----------- |
| test\_suggestion\_states | [repeated TestSuggestionState](#testsuggestionstate) | none |
### GetActiveSuggestionStatesForRequest
(synq.agent.sre.v1.GetActiveSuggestionStatesForRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### GetActiveSuggestionStatesForResponse
(synq.agent.sre.v1.GetActiveSuggestionStatesForResponse)
| Field | Type | Description |
| ------------------------ | ---------------------------------------------------- | ----------- |
| test\_suggestion\_states | [repeated TestSuggestionState](#testsuggestionstate) | none |
### ListSuggestionStatesRequest
(synq.agent.sre.v1.ListSuggestionStatesRequest)
| Field | Type | Description |
| -------- | ------------------------------------------------------ | ----------- |
| statuses | [repeated TestSuggestionStatus](#testsuggestionstatus) | none |
### ListSuggestionStatesResponse
(synq.agent.sre.v1.ListSuggestionStatesResponse)
| Field | Type | Description |
| ------------------------ | ---------------------------------------------------- | ----------- |
| test\_suggestion\_states | [repeated TestSuggestionState](#testsuggestionstate) | none |
### MarkAsCancelledRequest
(synq.agent.sre.v1.MarkAsCancelledRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsCancelledResponse
(synq.agent.sre.v1.MarkAsCancelledResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsCompletedRequest
(synq.agent.sre.v1.MarkAsCompletedRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsCompletedResponse
(synq.agent.sre.v1.MarkAsCompletedResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsFailedRequest
(synq.agent.sre.v1.MarkAsFailedRequest)
| Field | Type | Description |
| -------------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
| error\_message | [ string](#string) | none |
### MarkAsFailedResponse
(synq.agent.sre.v1.MarkAsFailedResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsRunningRequest
(synq.agent.sre.v1.MarkAsRunningRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### MarkAsRunningResponse
(synq.agent.sre.v1.MarkAsRunningResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### SuggestForRequest
(synq.agent.sre.v1.SuggestForRequest)
| Field | Type | Description |
| ------------ | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
| user\_prompt | [ string](#string) | none |
### SuggestForResponse
(synq.agent.sre.v1.SuggestForResponse)
### EvaluateRequest
(synq.agent.sre.v1.EvaluateRequest)
Request to evaluate an LLM request with structured output.
| Field | Type | Description |
| -------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| output\_schema | [ Struct](#struct) | JSON schema defining the structure of the expected output. The LLM will produce output conforming to this schema. |
| system\_prompt | [ string](#string) | Main system prompt providing instructions to the LLM. This should be constant as it will be cached for efficiency. |
| messages | [repeated Message](#message) | History of messages in the conversation. Must contain at least one message. The last message is used as the final request to the LLM. |
| model\_type | [ ModelType](#modeltype) | Type of model to use for the evaluation. Defaults to MODEL\_TYPE\_SUMMARY if not specified or set to MODEL\_TYPE\_UNSPECIFIED. |
### EvaluateResponse
(synq.agent.sre.v1.EvaluateResponse)
Response from the LLM evaluation.
| Field | Type | Description |
| ------- | ------------------------------------------ | ----------------------------------------------------------------- |
| output | [ Struct](#struct) | Structured output from the LLM conforming to the provided schema. |
| metrics | [ LlmResponseMetrics](#llmresponsemetrics) | Metrics about the LLM response. |
### LlmResponseMetrics
(synq.agent.sre.v1.LlmResponseMetrics)
Metrics about the LLM response.
| Field | Type | Description |
| -------------------- | ------------------ | ---------------------------------------------------- |
| input\_tokens | [ int32](#int32) | Number of tokens in the input prompt and messages. |
| output\_tokens | [ int32](#int32) | Number of tokens in the generated output. |
| total\_tokens | [ int32](#int32) | Total number of tokens used (input + output). |
| latency\_ms | [ int64](#int64) | Time taken to generate the response in milliseconds. |
| model | [ string](#string) | Model identifier used for the evaluation. |
| cache\_write\_tokens | [ int32](#int32) | Number of tokens written to the prompt cache. |
| cache\_read\_tokens | [ int32](#int32) | Number of tokens read from the prompt cache. |
### Message
(synq.agent.sre.v1.Message)
A single message in the conversation history.
| Field | Type | Description |
| ------- | ---------------------------- | --------------------------- |
| role | [ MessageRole](#messagerole) | Role of the message author. |
| content | [ string](#string) | Content of the message. |
### Config
(synq.agent.sre.v1.Config)
Config represents the main configuration for the SRE agent
| Field | Type | Description |
| ----------- | ----------------------------------------- | --------------------------------------- |
| synq | [ SYNQ](#synq) | Coalesce Quality platform configuration |
| connections | [map ConnectionsEntry](#connectionsentry) | Map of connection configurations |
| llm | [ LlmConfig](#llmconfig) | none |
### Config.ConnectionsEntry
(synq.agent.sre.v1.Config.ConnectionsEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Connection](#connection) | none |
### TestSuggestionState
(synq.agent.sre.v1.TestSuggestionState)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------- |
| workspace | [ string](#string) | none |
| path | [ string](#string) | none |
| identifier | [ Identifier](#identifier) | none |
| status | [ TestSuggestionStatus](#testsuggestionstatus) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| scheduled\_at | [ Timestamp](#timestamp) | none |
| updated\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_user\_prompt.last\_user\_prompt | [optional string](#string) | none |
### FolderOf
(synq.queries.v1.FolderOf)
Resolves the folder(s) containing a set of assets, for use as the folder
source of `InFolder` — i.e. "everything in the same folder as these assets".
Name the assets either the simple way (`entity_ids`, opaque asset ids) or with
a full `input_query` when they need to be computed (e.g. by name or type). Set
exactly one.
| Field | Type | Description |
| ----------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entity\_ids | [repeated string](#string) | Simplified source: the assets named directly by opaque entity id. Use this for the common "same folder as these specific assets" case; equivalent to an input\_query that lists the same ids. |
| input\_query | [ Query](#query) | General source: resolve the folder(s) of whatever assets this query matches (e.g. a name or type filter). Use when the assets can't be listed up front. |
| include\_all\_ancestors | [ bool](#bool) | When false (default): only each asset's immediate parent folder. When true: every ancestor folder up the hierarchy, so `InFolder` then also matches assets in those ancestor folders. |
### IdentitiesOf
(synq.queries.v1.IdentitiesOf)
Resolves to the identities of whatever the inner query matches.
The same real-world table is often described by several assets — a
transformation model and the warehouse table it materialises into are one
asset with several representations. Those representations form an identity
group. IdentitiesOf takes the assets matched by `input_query` and returns
their identity groups, so a selection made in one platform's terms also
covers the equivalent assets in every other platform.
The typical use is subtraction: "this warehouse database, except whatever my
transformation tool already owns" is an EXCEPT whose removal clause is an
IdentitiesOf over the transformation models. Without it the two selections
overlap on every materialised table.
| Field | Type | Description |
| ---------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| input\_query | [ Query](#query) | The assets whose identities to resolve. Required. |
| limit\_to\_types | [repeated Type](#type) | Restrict the result to these types. When empty, only the other members of each identity group are returned. When set, an input asset that already has one of these types is returned as well. |
### InFolder
(synq.queries.v1.InFolder)
Resolves to entities located in one or more folders.
Give the folders exactly one way (they are mutually exclusive; if more than
one is set, `folders` wins, then `folder_of`, then `path`):
* `folders` — the preferred, human-authorable form: name each folder by
its root entity plus its ordered folder-name segments. No
opaque ids required.
* `folder_of` — "the same folder(s) as these assets": resolves the folder(s)
containing the assets matched by an inner query, then matches
everything in them. Lets you select siblings without naming a
folder.
* `path` — legacy opaque folder identifiers. Kept for back-compat;
prefer `folders`. Discover a folder's structured address
with the folders navigation API instead of hand-writing an id.
`deep` controls recursion (see its field comment).
InFolder lives here rather than in query\_parts.proto because FolderOf nests a
full Query, which would make query\_parts.proto import query.proto and form a
proto file import cycle.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| path | [repeated string](#string) | Opaque folder identifiers (a folder's own entity id). `folders` is the structured, human-authorable alternative. When `path` is the only source set and `deep` is unset, `deep` defaults to true for back-compat with queries authored before `deep` existed. |
| folders | [repeated FolderRef](#folderref) | Structured, human-authorable folder addresses (root entity + folder-name segments). Take a `FolderRef` verbatim from a folder returned by the folders navigation API, or build one from names you can see in the catalog. |
| folder\_of | [ FolderOf](#folderof) | Resolve the folders to search from a set of assets, rather than naming them. Selects everything in the folder(s) that contain those assets. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deep.deep | [optional bool](#bool) | When false or unset, matches only the direct members of the folder(s). When true, matches the entire recursive subtree (members of subfolders too). |
Exception: when only the legacy `path` source is set and `deep` is unset, it defaults to true (preserves the behaviour of queries authored before this flag existed). With `folders` or `folder_of`, unset means false (shallow). |
### Query
(synq.queries.v1.Query)
Query is a structured query that can be used to find entities in the system.
It consists of multiple parts, each representing a different filter or sub-query.
The parts are combined using the operand to form the final result:
* AND (default): returns only entities matching ALL parts (intersection).
* OR: returns entities matching ANY part (union).
* EXCEPT: requires exactly 2 parts — returns entities from part\[0] that are NOT in part\[1].
* UPSTREAM: returns entities that are upstream (dependencies) of the entities matched by the parts.
* DOWNSTREAM: returns entities that are downstream (dependents) of the entities matched by the parts.
Queries can be nested by using a Query as a QueryPart, enabling complex compositions
like "upstream of all Snowflake tables".
| Field | Type | Description |
| ------- | -------------------------------- | --------------------------------- |
| parts | [repeated QueryPart](#querypart) | none |
| operand | [ QueryOperand](#queryoperand) | Defaults to AND if not specified. |
### Query.QueryPart
(synq.queries.v1.Query.QueryPart)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier\_list | [ IdentifierList](#identifierlist) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_name\_search | [ WithNameSearch](#withnamesearch) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_type | [ WithType](#withtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_annotation | [ WithAnnotation](#withannotation) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_dataproduct | [ InDataproduct](#indataproduct) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_data\_platform | [ InDataPlatform](#indataplatform) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_data\_platform\_type | [ WithDataPlatformType](#withdataplatformtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_folder | [ InFolder](#infolder) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_domain | [ InDomain](#indomain) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identities\_of | [ IdentitiesOf](#identitiesof) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_default\_visible\_types | [ WithDefaultVisibleTypes](#withdefaultvisibletypes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ Query](#query) | Nested sub-query, enabling recursive composition of filters and operands. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.unsupported | [ Unsupported](#unsupported) | Read-only. Represents internal query types that cannot be expressed in the public API. Do not construct these directly — they are returned when translating from internal queries. |
### ResolveQueryRequest
(synq.queries.v1.ResolveQueryRequest)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.resolver\_ql | [ string](#string) | ResolverQL expression to compile and evaluate. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.query | [ Query](#query) | Structured query to evaluate. |
| pagination | [ Pagination](#pagination) | Pagination over the matched entity set. `page_size` defaults per API when unset; pass the previous response's `page_info.last_id` as the cursor to fetch the next page. |
### ResolveQueryResponse
(synq.queries.v1.ResolveQueryResponse)
| Field | Type | Description |
| ---------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| entity\_ids | [repeated Identifier](#identifier) | Opaque identifiers of the matched entities, one page worth. Round-trip each id verbatim to the rest of the entities API. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
| rendered\_resolver\_ql | [ string](#string) | The resolved selection rendered as canonical ResolverQL. Empty when the selection has no ResolverQL representation. |
### TranslateResolverQlRequest
(synq.queries.v1.TranslateResolverQlRequest)
| Field | Type | Description |
| ------------ | ------------------ | ------------------------------------------------------------------- |
| resolver\_ql | [ string](#string) | ResolverQL expression to compile, for example `with_type("TABLE")`. |
### TranslateResolverQlResponse
(synq.queries.v1.TranslateResolverQlResponse)
| Field | Type | Description |
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| query | [ Query](#query) | The compiled structured query. Pass it verbatim to any public API that accepts a `synq.queries.v1.Query` (for example a folder browse `filter`), or to `ResolveQuery.query` to evaluate it. |
| rendered\_resolver\_ql | [ string](#string) | The compiled query rendered back to canonical ResolverQL. Empty when the query has no ResolverQL representation (legacy / deprecated operands). |
### GenerateQueryRequest
(synq.queries.v1.GenerateQueryRequest)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| description | [ string](#string) | none |
### GenerateQueryResponse
(synq.queries.v1.GenerateQueryResponse)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_query.query | [optional Query](#query) | The public Query proto. Absent when unsupported. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_resolver\_ql.resolver\_ql | [optional string](#string) | The generated ResolverQL query string. Empty when unsupported. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_unsupported\_reason.unsupported\_reason | [optional string](#string) | When the LLM determines the request cannot be expressed as a query, this field contains the reason(s). The other fields will be empty. |
### IdentifierList
(synq.queries.v1.IdentifierList)
Resolves to entities matching any of the given identifiers.
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### InDataPlatform
(synq.queries.v1.InDataPlatform)
Resolves to all entities that belong to the given data platform.
| Field | Type | Description |
| ---------- | -------------------------------------------------- | ----------- |
| identifier | [ DataPlatformIdentifier](#dataplatformidentifier) | none |
### InDataproduct
(synq.queries.v1.InDataproduct)
Resolves to all the assets that belong to the given data product.
| Field | Type | Description |
| ---------- | ------------------------------------------------ | ----------- |
| identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
### InDomain
(synq.queries.v1.InDomain)
Resolves to all entities in the given data domain.
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
### Unsupported
(synq.queries.v1.Unsupported)
Collects all the parts of the query that are currently unsupported in translation.
These represent an internal structure that are not yet completely available on the API.
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| query\_json | [ string](#string) | none |
### WithAnnotation
(synq.queries.v1.WithAnnotation)
Resolves to all entities that contain the annotation with at least one of the provided accepted values.
In case of no given accepted values, all entities that carry the given annotation are returned.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_accepted\_value.accepted\_value | [optional string](#string) | none |
| accepted\_values | [repeated string](#string) | none |
### WithDataPlatformType
(synq.queries.v1.WithDataPlatformType)
| Field | Type | Description |
| ----- | ---------------------------------------------- | ----------- |
| types | [repeated DataPlatformType](#dataplatformtype) | none |
### WithDefaultVisibleTypes
(synq.queries.v1.WithDefaultVisibleTypes)
Resolves to every asset of a type the catalog shows by default — the
"everything" starting set.
Use it as the base of a subtraction, e.g. an EXCEPT query whose first part is
WithDefaultVisibleTypes and whose second part is what to leave out. On its own
it selects the whole catalog, so it is rarely useful as the only part of a
query.
"Default visible" excludes the supporting asset types the catalog hides unless
asked for (columns, tests, and similar), so this is not literally every entity.
### WithNameSearch
(synq.queries.v1.WithNameSearch)
Resolves to all entities matching the given name search.
| Field | Type | Description |
| ------------- | ------------------ | ----------- |
| search\_query | [ string](#string) | none |
### WithType
(synq.queries.v1.WithType)
Resolves to all the entities that have the provided type.
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| type | [ Type](#type) | none |
| types | [repeated Type](#type) | none |
### WithType.Type
(synq.queries.v1.WithType.Type)
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) entity\_type.default | [ EntityType](#entitytype) | Default Coalesce Quality types |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) entity\_type.custom | [ int32](#int32) | Custom types as defined through synq.entities.custom.v1.TypesService |
### ScopeFilter
(synq.common.v1.ScopeFilter)
ScopeFilter defines include/exclude rules for scoping data warehouse queries.
Matching semantics:
* If include is non-empty, a (database, schema, table) tuple must match at least one include rule.
* If exclude is non-empty, the tuple must NOT match any exclude rule.
* Exclude takes precedence over include (exclude wins).
* Empty/unset ScopeFilter means accept all.
| Field | Type | Description |
| ------- | -------------------------------- | --------------------------------------------------------------------------------- |
| include | [repeated ScopeRule](#scoperule) | Include rules. If non-empty, only matching objects are accepted. |
| exclude | [repeated ScopeRule](#scoperule) | Exclude rules. Matching objects are rejected, even if they match an include rule. |
### ScopeRule
(synq.common.v1.ScopeRule)
ScopeRule is a multi-level pattern for matching data warehouse objects.
All non-empty fields must match for the rule to apply.
Empty field means "match anything" at that level (wildcard).
Patterns support glob syntax where \* matches zero or more characters.
Matching is case-insensitive.
| Field | Type | Description |
| -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| database | [ string](#string) | Database-level pattern. Only meaningful for warehouses that expose more than one database/catalog per connection — Snowflake & Trino (catalog), Databricks (catalog), Athena (Glue catalog), DuckDB (database). Ignored by single-database/-project connections (Postgres, Redshift, MSSQL, Oracle, BigQuery project) and by MySQL/ClickHouse, which filter their namespace at the schema level below. |
| schema | [ string](#string) | Schema-level pattern. The level directly above a table. Maps to: dataset in BigQuery; database (namespace) in MySQL & ClickHouse; schema in Postgres/Redshift/Snowflake/Trino/MSSQL; owner in Oracle. |
| table | [ string](#string) | Table or view name pattern. |
### SqlExpression
(synq.common.v1.SqlExpression)
SqlExpression carries a SQL string together with the placeholder tokens
the caller must substitute before executing it.
Empty `placeholders` means `sql` is byte-equal to what runs in the warehouse
and is safe to dispatch without further processing. When `placeholders` is
non-empty, every listed token appears literally in `sql` and must be replaced
(or otherwise interpreted) by the caller before execution.
| Field | Type | Description |
| ------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| sql | [ string](#string) | SQL string. Dialect matches the integration that owns the expression's parent resource. May contain placeholder tokens — see `placeholders`. |
| placeholders | [repeated SqlPlaceholder](#sqlplaceholder) | Placeholders present in `sql`. Order is undefined; each token is unique within the slice. Absent when `sql` is directly runnable. |
### SqlPlaceholder
(synq.common.v1.SqlPlaceholder)
SqlPlaceholder describes one substitution slot in a SqlExpression.
| Field | Type | Description |
| ----------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| token | [ string](#string) | Literal token as it appears in `sql`, e.g. "\{from}". |
| description | [ string](#string) | Human- and AI-readable purpose of the placeholder. Should answer "what value should I substitute, and in what form?" without relying on out-of-band documentation. Example: "Lower bound of the metric query time window (inclusive, UTC timestamp)." |
### AssetSelectionQuery
(synq.domains.v1.AssetSelectionQuery)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| parts | [repeated QueryPart](#querypart) | none |
| operand | [ QueryOperand](#queryoperand) | none |
### AssetSelectionQuery.QueryPart
(synq.domains.v1.AssetSelectionQuery.QueryPart)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier\_list | [ IdentifierList](#identifierlist) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_name\_search | [ WithNameSearch](#withnamesearch) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_type | [ WithType](#withtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_annotation | [ WithAnnotation](#withannotation) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_data\_platform | [ InDataPlatform](#indataplatform) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_folder | [ InFolder](#infolder) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_data\_platform\_type | [ WithDataPlatformType](#withdataplatformtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identities\_of | [ IdentitiesOf](#identitiesof) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_default\_visible\_types | [ WithDefaultVisibleTypes](#withdefaultvisibletypes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ AssetSelectionQuery](#assetselectionquery) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.unsupported | [ Unsupported](#unsupported) | none |
### DomainDefinition
(synq.domains.v1.DomainDefinition)
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| parts | [repeated Part](#part) | none |
### DomainDefinition.Part
(synq.domains.v1.DomainDefinition.Part)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------- |
| id | [ string](#string) | part identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier | [ Identifier](#identifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.dataproduct | [ DataproductIdentifier](#dataproductidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ AssetSelectionQuery](#assetselectionquery) | none |
### Domain
(synq.domains.v1.Domain)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------- | --------------------------------------------- |
| id | [ string](#string) | none |
| name | [ string](#string) | none |
| description | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | none |
| definition | [ DomainDefinition](#domaindefinition) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | none |
| source | [ Source](#source) | Source for creation and management of domain. |
### BatchGetRequest
(synq.domains.v1.BatchGetRequest)
| Field | Type | Description |
| ----------- | -------------------------- | ----------- |
| domain\_ids | [repeated string](#string) | none |
### BatchGetResponse
(synq.domains.v1.BatchGetResponse)
| Field | Type | Description |
| ------- | --------------------------------- | ----------- |
| domains | [map DomainsEntry](#domainsentry) | none |
### BatchGetResponse.DomainsEntry
(synq.domains.v1.BatchGetResponse.DomainsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Domain](#domain) | none |
### DeleteRequest
(synq.domains.v1.DeleteRequest)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
### DeleteResponse
(synq.domains.v1.DeleteResponse)
### FetchDomainWithSubDomainsRequest
(synq.domains.v1.FetchDomainWithSubDomainsRequest)
| Field | Type | Description |
| ------------------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
| exclude\_definition | [ bool](#bool) | none |
### FetchDomainWithSubDomainsResponse
(synq.domains.v1.FetchDomainWithSubDomainsResponse)
| Field | Type | Description |
| ------- | --------------------------------- | ----------- |
| domains | [map DomainsEntry](#domainsentry) | none |
### FetchDomainWithSubDomainsResponse.DomainsEntry
(synq.domains.v1.FetchDomainWithSubDomainsResponse.DomainsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Domain](#domain) | none |
### GetUsageRequest
(synq.domains.v1.GetUsageRequest)
### GetUsageResponse
(synq.domains.v1.GetUsageResponse)
| Field | Type | Description |
| ----------------- | ---------------- | ----------- |
| num\_domains | [ int32](#int32) | none |
| num\_sub\_domains | [ int32](#int32) | none |
### ListRequest
(synq.domains.v1.ListRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | none |
| exclude\_definition | [ bool](#bool) | none |
### ListResponse
(synq.domains.v1.ListResponse)
| Field | Type | Description |
| ------- | -------------------------- | ----------- |
| domains | [repeated Domain](#domain) | none |
### RemoveDefinitionPartRequest
(synq.domains.v1.RemoveDefinitionPartRequest)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
| part\_id | [ string](#string) | none |
### RemoveDefinitionPartResponse
(synq.domains.v1.RemoveDefinitionPartResponse)
### SetDefinitionRequest
(synq.domains.v1.SetDefinitionRequest)
| Field | Type | Description |
| ---------- | -------------------------------------- | ----------- |
| domain\_id | [ string](#string) | none |
| definition | [ DomainDefinition](#domaindefinition) | none |
### SetDefinitionResponse
(synq.domains.v1.SetDefinitionResponse)
### UpsertDefinitionPartRequest
(synq.domains.v1.UpsertDefinitionPartRequest)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
| part | [ Part](#part) | none |
### UpsertDefinitionPartResponse
(synq.domains.v1.UpsertDefinitionPartResponse)
### UpsertRequest
(synq.domains.v1.UpsertRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| id | [ string](#string) | none |
| name | [ string](#string) | none |
| description | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | none |
| source | [ Source](#source) | none |
### UpsertResponse
(synq.domains.v1.UpsertResponse)
### AddDomainMembersRequest
(synq.domains.members.v1.AddDomainMembersRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ----------- |
| domain\_id | [ string](#string) | none |
| user\_ids | [repeated string](#string) | none |
### AddDomainMembersResponse
(synq.domains.members.v1.AddDomainMembersResponse)
### ListDomainMembersRequest
(synq.domains.members.v1.ListDomainMembersRequest)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
### ListDomainMembersResponse
(synq.domains.members.v1.ListDomainMembersResponse)
| Field | Type | Description |
| ----------- | ---------------------------------------------- | ----------- |
| memberships | [repeated DomainMembership](#domainmembership) | none |
### ListUserDomainsRequest
(synq.domains.members.v1.ListUserDomainsRequest)
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
### ListUserDomainsResponse
(synq.domains.members.v1.ListUserDomainsResponse)
| Field | Type | Description |
| ----------- | ---------------------------------------------- | ----------- |
| memberships | [repeated DomainMembership](#domainmembership) | none |
### RemoveDomainMembersRequest
(synq.domains.members.v1.RemoveDomainMembersRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ----------- |
| domain\_id | [ string](#string) | none |
| user\_ids | [repeated string](#string) | none |
### RemoveDomainMembersResponse
(synq.domains.members.v1.RemoveDomainMembersResponse)
### SetDefaultUserDomainRequest
(synq.domains.members.v1.SetDefaultUserDomainRequest)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| domain\_id | [ string](#string) | none |
| user\_id | [ string](#string) | none |
### SetDefaultUserDomainResponse
(synq.domains.members.v1.SetDefaultUserDomainResponse)
### DomainMembership
(synq.domains.members.v1.DomainMembership)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
| domain\_id | [ string](#string) | none |
| is\_default | [ bool](#bool) | none |
### DomainDefinition
(synq.domains.v2.DomainDefinition)
The membership of a domain: which assets belong to it. A definition is an
ordered list of parts; an asset is a member if it matches ANY part (the parts
are OR'd together).
Unlike a data product, a domain is NOT a leaf: a part may pull in a whole data
product or another domain, and membership is then resolved recursively. The
server maintains the reference graph across domains and data products and
rejects any write that would close a loop, naming the offending path — so a
definition can always be resolved in finite time. The domain hierarchy counts
as a reference too: a parent domain aggregates its sub-domains.
| Field | Type | Description |
| ----- | ---------------------- | ------------------------------------------------------------------------- |
| parts | [repeated Part](#part) | The parts of the definition. An asset is a member if it matches any part. |
### DomainDefinition.Part
(synq.domains.v2.DomainDefinition.Part)
A single piece of a domain definition: a pinned asset, a whole data product,
a whole other domain, or a selection query.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Stable id of this part (a UUID). Supplied by the caller for idempotent part upserts; the server mints one if left empty on create. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.entity\_id | [ string](#string) | Pin a single asset by its opaque entity id (as returned by resolve / listing APIs). Never constructed by hand. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.dataproduct\_id | [ string](#string) | Include everything that belongs to a data product. Accepts either the bare data-product UUID or the `dataproduct-` form that API returns as its `entity_id` — the prefix is stripped server-side. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.domain\_id | [ string](#string) | Include everything that belongs to another domain, including that domain's own sub-domains. Accepts either the bare domain UUID or the `domain-` form — the prefix is stripped server-side. Rejected when it would make the domains reference each other in a loop. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ DomainQuery](#domainquery) | Select assets by a query. |
A query whose whole content is a single domain reference is equivalent to `domain_id` and is returned in that form on read, since both describe the same membership. |
### DomainQuery
(synq.domains.v2.DomainQuery)
The selection query behind a domain definition part, expressed for the public
API.
On write, provide the query in ONE of three forms:
* `resolver_ql` — the resolver query language, a compact text form that is
the canonical way to author selections as code;
* `public_query` — a structured query (the same shape used elsewhere for
asset selection), convenient to build from a filter UI; or
* `asset_selection_query` — the structured form domains have always
accepted, kept so an existing definition can be moved across unchanged.
When more than one is set the first of that list wins. The server compiles the
query and stores it canonically; the raw text is not preserved verbatim.
On read, the server returns `rendered_resolver_ql` (the stored query rendered
back to canonical resolver query language) plus, best-effort, both structured
forms. `resolver_ql` is not echoed back — read `rendered_resolver_ql`.
A domain query may reference another domain or a data product (via the
`in_domain` / `in_dataproduct` operands, or their resolver-query-language
equivalents). Such a reference is resolved recursively and is rejected only
when it would close a reference loop.
| Field | Type | Description |
| ----------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| resolver\_ql | [ string](#string) | WRITE (option A). The query in resolver query language. |
| rendered\_resolver\_ql | [ string](#string) | READ, output-only. The stored query rendered back to canonical resolver query language. Deterministically derived; does not preserve original hand-typed formatting or comments. |
| public\_query | [ Query](#query) | WRITE (option B) and READ. On write, the structured query to store (used when `resolver_ql` is empty). On read, a best-effort structured representation of the stored query. |
| asset\_selection\_query | [ AssetSelectionQuery](#assetselectionquery) | WRITE (option C) and READ. The structured form carried over from `synq.domains.v1`, for definitions authored against that API. On write it is used only when neither `resolver_ql` nor `public_query` is set. On read it is the stored query as-is, so a v1 definition round-trips through v2 unchanged. `public_query` is the richer form — prefer it for new integrations, since it can express domain and data-product references this one cannot. |
### BatchGetRequest
(synq.domains.v2.BatchGetRequest)
| Field | Type | Description |
| ------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| ids | [repeated string](#string) | Ids to fetch (1–200, unique). Each accepts either the bare UUID or the `domain-` form; the prefix is stripped server-side. |
| include\_deleted | [ bool](#bool) | Include soft-deleted domains. |
| exclude\_definition | [ bool](#bool) | Omit the (potentially large) membership definition from each domain. |
### BatchGetResponse
(synq.domains.v2.BatchGetResponse)
| Field | Type | Description |
| ------- | --------------------------------- | ----------------------------------------------------------------------------------------- |
| domains | [map DomainsEntry](#domainsentry) | Domains keyed by id. Ids that do not exist (or are deleted, unless requested) are absent. |
### BatchGetResponse.DomainsEntry
(synq.domains.v2.BatchGetResponse.DomainsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Domain](#domain) | none |
### DeleteRequest
(synq.domains.v2.DeleteRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the domain to delete. Accepts the bare UUID or the `domain-` form (the prefix is stripped server-side). |
| purge | [ bool](#bool) | Hard-delete instead of soft-delete, releasing the id for reuse. Refused while the domain still has sub-domains — delete or re-parent them first. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
### DeleteResponse
(synq.domains.v2.DeleteResponse)
### FetchDomainWithSubDomainsRequest
(synq.domains.v2.FetchDomainWithSubDomainsRequest)
| Field | Type | Description |
| ------------------- | ------------------ | -------------------------------------------------------------------- |
| id | [ string](#string) | Id of the domain. Accepts the bare UUID or the `domain-` form. |
| exclude\_definition | [ bool](#bool) | Omit the membership definition from each domain. |
### FetchDomainWithSubDomainsResponse
(synq.domains.v2.FetchDomainWithSubDomainsResponse)
| Field | Type | Description |
| ------- | --------------------------------- | --------------------------------------------------- |
| domains | [map DomainsEntry](#domainsentry) | The domain and its direct sub-domains, keyed by id. |
### FetchDomainWithSubDomainsResponse.DomainsEntry
(synq.domains.v2.FetchDomainWithSubDomainsResponse.DomainsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Domain](#domain) | none |
### GetUsageRequest
(synq.domains.v2.GetUsageRequest)
### GetUsageResponse
(synq.domains.v2.GetUsageResponse)
| Field | Type | Description |
| ----------------- | ---------------- | ------------------------------------ |
| num\_domains | [ int32](#int32) | Number of top-level domains. |
| num\_sub\_domains | [ int32](#int32) | Number of sub-domains, at any depth. |
### ListMembersRequest
(synq.domains.v2.ListMembersRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Id of the domain whose members to list. Accepts the bare UUID or the `domain-` form (the prefix is stripped server-side). |
| pagination | [ Pagination](#pagination) | Pagination. |
### ListMembersResponse
(synq.domains.v2.ListMembersResponse)
| Field | Type | Description |
| ----------- | -------------------------- | -------------------------------------------------------------------- |
| entity\_ids | [repeated string](#string) | Opaque entity ids of the assets that currently belong to the domain. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### ListRequest
(synq.domains.v2.ListRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| pagination | [ Pagination](#pagination) | Pagination. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | Restrict to the children of one domain. Pass an empty string to return only top-level domains. Omit to return every domain at any level. |
| include\_deleted | [ bool](#bool) | Include soft-deleted domains. |
| exclude\_definition | [ bool](#bool) | Omit the membership definition from each domain. |
### ListResponse
(synq.domains.v2.ListResponse)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------------------ |
| domains | [repeated Domain](#domain) | The matching domains. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### RemoveDefinitionPartRequest
(synq.domains.v2.RemoveDefinitionPartRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the domain. Accepts the bare UUID or the `domain-` form (the prefix is stripped server-side). |
| part\_id | [ string](#string) | Id of the part to remove. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### RemoveDefinitionPartResponse
(synq.domains.v2.RemoveDefinitionPartResponse)
| Field | Type | Description |
| ------ | ------------------ | ----------------------------------------- |
| domain | [ Domain](#domain) | The stored domain after the part removal. |
### SetDefinitionRequest
(synq.domains.v2.SetDefinitionRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the domain whose definition to replace. Accepts the bare UUID or the `domain-` form (the prefix is stripped server-side). |
| definition | [ DomainDefinition](#domaindefinition) | The new membership definition (replaces the existing one entirely). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### SetDefinitionResponse
(synq.domains.v2.SetDefinitionResponse)
| Field | Type | Description |
| ------ | ------------------ | --------------------------------------------- |
| domain | [ Domain](#domain) | The stored domain after the definition write. |
### UpsertDefinitionPartRequest
(synq.domains.v2.UpsertDefinitionPartRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the domain. Accepts the bare UUID or the `domain-` form (the prefix is stripped server-side). |
| part | [ Part](#part) | The part to add or replace (matched by its part id). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### UpsertDefinitionPartResponse
(synq.domains.v2.UpsertDefinitionPartResponse)
| Field | Type | Description |
| ------ | ------------------ | --------------------------------------- |
| domain | [ Domain](#domain) | The stored domain after the part write. |
### UpsertRequest
(synq.domains.v2.UpsertRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the domain. Accepts either the bare UUID or the `domain-` form — the prefix is stripped server-side, so the value you read back from any API can be passed straight in. The same id updates the same domain; a new id creates a new domain. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name.name | [optional string](#string) | Name. Required when creating; omit to keep the existing name on update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Description. Omit to keep the existing description. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | Parent domain, making this a sub-domain. Omit to keep the current parent; pass an empty string to detach the domain and make it top-level. Accepts the bare UUID or the `domain-` form. The parent must already exist, and the write is rejected if it would make the hierarchy loop. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source.source | [optional Source](#source) | Source. Omit to keep the existing source (defaults to SOURCE\_SYNQ on create). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_definition.definition | [optional DomainDefinition](#domaindefinition) | Membership definition. Omit to keep the existing definition; pass a present (possibly empty) definition to replace it. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the update fails with a conflict if the domain was modified since this etag was read. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### UpsertResponse
(synq.domains.v2.UpsertResponse)
| Field | Type | Description |
| ------ | ------------------ | ----------------------------------- |
| domain | [ Domain](#domain) | The stored domain after the upsert. |
### Domain
(synq.domains.v2.Domain)
A data domain: a named area of ownership that groups the assets, data products
and sub-domains belonging to one part of the business.
Domains form a hierarchy through `parent_id`, and a parent's membership
includes everything its sub-domains contain.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the domain (a UUID). Supplied by the caller on create, which makes Upsert idempotent. This is the value to pass wherever another API accepts a domain reference (for example the `in_domain` query operand). |
| name | [ string](#string) | Human-readable name. |
| description | [ string](#string) | Optional longer description. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent\_id.parent\_id | [optional string](#string) | Id of the parent domain, if this is a sub-domain. Absent for a top-level domain. |
| source | [ Source](#source) | none |
| definition | [ DomainDefinition](#domaindefinition) | The membership definition. Omitted when a read requests `exclude_definition`. |
| etag | [ string](#string) | Entity tag for optimistic concurrency: pass back on Upsert / Delete / definition writes to guard against overwriting a concurrent change. Form: `W/"-"`. Opaque — do not parse. |
| created\_by | [ Actor](#actor) | Who created the domain. Output-only. |
| updated\_by | [ Actor](#actor) | Who last edited the domain. Output-only. |
| created\_at | [ Timestamp](#timestamp) | When the domain was created. Output-only. |
| updated\_at | [ Timestamp](#timestamp) | When the domain was last updated. Output-only. Absent for a domain that has not been written since this field was introduced. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When the domain was soft-deleted, if it has been. Output-only. |
### AlertIdentifier
(synq.alerts.services.v1.AlertIdentifier)
| Field | Type | Description |
| -------------------------------------------------------------------------------------------- | ------------------ | ----------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) identifier.id | [ string](#string) | ID of the alert configuration to update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) identifier.fqn | [ string](#string) | FQN of the alert configuration to update. |
### BatchGetRequest
(synq.alerts.services.v1.BatchGetRequest)
| Field | Type | Description |
| ----------- | -------------------------------------------- | ------------------------- |
| identifiers | [repeated AlertIdentifier](#alertidentifier) | IDs of the alerts to get. |
### BatchGetResponse
(synq.alerts.services.v1.BatchGetResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ----------------------------------- |
| alerts | [map AlertsEntry](#alertsentry) | Alerts mapped by their identifiers. |
### BatchGetResponse.AlertsEntry
(synq.alerts.services.v1.BatchGetResponse.AlertsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Alert](#alert) | none |
### CreateRequest
(synq.alerts.services.v1.CreateRequest)
CreateRequest creates a new alert configuration.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Human-readable name for the alert configuration. |
| fqn | [ string](#string) | User-provided fully qualified name for the alert config. This is a unique identifier that users can specify to reference the alert. |
| trigger | [ EntityGroupQuery](#entitygroupquery) | Query that defines which entities can trigger this alert. |
| targets | [repeated AlertingTarget](#alertingtarget) | Targets where alerts will be sent. |
| settings | [ AlertSettings](#alertsettings) | Additional settings for the specific alert type. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_owner.owner | [optional Owner](#owner) | Optional owner information for the alert configuration. |
### CreateResponse
(synq.alerts.services.v1.CreateResponse)
CreateResponse returns the created alert configuration.
| Field | Type | Description |
| ----- | ---------------- | ----------------------------------------- |
| alert | [ Alert](#alert) | The alert configuration that was created. |
### DeleteRequest
(synq.alerts.services.v1.DeleteRequest)
DeleteRequest specifies which alert configuration to delete.
The config can be identified by either ID or FQN.
| Field | Type | Description |
| ---------- | ------------------------------------ | ------------------------------------ |
| identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to delete. |
### DeleteResponse
(synq.alerts.services.v1.DeleteResponse)
DeleteResponse confirms the deletion (empty response).
Empty response - successful deletion is indicated by HTTP 200 status.
### ListRequest
(synq.alerts.services.v1.ListRequest)
ListRequest filters alert configurations to retrieve.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ------------------------ | ----------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_owner.owner | [optional Owner](#owner) | Optional filter by owner of the alert configurations. |
### ListResponse
(synq.alerts.services.v1.ListResponse)
ListResponse returns the filtered list of alert configurations.
| Field | Type | Description |
| ----------- | -------------------------- | -------------------------------------------------------------- |
| alerts\_ids | [repeated string](#string) | The list of alert configurations matching the filter criteria. |
### ToggleEnabledRequest
(synq.alerts.services.v1.ToggleEnabledRequest)
ToggleEnabledRequest enables or disables an alert configuration.
The config can be identified by either ID or FQN.
| Field | Type | Description |
| ----------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------ |
| identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to toggle. |
| is\_enabled | [ bool](#bool) | Whether the alert configuration should be enabled. true = enable the alert, false = disable the alert. |
### ToggleEnabledResponse
(synq.alerts.services.v1.ToggleEnabledResponse)
ToggleEnabledResponse confirms the toggle operation (empty response).
Empty response - successful toggle is indicated by HTTP 200 status.
### UpdateRequest
(synq.alerts.services.v1.UpdateRequest)
UpdateRequest updates an existing alert configuration.
The config can be identified by either ID or FQN.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------ |
| identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name.name | [optional string](#string) | Human-readable name for the alert configuration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_trigger.trigger | [optional EntityGroupQuery](#entitygroupquery) | Query that defines which entities can trigger this alert. |
| targets | [repeated AlertingTarget](#alertingtarget) | Targets where alerts will be sent. Leave empty to keep existing targets. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_settings.settings | [optional AlertSettings](#alertsettings) | Additional settings for the specific alert type. |
### UpdateResponse
(synq.alerts.services.v1.UpdateResponse)
UpdateResponse returns the updated alert configuration.
| Field | Type | Description |
| ----- | ---------------- | ----------------------------------------- |
| alert | [ Alert](#alert) | The alert configuration that was updated. |
### Alert
(synq.alerts.v1.Alert)
Alert represents the configuration for an alert.
It contains all the necessary information to trigger and send alerts.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Unique identifier for the alert config (system-generated). |
| name | [ string](#string) | Human-readable name for the alert configuration. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fqn.fqn | [optional string](#string) | User-provided fully qualified name for the alert config. This is a unique identifier that users can specify to reference the alert. |
| trigger | [ EntityGroupQuery](#entitygroupquery) | Query that defines which entities can trigger this alert. |
| targets | [repeated AlertingTarget](#alertingtarget) | List of targets where alerts will be sent. |
| settings | [ AlertSettings](#alertsettings) | Additional settings for the specific alert type. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_owner.owner | [optional Owner](#owner) | none |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the alert config was created. |
| is\_disabled | [ bool](#bool) | Whether the alert config is currently disabled. |
### Alert.Owner
(synq.alerts.v1.Alert.Owner)
Owner information for the alert configuration.
If set, the alert is attributed to the specified owner and ownership.
| Field | Type | Description |
| ------------- | ------------------ | ------------------------------------------------ |
| owner\_path | [ string](#string) | Path identifying the owner of this alert config. |
| ownership\_id | [ string](#string) | Ownership identifier. |
### AlertSettings
(synq.alerts.v1.AlertSettings)
AlertSettings defines the properties that affect the trigger and presentation of an alert.
It specifies the conditions under which an alert should be fired and how it should behave.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) settings.schema\_change | [ SchemaChangeAlertSettings](#schemachangealertsettings) | Alert triggered by schema changes. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) settings.issue | [ IssueAlertSettings](#issuealertsettings) | Unified issue alert settings (replaces entity\_failure and issue\_lifecycle). |
### EntityGroupQuery
(synq.alerts.v1.EntityGroupQuery)
EntityGroupQuery defines a query to select a group of entities.
This is used to specify which entities should be monitored by an alert.
| Field | Type | Description |
| ----- | ------------------------------------------ | ----------------------------------------------- |
| parts | [repeated SelectionQuery](#selectionquery) | The parts that compose this entity group query. |
### IssueAlertSettings
(synq.alerts.v1.IssueAlertSettings)
IssueAlertSettings is the unified alert settings type for issue-based alerts.
It replaces both EntityFailureAlertSettings and IssueLifecycleAlertSettings.
| Field | Type | Description |
| ----------------------------- | ------------------------------------------------ | ----------------------------------------------------------------- |
| severities | [repeated Severity](#severity) | The severity levels that should trigger this alert. |
| notify\_upstream | [ bool](#bool) | Whether to notify upstream dependencies when this alert triggers. |
| allow\_sql\_test\_audit\_link | [ bool](#bool) | Whether to allow SQL test audit links in alert notifications. |
| ongoing | [ OngoingAlertsStrategy](#ongoingalertsstrategy) | Strategy for handling ongoing/repeated alerts. |
| grouping | [ IssueGroupingStrategy](#issuegroupingstrategy) | Strategy for grouping issues in alert notifications. |
### IssueGroupingStrategy
(synq.alerts.v1.IssueGroupingStrategy)
IssueGroupingStrategy controls how issues are grouped for alerting purposes.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.no\_grouping | [ NoGrouping](#nogrouping) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.system\_detected | [ SystemDetected](#systemdetected) | none |
### IssueGroupingStrategy.NoGrouping
(synq.alerts.v1.IssueGroupingStrategy.NoGrouping)
NoGrouping - each issue triggers a separate alert.
### IssueGroupingStrategy.SystemDetected
(synq.alerts.v1.IssueGroupingStrategy.SystemDetected)
SystemDetected - the system automatically groups related issues.
### OngoingAlertsStrategy
(synq.alerts.v1.OngoingAlertsStrategy)
OngoingAlertsStrategy defines how to handle ongoing/repeated alerts.
This prevents alert spam by controlling notification frequency.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | ---------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.disabled | [ Disabled](#disabled) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.stream | [ Stream](#stream) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.schedule | [ Schedule](#schedule) | none |
### OngoingAlertsStrategy.Disabled
(synq.alerts.v1.OngoingAlertsStrategy.Disabled)
Disabled strategy - no ongoing alerts will be sent after the initial alert.
No configuration needed - alerts are simply disabled after the first one.
### OngoingAlertsStrategy.Schedule
(synq.alerts.v1.OngoingAlertsStrategy.Schedule)
Schedule strategy - alerts are sent on a scheduled basis.
| Field | Type | Description |
| ----- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| cron | [ string](#string) | Cron expression defining when ongoing alerts should be sent. Must be a valid cron expression (e.g., "0 9 \* \* MON" for every Monday at 9 AM). |
### OngoingAlertsStrategy.Stream
(synq.alerts.v1.OngoingAlertsStrategy.Stream)
Stream strategy - alerts are sent continuously as issues persist.
No configuration needed - alerts stream continuously.
### SchemaChangeAlertSettings
(synq.alerts.v1.SchemaChangeAlertSettings)
SchemaChangeAlertSettings configures alerts for schema changes.
This alert triggers when the schema of monitored entities changes.
| Field | Type | Description |
| ---------------- | -------------- | ------------------------------------------------------------------ |
| notify\_upstream | [ bool](#bool) | Whether to notify upstream dependencies when schema changes occur. |
### SelectionQuery
(synq.alerts.v1.SelectionQuery)
SelectionQuery represents a query that selects entities based on various criteria.
It combines multiple query parts with a logical operand.
| Field | Type | Description |
| ------- | -------------------------------- | -------------------------------------------------------------------- |
| parts | [repeated QueryPart](#querypart) | The individual query parts that make up this selection. |
| operand | [ QueryOperand](#queryoperand) | The logical operand used to combine the query parts (AND, OR, etc.). |
### SelectionQuery.QueryPart
(synq.alerts.v1.SelectionQuery.QueryPart)
A single part of a selection query.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | --------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier\_list | [ IdentifierList](#identifierlist) | Filter by specific entity identifiers. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_name\_search | [ WithNameSearch](#withnamesearch) | Filter by name pattern search. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_type | [ WithType](#withtype) | Filter by entity type. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_annotation | [ WithAnnotation](#withannotation) | Filter by annotation presence/value. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_data\_platform | [ InDataPlatform](#indataplatform) | Filter by data platform. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_folder | [ InFolder](#infolder) | Filter by folder location. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_data\_platform\_type | [ WithDataPlatformType](#withdataplatformtype) | Filter by data platform type. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_dataproduct | [ InDataproduct](#indataproduct) | Filter by data product membership. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ SelectionQuery](#selectionquery) | Nested selection query for complex filtering. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.unsupported | [ Unsupported](#unsupported) | Unsupported query types for backward compatibility. |
### AlertingTarget
(synq.alerts.v1.AlertingTarget)
AlertingTarget represents a destination where alert notifications will be sent.
Each target type has its own specific configuration requirements.
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.slack | [ SlackTarget](#slacktarget) | Send alert to a Slack channel or user. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.email | [ EmailTarget](#emailtarget) | Send alert via email. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.owner | [ OwnerTarget](#ownertarget) | Send alert to the owner of the monitored entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.ms\_teams | [ MsTeamsTarget](#msteamstarget) | Send alert to Microsoft Teams channel or member. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.webhook | [ WebhookTarget](#webhooktarget) | Send alert via webhook integration. |
### EmailTarget
(synq.alerts.v1.EmailTarget)
EmailTarget configures alert delivery via email.
| Field | Type | Description |
| ----------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| recipient\_emails | [repeated string](#string) | List of email addresses that will receive the alert notifications. Each email must be a valid email address format. |
### MsTeamsTarget
(synq.alerts.v1.MsTeamsTarget)
MsTeamsTarget configures alert delivery to Microsoft Teams.
Alerts are sent to a Microsoft Teams channel.
| Field | Type | Description |
| ------- | ------------------ | ------------------------- |
| channel | [ string](#string) | Teams channel name or ID. |
### OwnerTarget
(synq.alerts.v1.OwnerTarget)
OwnerTarget configures alert delivery to the owner of the monitored entity.
This allows alerts to be automatically sent to whoever owns the data being monitored.
| Field | Type | Description |
| ----------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| owner\_path | [ string](#string) | Path that identifies the ownership context for this target. This determines how the system will resolve the actual owner. |
### SlackTarget
(synq.alerts.v1.SlackTarget)
SlackTarget configures alert delivery to Slack.
Alerts are sent to a Slack channel.
| Field | Type | Description |
| ------- | ------------------ | ------------------------------------------------------------ |
| channel | [ string](#string) | Slack channel name or ID (e.g., "#alerts" or "C1234567890"). |
### WebhookTarget
(synq.alerts.v1.WebhookTarget)
WebhookTarget configures alert delivery via webhook/hook integrations.
This allows integration with external systems and custom notification workflows.
| Field | Type | Description |
| ----------- | ------------------ | ----------------------------------------------------------------------------------------------------------- |
| webhook\_id | [ string](#string) | Unique identifier of the webhook to send alerts to. This references a pre-configured webhook in the system. |
### AthenaIdentifier
(synq.platforms.v1.AthenaIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| instance | [ string](#string) | AWS account and region the Athena workgroup runs in, formatted as "\.\" (e.g. "123456789012.eu-west-1"). Auto-derived by SYNQ from sts:GetCallerIdentity at integration setup time. |
| catalog | [ string](#string) | Glue Data Catalog name. Almost always "AwsDataCatalog" — the default catalog for Athena unless the customer registered a federated catalog. |
### BigqueryIdentifier
(synq.platforms.v1.BigqueryIdentifier)
| Field | Type | Description |
| ------- | ------------------ | ---------------- |
| project | [ string](#string) | BigQuery project |
### ClickhouseIdentifier
(synq.platforms.v1.ClickhouseIdentifier)
| Field | Type | Description |
| ------ | ------------------ | --------------------------------- |
| host | [ string](#string) | Clickhouse host inclusive of port |
| schema | [ string](#string) | Clickhouse database |
### DataPlatformIdentifier
(synq.platforms.v1.DataPlatformIdentifier)
DataPlatformIdentifier is a unique reference to a data platform integrated with Coalesce Quality.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.unknown | [ UnknownDataPlatform](#unknowndataplatform) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.bigquery | [ BigqueryIdentifier](#bigqueryidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.clickhouse | [ ClickhouseIdentifier](#clickhouseidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.snowflake | [ SnowflakeIdentifier](#snowflakeidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.redshift | [ RedshiftIdentifier](#redshiftidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.postgres | [ PostgresIdentifier](#postgresidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.mysql | [ MysqlIdentifier](#mysqlidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.databricks | [ DatabricksIdentifier](#databricksidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.dbt\_cloud | [ DbtCloudIdentifier](#dbtcloudidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.sql\_mesh | [ SqlMeshIdentifier](#sqlmeshidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.duckdb | [ DuckDbIdentifier](#duckdbidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.trino | [ TrinoIdentifier](#trinoidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.mssql | [ MssqlIdentifier](#mssqlidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.oracle | [ OracleIdentifier](#oracleidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.athena | [ AthenaIdentifier](#athenaidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.fabric | [ FabricIdentifier](#fabricidentifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.synq\_integration\_id | [ string](#string) | Coalesce Quality integration ID maps to the created integration on the Coalesce Quality platform. |
### DatabricksIdentifier
(synq.platforms.v1.DatabricksIdentifier)
| Field | Type | Description |
| --------- | ------------------ | ------------------------------- |
| workspace | [ string](#string) | URL of the databricks workspace |
### DbtCloudIdentifier
(synq.platforms.v1.DbtCloudIdentifier)
| Field | Type | Description |
| ------------- | ------------------ | -------------------------- |
| api\_endpoint | [ string](#string) | API endpoint for Dbt Cloud |
| account\_id | [ string](#string) | Account ID |
| project\_id | [ string](#string) | Project ID |
### DuckDbIdentifier
(synq.platforms.v1.DuckDbIdentifier)
| Field | Type | Description |
| ------------------- | ------------------ | ----------- |
| motherduck\_account | [ string](#string) | none |
### FabricIdentifier
(synq.platforms.v1.FabricIdentifier)
| Field | Type | Description |
| ------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| instance | [ string](#string) | Workspace SQL analytics endpoint host, e.g. "\.datawarehouse.fabric.microsoft.com". Identifies the Fabric workspace the integration connects to. Fabric is workspace-scoped with cross-database queries, so the workspace host alone identifies the platform (like Databricks' workspace URL); a specific warehouse/table is addressed by FabricTableIdentifier. |
| workspace\_id | [ string](#string) | Fabric workspace GUID — the identifier used by the Fabric REST API for workspace-scoped resources. The Fabric endpoint host in `instance` encodes the tenant and workspace GUIDs; this is the decoded workspace GUID, provided so you don't have to decode it yourself. `instance` remains the identifying value. Optional: empty when the host isn't a standard Fabric endpoint. |
| tenant\_id | [ string](#string) | Entra (Azure AD) tenant GUID, decoded from the endpoint host in `instance` alongside workspace\_id. Optional: empty when the host isn't a standard Fabric endpoint. |
### MssqlIdentifier
(synq.platforms.v1.MssqlIdentifier)
| Field | Type | Description |
| -------- | ------------------ | --------------- |
| host | [ string](#string) | SQL Server host |
| database | [ string](#string) | Database name |
### MysqlIdentifier
(synq.platforms.v1.MysqlIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ---------------------------- |
| host | [ string](#string) | Mysql host inclusive of port |
### OracleIdentifier
(synq.platforms.v1.OracleIdentifier)
| Field | Type | Description |
| ------------- | ------------------ | ------------------------- |
| host | [ string](#string) | Oracle host |
| service\_name | [ string](#string) | Oracle service name (PDB) |
### PostgresIdentifier
(synq.platforms.v1.PostgresIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ------------------------------- |
| host | [ string](#string) | Postgres host inclusive of port |
| database | [ string](#string) | Postgres database |
### RedshiftIdentifier
(synq.platforms.v1.RedshiftIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ----------------- |
| cluster | [ string](#string) | Redshift cluster |
| database | [ string](#string) | Redshift database |
### SnowflakeIdentifier
(synq.platforms.v1.SnowflakeIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ------------------ |
| account | [ string](#string) | Snowflake account |
| database | [ string](#string) | Snowflake database |
### SqlMeshIdentifier
(synq.platforms.v1.SqlMeshIdentifier)
| Field | Type | Description |
| --------------------------- | ------------------ | -------------------------------------- |
| default\_database\_instance | [ string](#string) | Default database instance for SQL Mesh |
### TrinoIdentifier
(synq.platforms.v1.TrinoIdentifier)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| coordinator | [ string](#string) | none |
### UnknownDataPlatform
(synq.platforms.v1.UnknownDataPlatform)
### OAuthAuthentication
(synq.platforms.v1.OAuthAuthentication)
Authentication using OAuth credentials
| Field | Type | Description |
| -------------- | ------------------ | ----------- |
| client\_id | [ string](#string) | none |
| client\_secret | [ string](#string) | none |
### PasswordAuthentication
(synq.platforms.v1.PasswordAuthentication)
Authentication using a username and password
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| username | [ string](#string) | none |
| password | [ string](#string) | none |
### PlatformAuthentication
(synq.platforms.v1.PlatformAuthentication)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.token | [ TokenAuthentication](#tokenauthentication) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.oauth | [ OAuthAuthentication](#oauthauthentication) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.password | [ PasswordAuthentication](#passwordauthentication) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.synq\_managed\_key\_pair | [ SynqManagedKeyPairAuthentication](#synqmanagedkeypairauthentication) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.user\_managed\_key\_pair | [ UserManagedKeyPairAuthentication](#usermanagedkeypairauthentication) | none |
### SynqManagedKeyPairAuthentication
(synq.platforms.v1.SynqManagedKeyPairAuthentication)
Authentication using a managed key pair.
The public key will be set and returned by the server after the authentication is created.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_public\_key.public\_key | [optional string](#string) | none |
### TokenAuthentication
(synq.platforms.v1.TokenAuthentication)
Authentication using a token (API key, PAT, etc)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| token | [ string](#string) | none |
### UserManagedKeyPairAuthentication
(synq.platforms.v1.UserManagedKeyPairAuthentication)
Authentication using a user-managed key pair.
The private key is stored safely as a secret. The response does not include the private key for security.
| Field | Type | Description |
| ------------ | ------------------ | ----------- |
| private\_key | [ string](#string) | none |
### SetPlatformAuthenticationRequest
(synq.platforms.v1.SetPlatformAuthenticationRequest)
| Field | Type | Description |
| -------------- | -------------------------------------------------- | ---------------------- |
| platform | [ DataPlatformIdentifier](#dataplatformidentifier) | Platform identifier |
| authentication | [ PlatformAuthentication](#platformauthentication) | Authentication details |
### SetPlatformAuthenticationResponse
(synq.platforms.v1.SetPlatformAuthenticationResponse)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| success | [ bool](#bool) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_authentication.authentication | [optional PlatformAuthentication](#platformauthentication) | The authentication is returned in case there is a server side set information to be passed to the client. |
### Callback
(synq.webhooks.v1.Callback)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------- | -------------------------------- | ----------- |
| url | [ string](#string) | none |
| action\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.issues\_command | [ IssuesCommand](#issuescommand) | none |
### FlatEvent
(synq.webhooks.v1.FlatEvent)
A webhook event in the flat format — an experimental, opt-in alternative to
`Event` that carries the same information in a flatter shape.
Instead of nesting the payload under a per-event-type field (`issue_created`,
`issue_updated`, `incident_open`, …), the payload is carried by a single
top-level field — `issue`, `incident`, or `ping` — and `event_type` says
which one is set and why. A receiver can then read a value the same way on
every event, e.g. `issue.owners[0].title` on any issue event, instead of a
different path per event type.
Exactly one of `issue`, `incident`, or `ping` is set, matching `event_type`.
Select this format per webhook integration; the default is the nested `Event`.
Payload signing is identical — see `Event` for the signature scheme.
Experimental: this shape may change while we gather feedback.
| Field | Type | Description |
| ----------- | ------------------------------------ | ------------------------------------------------------------------- |
| workspace | [ string](#string) | none |
| event\_id | [ string](#string) | none |
| event\_time | [ Timestamp](#timestamp) | none |
| event\_type | [ EventType](#eventtype) | Which event occurred, and which payload field below is set. |
| issue | [ IssueSummary](#issuesummary) | Issue payload. Set on every `EVENT_TYPE_ISSUE_*` event. |
| incident | [ IncidentSummary](#incidentsummary) | Incident payload. Set on every `EVENT_TYPE_INCIDENT_*` event. |
| ping | [ Ping](#ping) | Test payload. Set on `EVENT_TYPE_PING` (sent during webhook setup). |
| callbacks | [repeated Callback](#callback) | none |
### Event
(synq.webhooks.v1.Event)
A webhook event delivered to a customer-configured endpoint.
Payload signing: every outgoing request is signed so the receiver can verify
it originated from Coalesce Quality and was not tampered with or replayed. Two
headers are sent on every delivery:
X-Coalesce-Timestamp: \
X-Coalesce-Signature: v1=\
The signature is computed as:
signed\_payload = "\{X-Coalesce-Timestamp}." + \
signature = hex( HMAC\_SHA256(key = signing\_secret, msg = signed\_payload) )
where signing\_secret is the per-integration secret shown (read-only) in the
webhook integration settings. To verify:
1. Read X-Coalesce-Timestamp and the raw request body.
2. Recompute the signature with your copy of the signing secret and compare
it against the v1=... value in X-Coalesce-Signature using a constant-time
comparison.
3. Optionally reject deliveries whose timestamp is outside your tolerance
window (retries reuse the original signing timestamp, so allow for the
retry backoff window — up to \~30 minutes).
The v1= prefix identifies the signature scheme; future schemes may add
additional space-separated values to the header.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ----------- |
| workspace | [ string](#string) | none |
| event\_id | [ string](#string) | none |
| event\_time | [ Timestamp](#timestamp) | none |
| event\_type | [ EventType](#eventtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.ping | [ Ping](#ping) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.issue\_created | [ IssueCreated](#issuecreated) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.issue\_updated | [ IssueUpdated](#issueupdated) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.issue\_status\_updated | [ IssueStatusUpdated](#issuestatusupdated) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.issue\_closed | [ IssueClosed](#issueclosed) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.incident\_open | [ IncidentOpen](#incidentopen) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.incident\_closed | [ IncidentClosed](#incidentclosed) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) data.incident\_cancelled | [ IncidentCancelled](#incidentcancelled) | none |
| callbacks | [repeated Callback](#callback) | none |
### IncidentCancelled
(synq.webhooks.v1.IncidentCancelled)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| incident | [ IncidentSummary](#incidentsummary) | none |
### IncidentClosed
(synq.webhooks.v1.IncidentClosed)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| incident | [ IncidentSummary](#incidentsummary) | none |
### IncidentOpen
(synq.webhooks.v1.IncidentOpen)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| incident | [ IncidentSummary](#incidentsummary) | none |
### IncidentSummary
(synq.webhooks.v1.IncidentSummary)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------------------------------- | ----------- |
| incident\_id | [ string](#string) | none |
| incident\_url | [ string](#string) | none |
| title | [ string](#string) | none |
| description | [ string](#string) | none |
| description\_html | [ string](#string) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ended\_at.ended\_at | [optional Timestamp](#timestamp) | none |
### IssueClosed
(synq.webhooks.v1.IssueClosed)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| issue | [ IssueSummary](#issuesummary) | none |
### IssueCreated
(synq.webhooks.v1.IssueCreated)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| issue | [ IssueSummary](#issuesummary) | none |
### IssueStatusUpdated
(synq.webhooks.v1.IssueStatusUpdated)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| issue | [ IssueSummary](#issuesummary) | none |
### IssueSummary
(synq.webhooks.v1.IssueSummary)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | none |
| issue\_group\_id | [ string](#string) | none |
| issue\_url | [ string](#string) | none |
| title | [ string](#string) | Summary of the issue, what happened and where. |
| description | [ string](#string) | Detailed description of the issue. In the Markdown format. |
| description\_html | [ string](#string) | Detailed description of the issue. In the HTML format. |
| trigger\_entity | [ IssueEntity](#issueentity) | Entity which triggered the issue. |
| directly\_affected\_entities | [repeated IssueEntity](#issueentity) | Entities directly affected by the issue, not considering downstream ones. |
| monitored\_entities | [repeated IssueEntity](#issueentity) | The primary entities being monitored that are associated with this issue, for example the dbt model or dbt Cloud job that a failing test is attached to. |
| started\_at | [ Timestamp](#timestamp) | Time when the issue was triggered. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ended\_at.ended\_at | [optional Timestamp](#timestamp) | Time when the issue was closed. |
| trigger\_run\_id | [ string](#string) | none |
| trigger\_name | [ string](#string) | none |
| trigger\_message | [ string](#string) | none |
| status | [ IssueStatus](#issuestatus) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_status\_actor.status\_actor | [optional Actor](#actor) | The user who set the current status, when the transition was human-initiated (e.g. someone pressing Expected / Fixed / No action needed / Investigating in the app or via the public API). This is the same actor exposed by the Issues API as `Issue.latest_status_actor`, so the two feeds can be joined on it. |
Set only when an actor is known: it is populated on `issue_status_updated` events and left unset for system-driven transitions with no human actor (e.g. a status implied by a monitor run). Consumers must treat it as optional and tolerate its absence.
Carries the strongest identity the caller proved — a Coalesce Quality email, Slack user id, or PagerDuty user id — alongside a display `name`. |
\| owners | [repeated Owner](#owner) | Owners of the entities this issue is about.
Covers only the direct owners of the affected entities, not the owners of downstream entities. Empty when the affected entities have no owner assigned. Ordered as shown in the app. |
### IssueSummary.IssueEntity
(synq.webhooks.v1.IssueSummary.IssueEntity)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| name | [ string](#string) | none |
| type\_name | [ string](#string) | none |
| identifier | [ Identifier](#identifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_folder.folder | [optional string](#string) | none |
| entity\_url | [ string](#string) | none |
### IssueSummary.Owner
(synq.webhooks.v1.IssueSummary.Owner)
An owner (person or team) responsible for an entity, as assigned in
Coalesce Quality (natively or synced from a catalog).
| Field | Type | Description |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Identifier of the owner within the workspace. Matches the id on the Owners API, so callers can fetch the full owner record (contacts, source) from that API. |
| title | [ string](#string) | Display name of the owner, e.g. a team or person name. |
| url | [ string](#string) | Deep link to the owner in the Coalesce Quality app. |
### IssueUpdated
(synq.webhooks.v1.IssueUpdated)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| issue | [ IssueSummary](#issuesummary) | none |
### Ping
(synq.webhooks.v1.Ping)
Test event sent during a webhook setup.
| Field | Type | Description |
| ------- | ------------------ | ----------- |
| message | [ string](#string) | none |
### Dataproduct
(synq.dataproducts.v1.Dataproduct)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------- |
| identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
| definition | [ DataproductDefinition](#dataproductdefinition) | none |
| title | [ string](#string) | none |
| description | [ string](#string) | none |
| folder | [ string](#string) | none |
| priority | [ Priority](#priority) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | none |
| source | [ Source](#source) | Source for creation and management of dataproduct. |
### AssetSelectionQuery
(synq.dataproducts.v1.AssetSelectionQuery)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| parts | [repeated QueryPart](#querypart) | none |
| operand | [ QueryOperand](#queryoperand) | none |
### AssetSelectionQuery.QueryPart
(synq.dataproducts.v1.AssetSelectionQuery.QueryPart)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier\_list | [ IdentifierList](#identifierlist) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_name\_search | [ WithNameSearch](#withnamesearch) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_type | [ WithType](#withtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_annotation | [ WithAnnotation](#withannotation) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_data\_platform | [ InDataPlatform](#indataplatform) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_folder | [ InFolder](#infolder) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_data\_platform\_type | [ WithDataPlatformType](#withdataplatformtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identities\_of | [ IdentitiesOf](#identitiesof) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_default\_visible\_types | [ WithDefaultVisibleTypes](#withdefaultvisibletypes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ AssetSelectionQuery](#assetselectionquery) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.unsupported | [ Unsupported](#unsupported) | none |
### DataproductDefinition
(synq.dataproducts.v1.DataproductDefinition)
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| parts | [repeated Part](#part) | none |
### DataproductDefinition.Part
(synq.dataproducts.v1.DataproductDefinition.Part)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------- |
| id | [ string](#string) | part identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier | [ Identifier](#identifier) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ AssetSelectionQuery](#assetselectionquery) | none |
### DeleteRequest
(synq.dataproducts.v1.DeleteRequest)
| Field | Type | Description |
| ---------- | ------------------------------------------------ | ----------- |
| identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
### DeleteResponse
(synq.dataproducts.v1.DeleteResponse)
### GetRequest
(synq.dataproducts.v1.GetRequest)
| Field | Type | Description |
| ----------- | -------------------------------------------------------- | ----------- |
| identifiers | [repeated DataproductIdentifier](#dataproductidentifier) | none |
### GetResponse
(synq.dataproducts.v1.GetResponse)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| products | [repeated Dataproduct](#dataproduct) | none |
### ListRequest
(synq.dataproducts.v1.ListRequest)
| Field | Type | Description |
| ------------------- | -------------- | ----------- |
| include\_deleted | [ bool](#bool) | none |
| exclude\_definition | [ bool](#bool) | none |
### ListResponse
(synq.dataproducts.v1.ListResponse)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| products | [repeated Dataproduct](#dataproduct) | none |
### RemoveDefinitionPartRequest
(synq.dataproducts.v1.RemoveDefinitionPartRequest)
| Field | Type | Description |
| ------------------- | ------------------------------------------------ | ----------- |
| product\_identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
| part\_id | [ string](#string) | none |
### RemoveDefinitionPartResponse
(synq.dataproducts.v1.RemoveDefinitionPartResponse)
### SetDefinitionRequest
(synq.dataproducts.v1.SetDefinitionRequest)
| Field | Type | Description |
| ------------------- | ------------------------------------------------ | ----------- |
| product\_identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
| definition | [ DataproductDefinition](#dataproductdefinition) | none |
### SetDefinitionResponse
(synq.dataproducts.v1.SetDefinitionResponse)
### UpsertDefinitionPartRequest
(synq.dataproducts.v1.UpsertDefinitionPartRequest)
| Field | Type | Description |
| ------------------- | ------------------------------------------------ | ----------- |
| product\_identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
| part | [ Part](#part) | none |
### UpsertDefinitionPartResponse
(synq.dataproducts.v1.UpsertDefinitionPartResponse)
### UpsertRequest
(synq.dataproducts.v1.UpsertRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_identifier.identifier | [optional DataproductIdentifier](#dataproductidentifier) | none |
| title | [ string](#string) | none |
| description | [ string](#string) | none |
| folder | [ string](#string) | none |
| priority | [ Priority](#priority) | none |
| source | [ Source](#source) | none |
### UpsertResponse
(synq.dataproducts.v1.UpsertResponse)
| Field | Type | Description |
| ---------- | ------------------------------------------------ | ------------------------------------------------ |
| identifier | [ DataproductIdentifier](#dataproductidentifier) | identifier of the updated or created dataproduct |
### Dataproduct
(synq.dataproducts.v2.Dataproduct)
A data product: a named, owned grouping of data assets that share a purpose,
with a membership definition, a priority and an optional folder.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the data product (a UUID). Supplied by the caller on create, which makes Upsert idempotent. |
| entity\_id | [ string](#string) | Stable, opaque platform identifier of this data product (of the form "dataproduct-\"). Output-only — the server derives it; never construct it by hand. This is the value other SYNQ APIs accept as an entity reference for this product (lineage, entities, alerts), so read it here and pass it there to point at the same product without needing to know how it is formed. `synq.owners.v1.OwnershipSelection.dataproduct_id` accepts this `entity_id` directly (or the bare `id`). |
| title | [ string](#string) | Human-readable title. |
| description | [ string](#string) | Optional longer description. |
| folder | [ string](#string) | Optional free-text folder used to group products in the UI. |
| priority | [ Priority](#priority) | none |
| source | [ Source](#source) | none |
| definition | [ DataproductDefinition](#dataproductdefinition) | The membership definition. Omitted when a read requests `exclude_definition`. |
| etag | [ string](#string) | Entity tag for optimistic concurrency: pass back on Upsert / Delete / definition writes to guard against overwriting a concurrent change. Form: `W/"-"`. Opaque — do not parse. |
| created\_by | [ Actor](#actor) | Who created the data product. Output-only. |
| updated\_by | [ Actor](#actor) | Who last edited the data product. Output-only. |
| created\_at | [ Timestamp](#timestamp) | When the data product was created. Output-only. |
| updated\_at | [ Timestamp](#timestamp) | When the data product was last updated. Output-only. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When the data product was soft-deleted, if it has been. Output-only. |
### DataproductDefinition
(synq.dataproducts.v2.DataproductDefinition)
The membership of a data product: which assets belong to it. A definition is
an ordered list of parts; an asset is a member if it matches ANY part (the
parts are OR'd together).
A data product is a LEAF in the reference graph: its membership is defined
only by asset-level predicates, static asset ids and lineage of those — never
by referencing another data product or domain. The `in_dataproduct` /
`in_domain` query operands are therefore rejected anywhere in a data product
definition (see DataproductQuery). This keeps membership resolution finite:
data products can never take part in a reference cycle.
| Field | Type | Description |
| ----- | ---------------------- | ------------------------------------------------------------------------- |
| parts | [repeated Part](#part) | The parts of the definition. An asset is a member if it matches any part. |
### DataproductDefinition.Part
(synq.dataproducts.v2.DataproductDefinition.Part)
A single piece of a data product definition: either a pinned asset or a
selection query.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Stable id of this part (a UUID). Supplied by the caller for idempotent part upserts; the server mints one if left empty on create. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.entity\_id | [ string](#string) | Pin a single asset by its opaque entity id (as returned by resolve / listing APIs). Never constructed by hand. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ DataproductQuery](#dataproductquery) | Select assets by a query. |
### DataproductQuery
(synq.dataproducts.v2.DataproductQuery)
The selection query behind a data product part, expressed for the public API.
On write, provide the query in ONE of two forms:
* `public_query` — a structured query (the same shape used elsewhere for
asset selection), convenient to build from a filter UI; or
* `resolver_ql` — the resolver query language, a compact text form that is
the canonical way to author selections as code.
When both are set, `resolver_ql` wins. The server compiles the query and
stores it canonically; the raw text is not preserved verbatim.
On read, the server returns `rendered_resolver_ql` (the stored query rendered
back to canonical resolver query language) and, best-effort, `public_query`
(the structured representation). `resolver_ql` is not echoed back — read
`rendered_resolver_ql`.
Leaf rule: a data product may not reference another data product or domain.
The `in_dataproduct`, `in_domain` and `unsupported` operands are rejected at
the top level here (CEL) and, for nested sub-queries, by a server-side walk.
| Field | Type | Description |
| ---------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| resolver\_ql | [ string](#string) | WRITE (option A). The query in resolver query language. |
| rendered\_resolver\_ql | [ string](#string) | READ, output-only. The stored query rendered back to canonical resolver query language. Deterministically derived; does not preserve original hand-typed formatting or comments. |
| public\_query | [ Query](#query) | WRITE (option B) and READ. On write, the structured query to store (used when `resolver_ql` is empty). On read, a best-effort structured representation of the stored query. |
### BatchGetRequest
(synq.dataproducts.v2.BatchGetRequest)
| Field | Type | Description |
| ------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| ids | [repeated string](#string) | Ids to fetch (1–200, unique). Each accepts either the bare UUID or the `entity_id` form (`dataproduct-`); the prefix is stripped server-side. |
| include\_deleted | [ bool](#bool) | Include soft-deleted products. |
| exclude\_definition | [ bool](#bool) | Omit the (potentially large) membership definition from each product. |
### BatchGetResponse
(synq.dataproducts.v2.BatchGetResponse)
| Field | Type | Description |
| ------------ | ------------------------------------------- | ------------------------------------------------------------------------------------------ |
| dataproducts | [map DataproductsEntry](#dataproductsentry) | Products keyed by id. Ids that do not exist (or are deleted, unless requested) are absent. |
### BatchGetResponse.DataproductsEntry
(synq.dataproducts.v2.BatchGetResponse.DataproductsEntry)
| Field | Type | Description |
| ----- | ---------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Dataproduct](#dataproduct) | none |
### DeleteRequest
(synq.dataproducts.v2.DeleteRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the product to delete. Accepts the bare UUID or the `dataproduct-` entity\_id form (the prefix is stripped server-side). |
| purge | [ bool](#bool) | Hard-delete instead of soft-delete, releasing the id for reuse. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
### DeleteResponse
(synq.dataproducts.v2.DeleteResponse)
### ListMembersRequest
(synq.dataproducts.v2.ListMembersRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the product whose members to list. Accepts the bare UUID or the `dataproduct-` entity\_id form (the prefix is stripped server-side). |
| pagination | [ Pagination](#pagination) | Pagination. |
### ListMembersResponse
(synq.dataproducts.v2.ListMembersResponse)
| Field | Type | Description |
| ----------- | -------------------------- | --------------------------------------------------------------------- |
| entity\_ids | [repeated string](#string) | Opaque entity ids of the assets that currently belong to the product. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### ListRequest
(synq.dataproducts.v2.ListRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | ------------------------------ | ----------------------------------------------------------- |
| pagination | [ Pagination](#pagination) | Pagination. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_folder.folder | [optional string](#string) | Restrict to a single folder. |
| priorities | [repeated Priority](#priority) | Restrict to these priorities. Empty returns all priorities. |
| include\_deleted | [ bool](#bool) | Include soft-deleted products. |
| exclude\_definition | [ bool](#bool) | Omit the membership definition from each product. |
### ListResponse
(synq.dataproducts.v2.ListResponse)
| Field | Type | Description |
| ------------ | ------------------------------------ | ------------------------------------ |
| dataproducts | [repeated Dataproduct](#dataproduct) | The matching products. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### RemoveDefinitionPartRequest
(synq.dataproducts.v2.RemoveDefinitionPartRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the product. Accepts the bare UUID or the `dataproduct-` entity\_id form (the prefix is stripped server-side). |
| part\_id | [ string](#string) | Id of the part to remove. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### RemoveDefinitionPartResponse
(synq.dataproducts.v2.RemoveDefinitionPartResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ------------------------------------------ |
| dataproduct | [ Dataproduct](#dataproduct) | The stored product after the part removal. |
### SetDefinitionRequest
(synq.dataproducts.v2.SetDefinitionRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the product whose definition to replace. Accepts the bare UUID or the `dataproduct-` entity\_id form (the prefix is stripped server-side). |
| definition | [ DataproductDefinition](#dataproductdefinition) | The new membership definition (replaces the existing one entirely). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### SetDefinitionResponse
(synq.dataproducts.v2.SetDefinitionResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ---------------------------------------------- |
| dataproduct | [ Dataproduct](#dataproduct) | The stored product after the definition write. |
### UpsertDefinitionPartRequest
(synq.dataproducts.v2.UpsertDefinitionPartRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ string](#string) | Id of the product. Accepts the bare UUID or the `dataproduct-` entity\_id form (the prefix is stripped server-side). |
| part | [ Part](#part) | The part to add or replace (matched by its part id). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### UpsertDefinitionPartResponse
(synq.dataproducts.v2.UpsertDefinitionPartResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ---------------------------------------- |
| dataproduct | [ Dataproduct](#dataproduct) | The stored product after the part write. |
### UpsertRequest
(synq.dataproducts.v2.UpsertRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the product. Accepts either the bare UUID or the `entity_id` form this API returns (`dataproduct-`) — the prefix is stripped server-side, so the value you read back from any API can be passed straight in. The same id updates the same product; a new id creates a new product. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Title. Required when creating; omit to keep the existing title on update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Description. Omit to keep the existing description. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_folder.folder | [optional string](#string) | Folder. Omit to keep the existing folder; pass an empty string to clear it. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_priority.priority | [optional Priority](#priority) | Priority. Omit to keep the existing priority. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source.source | [optional Source](#source) | Source. Omit to keep the existing source (defaults to SOURCE\_SYNQ on create). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_definition.definition | [optional DataproductDefinition](#dataproductdefinition) | Membership definition. Omit to keep the existing definition; pass a present (possibly empty) definition to replace it. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the update fails with a conflict if the product was modified since this etag was read. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### UpsertResponse
(synq.dataproducts.v2.UpsertResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ------------------------------------ |
| dataproduct | [ Dataproduct](#dataproduct) | The stored product after the upsert. |
### PageInfo
(synq.v1.PageInfo)
| Field | Type | Description |
| ------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| total\_count | [ int32](#int32) | Total number of items matching the request. May not be available for cursor-based pagination where the total is unknown or expensive to compute. Deprecated: most of the APIs which require pagination don't know the total count. |
| count | [ int32](#int32) | Number of items returned in this response. |
| last\_id | [ string](#string) | Opaque cursor token for fetching the next page of results. Pass this value as the cursor in the next Pagination request to continue pagination. Empty if there are no more pages. |
### Pagination
(synq.v1.Pagination)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cursor.cursor | [optional string](#string) | Opaque cursor token for the next page of results. If not provided, returns the first page. This is an encoded token that should be passed as-is from the previous PageInfo.last\_id. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_page\_size.page\_size | [optional int32](#int32) | Maximum number of items to return in a single page. If not provided, defaults vary per API. |
### ScopeAuthorization
(synq.v1.ScopeAuthorization)
| Field | Type | Description |
| ------ | ------------------------ | ----------- |
| scopes | [repeated Scope](#scope) | none |
### Contact
(synq.owners.v1.Contact)
A notification channel attached to an owner. An owner can hold several
contacts of different kinds; when an owner's ownership fires an alert, the
notification is delivered to every one of the owner's contacts.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) contact\_method.slack | [ SlackChannelContact](#slackchannelcontact) | Post to a Slack channel. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) contact\_method.email | [ EmailContact](#emailcontact) | Send to a fixed set of email addresses. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) contact\_method.ms\_teams | [ MsTeamsContact](#msteamscontact) | Post to a Microsoft Teams channel. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) contact\_method.users | [ UserContact](#usercontact) | Notify Coalesce Quality users by email. |
### EmailContact
(synq.owners.v1.EmailContact)
Deliver notifications by email to a fixed list of recipients.
| Field | Type | Description |
| ----------------- | -------------------------- | -------------------------- |
| recipient\_emails | [repeated string](#string) | Recipient email addresses. |
### MsTeamsContact
(synq.owners.v1.MsTeamsContact)
Deliver notifications to a Microsoft Teams channel, optionally @-mentioning
members.
| Field | Type | Description |
| ----------- | ------------------------------------------ | --------------------------------------------------- |
| channel\_id | [ string](#string) | Teams channel id to post in. |
| mentions | [repeated MsTeamsMention](#msteamsmention) | Members to @-mention in the notification. Optional. |
### MsTeamsMemberMention
(synq.owners.v1.MsTeamsMemberMention)
An @-mention of an individual Microsoft Teams member.
| Field | Type | Description |
| ---------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| member\_id | [ string](#string) | Teams member id that is actually mentioned. A workspace user's Teams member id is available from `synq.users.v1.UsersService` — the `msteams:` entry in `GetUserIdentities`, or an `ms_teams` alias on the user. |
| name | [ string](#string) | Display name of the member (informational). Optional. |
### MsTeamsMention
(synq.owners.v1.MsTeamsMention)
A single @-mention in a Microsoft Teams notification.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mention.member | [ MsTeamsMemberMention](#msteamsmembermention) | Mention an individual Teams member. |
### SlackChannelContact
(synq.owners.v1.SlackChannelContact)
Deliver notifications to a Slack channel, optionally @-mentioning users or
user groups in the message.
| Field | Type | Description |
| ---------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| channel | [ string](#string) | Channel to post in — a channel name (e.g. "#data-alerts") or a channel id (e.g. "C0123456789"). |
| team\_name | [ string](#string) | Name of the Slack workspace (team) the channel belongs to. Optional; only needed to disambiguate when more than one Slack workspace is connected. |
| mentions | [repeated SlackMention](#slackmention) | Users and/or user groups to @-mention in the notification. Optional. |
### SlackGroupMention
(synq.owners.v1.SlackGroupMention)
An @-mention of a Slack user group.
| Field | Type | Description |
| ----------- | ------------------ | -------------------------------------------------------------------- |
| group\_name | [ string](#string) | Display name of the group. Optional. |
| slack\_id | [ string](#string) | Slack user-group id that is actually mentioned (e.g. "S0123456789"). |
### SlackMention
(synq.owners.v1.SlackMention)
A single @-mention in a Slack notification.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mention.user | [ SlackUserMention](#slackusermention) | Mention an individual Slack user. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mention.group | [ SlackGroupMention](#slackgroupmention) | Mention a Slack user group. |
### SlackUserMention
(synq.owners.v1.SlackUserMention)
An @-mention of an individual Slack user.
| Field | Type | Description |
| ---------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| user\_name | [ string](#string) | Display handle of the user (informational; helps readers recognise the mention). Optional. |
| slack\_id | [ string](#string) | Slack user id that is actually mentioned (e.g. "U0123456789"). A workspace user's Slack id is available from `synq.users.v1.UsersService` — the `slack:` entry in `GetUserIdentities`, or a `slack` alias on the user. |
### UserContact
(synq.owners.v1.UserContact)
Deliver notifications to Coalesce Quality users, identified by email. Each
email should match a user in the workspace; the notification reaches them
through their own configured notification preferences.
Enumerate the valid users (and their emails) with `synq.users.v1.UsersService`
— `ListUsers` for the full set, or `GetByEmail` to validate a single address.
| Field | Type | Description |
| ------------ | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| user\_emails | [repeated string](#string) | Emails of the users to notify. Each should match a workspace user; look them up via `synq.users.v1.UsersService.ListUsers` / `GetByEmail`. |
### BatchGetOwnersRequest
(synq.owners.v1.BatchGetOwnersRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| ids | [repeated string](#string) | Owner ids to fetch (1–200, unique). Each accepts either the bare UUID or the `entity_id` form (`owner-`); the prefix is stripped server-side. |
| include\_deleted | [ bool](#bool) | Include soft-deleted owners. |
### BatchGetOwnersResponse
(synq.owners.v1.BatchGetOwnersResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------- |
| owners | [map OwnersEntry](#ownersentry) | Owners keyed by id. Ids that do not exist (or are deleted, unless requested) are absent. |
### BatchGetOwnersResponse.OwnersEntry
(synq.owners.v1.BatchGetOwnersResponse.OwnersEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Owner](#owner) | none |
### BatchGetOwnershipsRequest
(synq.owners.v1.BatchGetOwnershipsRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | --------------------------------------- |
| ids | [repeated string](#string) | Ownership ids to fetch (1–200, unique). |
| include\_deleted | [ bool](#bool) | Include soft-deleted ownerships. |
### BatchGetOwnershipsResponse
(synq.owners.v1.BatchGetOwnershipsResponse)
| Field | Type | Description |
| ---------- | --------------------------------------- | -------------------------------------------------------------------------------------------- |
| ownerships | [map OwnershipsEntry](#ownershipsentry) | Ownerships keyed by id. Ids that do not exist (or are deleted, unless requested) are absent. |
### BatchGetOwnershipsResponse.OwnershipsEntry
(synq.owners.v1.BatchGetOwnershipsResponse.OwnershipsEntry)
| Field | Type | Description |
| ----- | ------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Ownership](#ownership) | none |
### ContactList
(synq.owners.v1.ContactList)
A wrapper giving the contact set explicit presence on write, so a partial
update can distinguish "replace the contacts" (present, possibly empty) from
"leave contacts unchanged" (absent).
| Field | Type | Description |
| -------- | ---------------------------- | ----------- |
| contacts | [repeated Contact](#contact) | none |
### DeleteOwnerRequest
(synq.owners.v1.DeleteOwnerRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Id of the owner to delete. Accepts the bare UUID or the `owner-` entity\_id form (the prefix is stripped server-side). |
| purge | [ bool](#bool) | Hard-delete instead of soft-delete, releasing the id for reuse. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional. |
### DeleteOwnerResponse
(synq.owners.v1.DeleteOwnerResponse)
### DeleteOwnershipRequest
(synq.owners.v1.DeleteOwnershipRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------- |
| id | [ string](#string) | Id of the ownership to delete. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional. |
### DeleteOwnershipResponse
(synq.owners.v1.DeleteOwnershipResponse)
### ListOwnersRequest
(synq.owners.v1.ListOwnersRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | ---------------------------- |
| pagination | [ Pagination](#pagination) | Pagination. |
| include\_deleted | [ bool](#bool) | Include soft-deleted owners. |
### ListOwnersResponse
(synq.owners.v1.ListOwnersResponse)
| Field | Type | Description |
| ---------- | ------------------------ | ------------------------------------ |
| owners | [repeated Owner](#owner) | The matching owners. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### ListOwnershipsRequest
(synq.owners.v1.ListOwnershipsRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| owner\_id | [ string](#string) | Id of the owner whose ownerships to list. Accepts the bare UUID or the `owner-` entity\_id form (the prefix is stripped server-side). |
| pagination | [ Pagination](#pagination) | Pagination. |
| include\_deleted | [ bool](#bool) | Include soft-deleted ownerships. |
### ListOwnershipsResponse
(synq.owners.v1.ListOwnershipsResponse)
| Field | Type | Description |
| ---------- | -------------------------------- | ------------------------------------ |
| ownerships | [repeated Ownership](#ownership) | The owner's ownerships. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### UpsertOwnerRequest
(synq.owners.v1.UpsertOwnerRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the owner. Accepts either the bare UUID or the `entity_id` form this API returns (`owner-`) — the prefix is stripped server-side, so the value you read back from any API can be passed straight in. The same id updates the same owner; a new id creates a new owner. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Owner name. Required when creating; omit to keep the existing name on update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_contacts.contacts | [optional ContactList](#contactlist) | Notification channels. Omit to leave the existing contacts unchanged; pass a present (possibly empty) list to replace them. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source.source | [optional Source](#source) | Source. Omit to keep the existing source (defaults to SOURCE\_SYNQ on create). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the update fails with a conflict if the owner was modified since this etag was read. |
| actor | [ Actor](#actor) | Who is performing this write. Optional — identity is completed from the calling credentials; set it to attribute the change on behalf of a user. |
### UpsertOwnerResponse
(synq.owners.v1.UpsertOwnerResponse)
| Field | Type | Description |
| ----- | ---------------- | ---------------------------------- |
| owner | [ Owner](#owner) | The stored owner after the upsert. |
### UpsertOwnershipRequest
(synq.owners.v1.UpsertOwnershipRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| owner\_id | [ string](#string) | Id of the owner this ownership belongs to. Accepts the bare UUID or the `owner-` entity\_id form (the prefix is stripped server-side). |
| id | [ string](#string) | Opaque id of the ownership (a UUID). The same id updates the same ownership; a new id creates a new one. |
| selection | [ OwnershipSelection](#ownershipselection) | Which assets this ownership covers. |
| alert | [ AlertConfig](#alertconfig) | How alerts fire for the covered assets. Optional. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
| actor | [ Actor](#actor) | Who is performing this write. Optional. |
### UpsertOwnershipResponse
(synq.owners.v1.UpsertOwnershipResponse)
| Field | Type | Description |
| --------- | ------------------------ | -------------------------------------- |
| ownership | [ Ownership](#ownership) | The stored ownership after the upsert. |
### AlertConfig
(synq.owners.v1.AlertConfig)
How alerts fire for the assets an ownership covers. Deliberately mirrors the
settings on the public alerts API (`synq.alerts.v1`) so alerting behaviour
reads the same across SYNQ.
| Field | Type | Description |
| ----------------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| severities | [repeated Severity](#severity) | Failure severities that fire an alert (Warning / Error / Fatal). Empty means no severity is selected and the ownership routes no failure alerts. |
| notify\_upstream | [ bool](#bool) | Also alert on issues in the upstream dependencies of the covered assets. |
| ongoing | [ OngoingAlertsStrategy](#ongoingalertsstrategy) | How repeat notifications for a still-open issue are handled: no repeats (Disabled), a scheduled digest (Schedule — a daily digest in the app), or one on every failed run (Stream). Leave unset for no ongoing notifications. |
| allow\_sql\_test\_audit\_link | [ bool](#bool) | Include a link to the SQL test audit report in notifications. |
| is\_disabled | [ bool](#bool) | When true this ownership's alerts are turned off while the assignment itself stays in place. |
### Ownership
(synq.owners.v1.Ownership)
An ownership assigns a set of data assets to an owner and configures the
alerts routed to that owner about those assets. In the app this is the
owner's "Owned assets". One owner can hold many ownerships; deleting the
owner deletes all of its ownerships.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the ownership (a UUID) supplied by the caller on create, which makes UpsertOwnership idempotent. This is the same value `synq.alerts.v1.AlertsService` reports as the ownership reference (`synq.alerts.v1.Alert.Owner.ownership_id`) on an alert attributed to this owner. |
| owner\_id | [ string](#string) | Id of the Owner this ownership belongs to (the owner's `id`, a UUID). |
| selection | [ OwnershipSelection](#ownershipselection) | Which assets this ownership covers. |
| alert | [ AlertConfig](#alertconfig) | How alerts fire for the covered assets. |
| etag | [ string](#string) | Entity tag for optimistic concurrency: pass it back on UpsertOwnership / DeleteOwnership to guard against overwriting a concurrent change. Form: `W/"-"`. Opaque — do not parse. |
| created\_by | [ Actor](#actor) | Who created the ownership. Output-only. |
| updated\_by | [ Actor](#actor) | Who last edited the ownership. Output-only. |
| created\_at | [ Timestamp](#timestamp) | When the ownership was created. Output-only. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When the ownership was soft-deleted, if it has been. Output-only. |
### OwnershipQuery
(synq.owners.v1.OwnershipQuery)
A named asset selection behind an ownership, expressed for the public API.
Uses the same write/read bridge as saved views and data products.
On write, provide the query in ONE of two forms:
* `public_query` — a structured query (the same shape used elsewhere for
asset selection), convenient to build from a filter UI; or
* `resolver_ql` — the resolver query language, a compact text form that is
the canonical way to author selections as code.
When both are set, `resolver_ql` wins. The server compiles and stores the
query canonically; the raw text is not preserved verbatim.
On read, the server returns `rendered_resolver_ql` (the stored query rendered
back to canonical resolver query language) and, best-effort, `public_query`
(the structured representation). `resolver_ql` is not echoed back — read
`rendered_resolver_ql`.
| Field | Type | Description |
| ---------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Human-readable name of the asset group (shown as "Asset group name"). |
| resolver\_ql | [ string](#string) | WRITE (option A). The query in resolver query language. |
| rendered\_resolver\_ql | [ string](#string) | READ, output-only. The stored query rendered back to canonical resolver query language. Deterministically derived; does not preserve original hand-typed formatting or comments. |
| public\_query | [ Query](#query) | WRITE (option B) and READ. On write, the structured query to store (used when `resolver_ql` is empty). On read, a best-effort structured representation of the stored query. |
### OwnershipSelection
(synq.owners.v1.OwnershipSelection)
The set of assets an ownership covers.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.query | [ OwnershipQuery](#ownershipquery) | Assets matched by a query. Covers both a custom "asset group" and the "all assets" case (a match-all query). Unlike a data product definition (which must be a leaf), an ownership query MAY reference data products and domains — routing alerts for everything in a data product/domain is a first-class use. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.dataproduct\_id | [ string](#string) | All assets belonging to a single data product, referenced by its opaque id (the `id` of a `synq.dataproducts.v2.Dataproduct`, as returned by `synq.dataproducts.v2.DataproductsService`). Accepts either the bare UUID or the `entity_id` form (`dataproduct-`) — the prefix is stripped server-side, so a product's `entity_id` from lineage can be assigned directly. The data product must exist in the workspace at write time. |
### Owner
(synq.owners.v1.Owner)
An owner: a named responsible party (a team or a person) that data assets can
be assigned to, together with the notification channels alerts about those
assets are delivered to. Assets are attached to an owner through Ownerships
(see OwnershipsService), so an owner on its own routes nothing until at least
one ownership assigns it some assets.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Opaque id of the owner (a UUID) supplied by the caller on create, which makes UpsertOwner idempotent. This is the id used to address the owner on this API (creating ownerships under it, deleting it). |
| entity\_id | [ string](#string) | Stable, opaque platform identifier of this owner (of the form "owner-\"). Output-only — the server derives it; never construct it by hand. This is the exact value other SYNQ APIs accept as an owner reference (for example the `synq.alerts.v1.AlertsService` owner path — see `synq.alerts.v1.Alert.Owner`), so read it here and pass it there to point at the same owner without needing to know how it is formed. |
| title | [ string](#string) | Human-readable name of the owner (shown as "Owner name" in the app). |
| contacts | [repeated Contact](#contact) | Notification channels for this owner. A fired alert is delivered to every contact. |
| source | [ Source](#source) | none |
| etag | [ string](#string) | Entity tag for optimistic concurrency: pass it back on UpsertOwner / DeleteOwner to guard against overwriting a concurrent change. Form: `W/"-"`. Opaque — do not parse. |
| created\_by | [ Actor](#actor) | Who created the owner. Output-only. |
| updated\_by | [ Actor](#actor) | Who last edited the owner. Output-only. |
| created\_at | [ Timestamp](#timestamp) | When the owner was created. Output-only. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When the owner was soft-deleted, if it has been. Output-only. |
### EmailUser
(synq.users.v1.EmailUser)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| user\_email | [ string](#string) | none |
### MsTeamsUser
(synq.users.v1.MsTeamsUser)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| member\_id | [ string](#string) | none |
### SlackUser
(synq.users.v1.SlackUser)
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
### User
(synq.users.v1.User)
| Field | Type | Description |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | none |
| first\_name | [ string](#string) | none |
| last\_name | [ string](#string) | none |
| email | [ string](#string) | none |
| identities | [repeated string](#string) | Canonical identity strings for this user. Includes "synq:\" and all linked aliases (email, slack, msteams). Can be passed to ListIssues(interacted\_by\_identities) to filter issues this user interacted with. |
### UserAlias
(synq.users.v1.UserAlias)
| Field | Type | Description |
| -------------------------------------------------------------------------------------------- | ---------------------------- | ----------- |
| user\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.slack | [ SlackUser](#slackuser) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.email | [ EmailUser](#emailuser) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.ms\_teams | [ MsTeamsUser](#msteamsuser) | none |
### BatchGetUsersRequest
(synq.users.v1.BatchGetUsersRequest)
| Field | Type | Description |
| --------- | -------------------------- | ----------- |
| user\_ids | [repeated string](#string) | none |
### BatchGetUsersResponse
(synq.users.v1.BatchGetUsersResponse)
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| users | [repeated User](#user) | none |
### DeleteUserAliasesRequest
(synq.users.v1.DeleteUserAliasesRequest)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| aliases | [repeated UserAlias](#useralias) | none |
### DeleteUserAliasesResponse
(synq.users.v1.DeleteUserAliasesResponse)
### GetByAliasRequest
(synq.users.v1.GetByAliasRequest)
| Field | Type | Description |
| ----- | ------------------------ | ----------- |
| alias | [ UserAlias](#useralias) | none |
### GetByAliasResponse
(synq.users.v1.GetByAliasResponse)
| Field | Type | Description |
| ----- | -------------- | ----------- |
| user | [ User](#user) | none |
### GetByEmailRequest
(synq.users.v1.GetByEmailRequest)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| email | [ string](#string) | none |
### GetByEmailResponse
(synq.users.v1.GetByEmailResponse)
| Field | Type | Description |
| ----- | -------------- | ----------- |
| user | [ User](#user) | none |
### GetUserAliasesRequest
(synq.users.v1.GetUserAliasesRequest)
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
### GetUserAliasesResponse
(synq.users.v1.GetUserAliasesResponse)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| aliases | [repeated UserAlias](#useralias) | none |
### GetUserIdentitiesRequest
(synq.users.v1.GetUserIdentitiesRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user\_id.user\_id | [optional string](#string) | User ID to resolve identities for. If omitted, uses the currently authenticated user. |
### GetUserIdentitiesResponse
(synq.users.v1.GetUserIdentitiesResponse)
| Field | Type | Description |
| ---------- | -------------------------- | --------------------------------------------------------------------------------------------------- |
| identities | [repeated string](#string) | Canonical identity strings for the user. Always includes "synq:\" and all linked aliases. |
### ListUsersRequest
(synq.users.v1.ListUsersRequest)
### ListUsersResponse
(synq.users.v1.ListUsersResponse)
| Field | Type | Description |
| ----- | ---------------------- | ----------- |
| users | [repeated User](#user) | none |
### UpsertUserAliasesRequest
(synq.users.v1.UpsertUserAliasesRequest)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| aliases | [repeated UserAlias](#useralias) | none |
### UpsertUserAliasesResponse
(synq.users.v1.UpsertUserAliasesResponse)
### FetchRunsRequest
(synq.extensions.atlan.workflows.v1.FetchRunsRequest)
| Field | Type | Description |
| ----- | ---------------- | ----------- |
| from | [ int32](#int32) | none |
| limit | [ int32](#int32) | none |
### FetchRunsResponse
(synq.extensions.atlan.workflows.v1.FetchRunsResponse)
| Field | Type | Description |
| -------------- | ------------------------------------ | ----------- |
| workflow\_runs | [repeated WorkflowRun](#workflowrun) | none |
### GetConnectionMappingsRequest
(synq.extensions.atlan.workflows.v1.GetConnectionMappingsRequest)
### GetConnectionMappingsResponse
(synq.extensions.atlan.workflows.v1.GetConnectionMappingsResponse)
| Field | Type | Description |
| -------- | ------------------------------------------------ | ----------- |
| mappings | [repeated ConnectionMapping](#connectionmapping) | none |
### GetDomainMappingsRequest
(synq.extensions.atlan.workflows.v1.GetDomainMappingsRequest)
### GetDomainMappingsResponse
(synq.extensions.atlan.workflows.v1.GetDomainMappingsResponse)
| Field | Type | Description |
| -------- | ---------------------------------------- | ----------- |
| mappings | [repeated DomainMapping](#domainmapping) | none |
### GetMappingTogglesRequest
(synq.extensions.atlan.workflows.v1.GetMappingTogglesRequest)
### GetMappingTogglesResponse
(synq.extensions.atlan.workflows.v1.GetMappingTogglesResponse)
| Field | Type | Description |
| ------- | ---------------------------------------- | ----------- |
| toggles | [repeated MappingToggle](#mappingtoggle) | none |
### GetProductMappingsRequest
(synq.extensions.atlan.workflows.v1.GetProductMappingsRequest)
### GetProductMappingsResponse
(synq.extensions.atlan.workflows.v1.GetProductMappingsResponse)
| Field | Type | Description |
| -------- | ------------------------------------------ | ----------- |
| mappings | [repeated ProductMapping](#productmapping) | none |
### RemoveConnectionMappingsRequest
(synq.extensions.atlan.workflows.v1.RemoveConnectionMappingsRequest)
| Field | Type | Description |
| ----------------------------------- | -------------------------- | ----------- |
| atlan\_connection\_qualified\_names | [repeated string](#string) | none |
### RemoveConnectionMappingsResponse
(synq.extensions.atlan.workflows.v1.RemoveConnectionMappingsResponse)
### SetConnectionMappingsRequest
(synq.extensions.atlan.workflows.v1.SetConnectionMappingsRequest)
| Field | Type | Description |
| -------- | ------------------------------------------------ | ----------- |
| mappings | [repeated ConnectionMapping](#connectionmapping) | none |
### SetConnectionMappingsResponse
(synq.extensions.atlan.workflows.v1.SetConnectionMappingsResponse)
### SetMappingTogglesRequest
(synq.extensions.atlan.workflows.v1.SetMappingTogglesRequest)
| Field | Type | Description |
| ------- | ---------------------------------------- | ----------- |
| toggles | [repeated MappingToggle](#mappingtoggle) | none |
### SetMappingTogglesResponse
(synq.extensions.atlan.workflows.v1.SetMappingTogglesResponse)
### SynchronizeRequest
(synq.extensions.atlan.workflows.v1.SynchronizeRequest)
| Field | Type | Description |
| ------- | -------------- | ----------- |
| use\_v2 | [ bool](#bool) | none |
### SynchronizeResponse
(synq.extensions.atlan.workflows.v1.SynchronizeResponse)
| Field | Type | Description |
| ------------- | ---------------------------- | ----------- |
| workflow\_run | [ WorkflowRun](#workflowrun) | none |
| has\_errors | [ bool](#bool) | none |
### ConnectionMapping
(synq.extensions.atlan.workflows.v1.ConnectionMapping)
| Field | Type | Description |
| ---------------------------------- | -------------------------------------------------- | ----------- |
| atlan\_connection\_qualified\_name | [ string](#string) | none |
| synq\_data\_platform\_identifier | [ DataPlatformIdentifier](#dataplatformidentifier) | none |
### DomainMapping
(synq.extensions.atlan.workflows.v1.DomainMapping)
| Field | Type | Description |
| ------------------------------ | ------------------ | ----------- |
| atlan\_domain\_qualified\_name | [ string](#string) | none |
| synq\_domain\_id | [ string](#string) | none |
### ProductMapping
(synq.extensions.atlan.workflows.v1.ProductMapping)
| Field | Type | Description |
| ----------------------------------- | ------------------------------------------------ | ----------- |
| atlan\_dataproduct\_qualified\_name | [ string](#string) | none |
| synq\_dataproduct\_identifier | [ DataproductIdentifier](#dataproductidentifier) | none |
### CommandResult
(synq.extensions.atlan.workflows.v1.CommandResult)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| command | [ string](#string) | none |
| status | [ Status](#status) | none |
| logs | [repeated string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_error.error | [optional string](#string) | none |
### Log
(synq.extensions.atlan.workflows.v1.Log)
| Field | Type | Description |
| --------- | ----------------------------------- | ----------- |
| message | [ string](#string) | none |
| timestamp | [ Timestamp](#timestamp) | none |
| status | [ Status](#status) | none |
| metadata | [map MetadataEntry](#metadataentry) | none |
### Log.MetadataEntry
(synq.extensions.atlan.workflows.v1.Log.MetadataEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### WorkflowRun
(synq.extensions.atlan.workflows.v1.WorkflowRun)
| Field | Type | Description |
| ----------- | ---------------------------------------- | ---------------------------- |
| workspace | [ string](#string) | none |
| results | [repeated CommandResult](#commandresult) | Deprecated: Use Log instead. |
| status | [ Status](#status) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| ended\_at | [ Timestamp](#timestamp) | none |
| logs | [repeated Log](#log) | none |
### DomainMappingToggle
(synq.extensions.atlan.workflows.v1.DomainMappingToggle)
| Field | Type | Description |
| ------------------------------ | ------------------ | ----------- |
| atlan\_domain\_qualified\_name | [ string](#string) | none |
### MappingToggle
(synq.extensions.atlan.workflows.v1.MappingToggle)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mapping.product\_mapping | [ ProductMappingToggle](#productmappingtoggle) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mapping.domain\_mapping | [ DomainMappingToggle](#domainmappingtoggle) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mapping.product\_owner\_mapping | [ ProductOwnerMappingToggle](#productownermappingtoggle) | none |
| enabled | [ bool](#bool) | none |
### ProductMappingToggle
(synq.extensions.atlan.workflows.v1.ProductMappingToggle)
| Field | Type | Description |
| ------------------------------- | ------------------ | ----------- |
| atlan\_product\_qualified\_name | [ string](#string) | none |
### ProductOwnerMappingToggle
(synq.extensions.atlan.workflows.v1.ProductOwnerMappingToggle)
| Field | Type | Description |
| ------------------------------- | ------------------ | ----------- |
| atlan\_product\_qualified\_name | [ string](#string) | none |
### AtlanConnection
(synq.extensions.atlan.provider.v1.AtlanConnection)
| Field | Type | Description |
| --------------- | ------------------ | ----------- |
| name | [ string](#string) | none |
| qualified\_name | [ string](#string) | none |
### AtlanDataDomain
(synq.extensions.atlan.provider.v1.AtlanDataDomain)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------------------------- | ----------- |
| name | [ string](#string) | none |
| qualified\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_parent.parent | [optional AtlanDataDomain](#atlandatadomain) | none |
### AtlanDataProduct
(synq.extensions.atlan.provider.v1.AtlanDataProduct)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------------------------- | --------------------------------------------------- |
| name | [ string](#string) | none |
| qualified\_name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_domain.domain | [optional AtlanDataDomain](#atlandatadomain) | none |
| owner\_users | [ Emails](#emails) | emails for the owner users |
| owner\_groups | [map OwnerGroupsEntry](#ownergroupsentry) | emails for the owner groups mapped against group ID |
### AtlanDataProduct.Emails
(synq.extensions.atlan.provider.v1.AtlanDataProduct.Emails)
| Field | Type | Description |
| ------ | -------------------------- | ----------- |
| emails | [repeated string](#string) | none |
### AtlanDataProduct.OwnerGroupsEntry
(synq.extensions.atlan.provider.v1.AtlanDataProduct.OwnerGroupsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Emails](#emails) | none |
### GetAtlanConnectionsRequest
(synq.extensions.atlan.provider.v1.GetAtlanConnectionsRequest)
### GetAtlanConnectionsResponse
(synq.extensions.atlan.provider.v1.GetAtlanConnectionsResponse)
| Field | Type | Description |
| ----------- | -------------------------------------------- | ----------- |
| connections | [repeated AtlanConnection](#atlanconnection) | none |
### GetAtlanDataProductsRequest
(synq.extensions.atlan.provider.v1.GetAtlanDataProductsRequest)
### GetAtlanDataProductsResponse
(synq.extensions.atlan.provider.v1.GetAtlanDataProductsResponse)
| Field | Type | Description |
| -------------- | ---------------------------------------------- | ----------- |
| data\_products | [repeated AtlanDataProduct](#atlandataproduct) | none |
### GetAtlanDomainsRequest
(synq.extensions.atlan.provider.v1.GetAtlanDomainsRequest)
### GetAtlanDomainsResponse
(synq.extensions.atlan.provider.v1.GetAtlanDomainsResponse)
| Field | Type | Description |
| ------- | -------------------------------------------- | ----------- |
| domains | [repeated AtlanDataDomain](#atlandatadomain) | none |
### Integration
(synq.extensions.atlan.integrations.v1.Integration)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------ |
| workspace | [ string](#string) | none |
| id | [ string](#string) | ID for the integration. Unique for a workspace. |
| atlan\_tenant\_url | [ string](#string) | none |
| atlan\_api\_token | [ string](#string) | none |
| is\_valid | [ bool](#bool) | Whether the integration is valid or not. Set on `upsert` as a result of connection to atlan api. |
| is\_active | [ bool](#bool) | Whether the integration is active or not. Only valid integrations can be activated. |
| created\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | none |
| updated\_at | [ Timestamp](#timestamp) | none |
### ActivateRequest
(synq.extensions.atlan.integrations.v1.ActivateRequest)
| Field | Type | Description |
| -------- | -------------- | ----------- |
| activate | [ bool](#bool) | none |
### ActivateResponse
(synq.extensions.atlan.integrations.v1.ActivateResponse)
### GetRequest
(synq.extensions.atlan.integrations.v1.GetRequest)
### GetResponse
(synq.extensions.atlan.integrations.v1.GetResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ----------- |
| integration | [ Integration](#integration) | none |
### PingRequest
(synq.extensions.atlan.integrations.v1.PingRequest)
| Field | Type | Description |
| ------------------ | ------------------ | ----------- |
| atlan\_tenant\_url | [ string](#string) | none |
| atlan\_api\_token | [ string](#string) | none |
### PingResponse
(synq.extensions.atlan.integrations.v1.PingResponse)
| Field | Type | Description |
| ------- | -------------- | ----------- |
| success | [ bool](#bool) | none |
### RemoveRequest
(synq.extensions.atlan.integrations.v1.RemoveRequest)
### RemoveResponse
(synq.extensions.atlan.integrations.v1.RemoveResponse)
### UpsertRequest
(synq.extensions.atlan.integrations.v1.UpsertRequest)
| Field | Type | Description |
| ------------------ | ------------------ | ----------- |
| atlan\_tenant\_url | [ string](#string) | none |
| atlan\_api\_token | [ string](#string) | none |
### UpsertResponse
(synq.extensions.atlan.integrations.v1.UpsertResponse)
| Field | Type | Description |
| ----------- | ---------------------------- | ----------- |
| integration | [ Integration](#integration) | none |
### CommitDiff
(synq.git.commits.v1.CommitDiff)
| Field | Type | Description |
| ----------- | ------------------------------ | ----------- |
| commit\_sha | [ string](#string) | none |
| file\_diffs | [repeated FileDiff](#filediff) | none |
### FileDiff
(synq.git.commits.v1.FileDiff)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| file\_path | [ string](#string) | none |
| diff | [ string](#string) | none |
### GetDiffByChangeIdRequest
(synq.git.commits.v1.GetDiffByChangeIdRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | ----------- |
| change\_id | [ string](#string) | none |
| limit\_to\_files | [repeated string](#string) | none |
### GetDiffByChangeIdResponse
(synq.git.commits.v1.GetDiffByChangeIdResponse)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_commit\_diff.commit\_diff | [optional CommitDiff](#commitdiff) | none |
### GetDiffByCommitRequest
(synq.git.commits.v1.GetDiffByCommitRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| commit\_sha | [ string](#string) | Commit SHA. Accepts either the full 40-char hex hash or any unique hex prefix of at least 7 characters (server resolves the prefix against stored commits, like `git rev-parse `). Ambiguous or unmatched prefixes return an empty diff rather than an error. |
| limit\_to\_files | [repeated string](#string) | none |
### GetDiffByCommitResponse
(synq.git.commits.v1.GetDiffByCommitResponse)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_commit\_diff.commit\_diff | [optional CommitDiff](#commitdiff) | none |
### CloudwatchLogsLogEvent
(synq.ingest.cloudwatch.v1.CloudwatchLogsLogEvent)
| Field | Type | Description |
| --------- | ------------------------ | ----------- |
| id | [ string](#string) | none |
| timestamp | [ Timestamp](#timestamp) | none |
| message | [ string](#string) | none |
### IngestCloudwatchLogsDataRequest
(synq.ingest.cloudwatch.v1.IngestCloudwatchLogsDataRequest)
| Field | Type | Description |
| --------------------- | ---------------------------------------------------------- | ----------- |
| owner | [ string](#string) | none |
| log\_group | [ string](#string) | none |
| log\_stream | [ string](#string) | none |
| subscription\_filters | [repeated string](#string) | none |
| message\_type | [ string](#string) | none |
| log\_events | [repeated CloudwatchLogsLogEvent](#cloudwatchlogslogevent) | none |
### IngestCloudwatchLogsDataResponse
(synq.ingest.cloudwatch.v1.IngestCloudwatchLogsDataResponse)
### QueryLog
(synq.ingest.dwh.v1.QueryLog)
QueryLog represents a single query execution log entry from a data warehouse.
This is the format used for ingesting query logs via the DWH agent.
The structure mirrors the internal QueryLogRawRow with protobuf serialization.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------- | --------------------------------------------------------- |
| workspace | [ string](#string) | Workspace and integration identifiers (for multi-tenancy) |
| integration\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_connection\_id.connection\_id | [optional string](#string) | Empty for direct connections, populated for agent uploads |
| query\_id | [ string](#string) | Query identifiers |
| created\_at | [ Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_at.started\_at | [optional Timestamp](#timestamp) | Query start time (optional, uses created\_at if not set) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_finished\_at.finished\_at | [optional Timestamp](#timestamp) | Query finish time (optional, uses created\_at if not set) |
| sql | [ string](#string) | Query content |
SQL text (may be obfuscated based on sql\_obfuscation\_mode) |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sql\_hash.sql\_hash | [optional string](#string) | SHA256 hash of original SQL for deduplication (computed during storage if not provided) |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_normalized\_query\_hash.normalized\_query\_hash | [optional string](#string) | Hash of normalized query for lineage caching (empty if not available from platform) |
\| sql\_dialect | [ string](#string) | SQL dialect (e.g., "snowflake", "bigquery", "clickhouse") |
\| query\_type | [ string](#string) | Platform-specific query type (e.g., "CREATE\_TABLE\_AS\_SELECT", "SELECT") |
\| status | [ string](#string) | Execution status: "SUCCESS", "FAILED", "CANCELED" |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dwh\_context.dwh\_context | [optional QueryLogDwhContext](#querylogdwhcontext) | DWH execution context |
\| sql\_obfuscation\_mode | [ SqlObfuscationMode](#sqlobfuscationmode) | Obfuscation and parsing hints |
\| has\_complete\_native\_lineage | [ bool](#bool) | If true, native lineage is complete and SQL parsing can be skipped |
\| is\_truncated | [ bool](#bool) | If true, SQL was truncated by the warehouse |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_metadata.metadata | [optional Struct](#struct) | Platform-specific metadata (arbitrary key-value pairs) Contains execution metrics, costs, etc. depending on the platform |
\| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_native\_lineage.native\_lineage | [optional QueryLogNativeLineage](#querylognativelineage) | Native lineage from the platform (if available) |
### QueryLogDwhContext
(synq.ingest.dwh.v1.QueryLogDwhContext)
QueryLogDwhContext represents the execution context of a query.
Contains information about where and by whom the query was executed.
Platform-specific mappings (Instance, Database, Schema):
* Snowflake: account, database\_name, schema\_name
* Databricks: workspace\_url, catalog\_name, schema\_name
* BigQuery: "", project\_id, dataset\_id
* Redshift: host, database\_name, schema\_name
* Postgres: host, database\_name, schema\_name
* Trino: host, catalog, schema
* MySQL: "", host, schema\_name
* ClickHouse: hostname, database\_name, "" (2-level: hostname.database)
* DuckDB: motherduck\_account, database\_name, schema\_name
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_instance.instance | [optional string](#string) | Instance identifier (account, workspace\_url, host, etc.) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database/catalog name |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schema.schema | [optional string](#string) | Schema name |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_warehouse.warehouse | [optional string](#string) | Warehouse identifier (Snowflake, Databricks) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | User who executed the query |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_role.role | [optional string](#string) | Role used for execution |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cluster.cluster | [optional string](#string) | Cluster identifier (Redshift, ClickHouse) |
### QueryLogNativeLineage
(synq.ingest.dwh.v1.QueryLogNativeLineage)
QueryLogNativeLineage contains lineage information provided natively by the data warehouse.
Not all platforms provide this - when available, it can be more accurate than SQL parsing.
| Field | Type | Description |
| -------------- | -------------------- | ------------------------------ |
| input\_tables | [repeated Fqn](#fqn) | Tables read by the query |
| output\_tables | [repeated Fqn](#fqn) | Tables written to by the query |
### Fqn
(synq.ingest.dwh.v1.Fqn)
| Field | Type | Description |
| -------------- | ------------------ | ----------- |
| instance\_name | [ string](#string) | none |
| database\_name | [ string](#string) | none |
| schema\_name | [ string](#string) | none |
| object\_name | [ string](#string) | none |
### ObjectInformation
(synq.ingest.dwh.v1.ObjectInformation)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| fqn | [ Fqn](#fqn) | none |
| object\_native\_type | [ string](#string) | none |
| is\_view | [ bool](#bool) | none |
| is\_table | [ bool](#bool) | none |
| tags | [repeated Tag](#tag) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | none |
### ObjectMetrics
(synq.ingest.dwh.v1.ObjectMetrics)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------- | ----------- |
| fqn | [ Fqn](#fqn) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_row\_count.row\_count | [optional int64](#int64) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_updated\_at.updated\_at | [optional Timestamp](#timestamp) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_size\_bytes.size\_bytes | [optional int64](#int64) | none |
### Schema
(synq.ingest.dwh.v1.Schema)
| Field | Type | Description |
| ------- | -------------------------------------- | ----------- |
| fqn | [ Fqn](#fqn) | none |
| columns | [repeated SchemaColumn](#schemacolumn) | none |
### SchemaColumn
(synq.ingest.dwh.v1.SchemaColumn)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- |
| name | [ string](#string) | none |
| native\_type | [ string](#string) | none |
| ordinal\_position | [ int32](#int32) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | none |
| tags | [repeated Tag](#tag) | none |
| is\_struct | [ bool](#bool) | none |
| is\_repeated | [ bool](#bool) | none |
| fields | [repeated SchemaColumnField](#schemacolumnfield) | none |
### SchemaColumnField
(synq.ingest.dwh.v1.SchemaColumnField)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- |
| name | [ string](#string) | none |
| native\_type | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | none |
| ordinal\_position | [ int32](#int32) | none |
| is\_struct | [ bool](#bool) | none |
| is\_repeated | [ bool](#bool) | none |
| fields | [repeated SchemaColumnField](#schemacolumnfield) | none |
### SqlDefinition
(synq.ingest.dwh.v1.SqlDefinition)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| fqn | [ Fqn](#fqn) | none |
| sql | [ string](#string) | none |
### TableConstraint
(synq.ingest.dwh.v1.TableConstraint)
TableConstraint represents a single constraint or index on a database table.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Name of the constraint or index |
| type | [ string](#string) | Type of the constraint (e.g. PRIMARY\_KEY, FOREIGN\_KEY, UNIQUE, CHECK, INDEX) |
| columns | [repeated string](#string) | Column names involved in this constraint or index |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_foreign\_key\_target.foreign\_key\_target | [optional Fqn](#fqn) | For foreign key: referenced table FQN |
| foreign\_key\_target\_columns | [repeated string](#string) | For foreign key: referenced column names |
| index\_type | [ string](#string) | Index type (e.g. "btree", "hash", "gin") |
| expression | [ string](#string) | Expression for check constraints or expression-based indexes |
| is\_unique | [ bool](#bool) | Whether this constraint or index enforces uniqueness |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_enforced.is\_enforced | [optional bool](#bool) | Whether this constraint is enforced by the database. nil/unset = unknown, true = enforced, false = not enforced. |
### TableConstraints
(synq.ingest.dwh.v1.TableConstraints)
TableConstraints contains all constraints and indexes for a single table.
| Field | Type | Description |
| ----------- | -------------------------------------------- | ----------- |
| fqn | [ Fqn](#fqn) | none |
| constraints | [repeated TableConstraint](#tableconstraint) | none |
### Tag
(synq.ingest.dwh.v1.Tag)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| tag\_name | [ string](#string) | none |
| tag\_value | [ string](#string) | none |
### LineageColumnEdge
(synq.ingest.dwh.v1.LineageColumnEdge)
LineageColumnEdge is a single column-to-column dependency carried inside a
table-level edge. Optional: omit to declare table-level lineage only. The
columns name positions on the parent LineageEdge's `upstream` and
`downstream` objects respectively.
| Field | Type | Description |
| ------------------ | ------------------ | -------------------------------------------------------------- |
| upstream\_column | [ string](#string) | Column on the upstream (source) object. |
| downstream\_column | [ string](#string) | Column on the downstream (target) object that derives from it. |
### LineageEdge
(synq.ingest.dwh.v1.LineageEdge)
LineageEdge is one directed dependency: data flows from `upstream` into
`downstream`. Represent multi-hop lineage as the set of its direct
(distance-1) edges; do not collapse intermediate hops, so the graph stays
explicit and each hop keeps its own object domain and column edges.
| Field | Type | Description |
| ------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| upstream | [ LineageNode](#lineagenode) | Object the data flows from. |
| downstream | [ LineageNode](#lineagenode) | Object the data flows into. |
| column\_edges | [repeated LineageColumnEdge](#lineagecolumnedge) | Optional column-level dependencies within this edge. When any edge for a given downstream object carries column edges, that object's lineage is treated as column-level; otherwise it is table-level only. |
| meta | [ Struct](#struct) | Free-form provenance about how this edge was established (for example the query id, or the warehouse's own description of the deriving process). Stored as-is and not interpreted by the platform. |
### LineageNode
(synq.ingest.dwh.v1.LineageNode)
LineageNode identifies one object that participates in a lineage edge.
| Field | Type | Description |
| ------ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| fqn | [ Fqn](#fqn) | Fully-qualified name of the object. `object_name` is required; set the higher levels (instance / database / schema) to whatever the warehouse exposes so the platform can resolve the object to a known asset. |
| domain | [ LineageObjectDomain](#lineageobjectdomain) | What kind of object this is. Lets the platform separate true table-to-table lineage from edges that involve warehouse-internal objects. |
### DatabasesScope
(synq.ingest.dwh.v1.DatabasesScope)
DatabasesScope makes the batch authoritative for the listed databases only.
| Field | Type | Description |
| --------- | -------------------------- | ------------------------------------------------ |
| databases | [repeated string](#string) | Each entry is "database" or "instance.database". |
### IngestLineageRequest
(synq.ingest.dwh.v1.IngestLineageRequest)
IngestLineageRequest carries one batch of lineage edges for a single
warehouse connection. Send many batches with the same connection\_id over
time; each batch is interpreted against the others according to
`replace_mode`.
| Field | Type | Description |
| -------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| connection\_id | [ string](#string) | Identifier of the warehouse connection this lineage was read from. Use the same connection\_id you use for the other Ingest\* calls of this warehouse so the lineage attaches to the right objects. |
| upload\_id | [ string](#string) | A unique id for this batch (UUID). Re-sending a batch with the same upload\_id is de-duplicated, so it is safe to retry. |
| state\_at | [ Timestamp](#timestamp) | Time at which the lineage was extracted from the warehouse. |
| source | [ LineageSource](#lineagesource) | How the lineage was derived. Drives the precedence of the resulting edges and keeps lineage of different origins from overwriting one another. |
| replace\_mode | [ LineageReplaceMode](#lineagereplacemode) | How this batch supersedes previously-ingested lineage. Defaults to MERGE (incremental) when unset. |
| scope | [ LineageScope](#lineagescope) | Required when replace\_mode is REPLACE\_SCOPE; ignored otherwise. |
| edges | [repeated LineageEdge](#lineageedge) | The lineage edges in this batch. Empty in REPLACE\_SCOPE mode is a valid way to expire all lineage inside the scope. |
### IngestLineageResponse
(synq.ingest.dwh.v1.IngestLineageResponse)
IngestLineageResponse is intentionally empty; a successful call means the
batch was accepted for processing.
### IngestObjectInformationRequest
(synq.ingest.dwh.v1.IngestObjectInformationRequest)
| Field | Type | Description |
| -------------- | ------------------------------------------------ | --------------------------------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| objects | [repeated ObjectInformation](#objectinformation) | none |
### IngestObjectInformationResponse
(synq.ingest.dwh.v1.IngestObjectInformationResponse)
### IngestObjectMetricsRequest
(synq.ingest.dwh.v1.IngestObjectMetricsRequest)
| Field | Type | Description |
| -------------- | ---------------------------------------- | --------------------------------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| metrics | [repeated ObjectMetrics](#objectmetrics) | none |
### IngestObjectMetricsResponse
(synq.ingest.dwh.v1.IngestObjectMetricsResponse)
### IngestQueryLogsRequest
(synq.ingest.dwh.v1.IngestQueryLogsRequest)
| Field | Type | Description |
| -------------- | ------------------------------ | ----------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| query\_logs | [repeated QueryLog](#querylog) | none |
### IngestQueryLogsResponse
(synq.ingest.dwh.v1.IngestQueryLogsResponse)
### IngestSchemasRequest
(synq.ingest.dwh.v1.IngestSchemasRequest)
| Field | Type | Description |
| -------------- | -------------------------- | --------------------------------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| schemas | [repeated Schema](#schema) | none |
### IngestSchemasResponse
(synq.ingest.dwh.v1.IngestSchemasResponse)
### IngestSqlDefinitionsRequest
(synq.ingest.dwh.v1.IngestSqlDefinitionsRequest)
| Field | Type | Description |
| ---------------- | ---------------------------------------- | --------------------------------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| sql\_definitions | [repeated SqlDefinition](#sqldefinition) | none |
### IngestSqlDefinitionsResponse
(synq.ingest.dwh.v1.IngestSqlDefinitionsResponse)
### IngestTableConstraintsRequest
(synq.ingest.dwh.v1.IngestTableConstraintsRequest)
| Field | Type | Description |
| ------------------ | ---------------------------------------------- | --------------------------------- |
| connection\_id | [ string](#string) | none |
| upload\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| table\_constraints | [repeated TableConstraints](#tableconstraints) | none |
### IngestTableConstraintsResponse
(synq.ingest.dwh.v1.IngestTableConstraintsResponse)
### IngestTaskResultsRequest
(synq.ingest.dwh.v1.IngestTaskResultsRequest)
| Field | Type | Description |
| -------------- | -------------------------------- | --------------------------------- |
| connection\_id | [ string](#string) | none |
| task\_id | [ string](#string) | none |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| task\_data | [ AgentTaskData](#agenttaskdata) | none |
### IngestTaskResultsResponse
(synq.ingest.dwh.v1.IngestTaskResultsResponse)
### LineageScope
(synq.ingest.dwh.v1.LineageScope)
LineageScope declares the set of downstream objects a REPLACE\_SCOPE batch is
authoritative for — the boundary inside which omitted edges are expired. The
scope is always additionally bounded by the request's connection\_id. Ignored
when the mode is MERGE.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) scope.whole\_connection | [ WholeConnectionScope](#wholeconnectionscope) | Authoritative for the whole connection: every downstream object previously ingested under this request's connection\_id. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) scope.databases | [ DatabasesScope](#databasesscope) | Authoritative only for the listed databases. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) scope.schemas | [ SchemasScope](#schemasscope) | Authoritative only for the listed schemas. |
### SchemasScope
(synq.ingest.dwh.v1.SchemasScope)
SchemasScope makes the batch authoritative for the listed schemas only.
| Field | Type | Description |
| ------- | -------------------------- | -------------------------------------------------------------- |
| schemas | [repeated string](#string) | Each entry is "database.schema" or "instance.database.schema". |
### WholeConnectionScope
(synq.ingest.dwh.v1.WholeConnectionScope)
WholeConnectionScope makes the batch authoritative for the entire connection.
### IngestDatahubAspectsRequest
(synq.ingest.airflow\.v1.IngestDatahubAspectsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| aspects | [repeated Struct](#struct) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_action.action | [optional string](#string) | none |
### IngestDatahubAspectsResponse
(synq.ingest.airflow\.v1.IngestDatahubAspectsResponse)
### IngestLogRequest
(synq.ingest.airflow\.v1.IngestLogRequest)
| Field | Type | Description |
| --------- | ------------------------ | ----------- |
| dag\_id | [ string](#string) | none |
| task\_id | [ string](#string) | none |
| run\_id | [ string](#string) | none |
| attempt | [ int32](#int32) | none |
| log | [ string](#string) | none |
| log\_time | [ Timestamp](#timestamp) | none |
### IngestLogResponse
(synq.ingest.airflow\.v1.IngestLogResponse)
### IngestRequest
(synq.ingest.openlineage.v1.IngestRequest)
| Field | Type | Description |
| ------- | ------------------ | ----------- |
| payload | [ Struct](#struct) | none |
### IngestResponse
(synq.ingest.openlineage.v1.IngestResponse)
### DbtArtifact
(synq.ingest.dbt.v1.DbtArtifact)
[https://docs.getdbt.com/reference/artifacts/dbt-artifacts](https://docs.getdbt.com/reference/artifacts/dbt-artifacts)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ---------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) artifact.manifest\_json | [ bytes](#bytes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) artifact.run\_results\_json | [ bytes](#bytes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) artifact.catalog\_json | [ bytes](#bytes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) artifact.sources\_json | [ bytes](#bytes) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) artifact.semantic\_manifest\_json | [ bytes](#bytes) | none |
### IngestInvocationRequest
(synq.ingest.dbt.v1.IngestInvocationRequest)
| Field | Type | Description |
| --------------------- | ------------------------------------------------- | ------------------------------------------------ |
| args | [repeated string](#string) | Arguments passed to the dbt executable |
| exit\_code | [ int32](#int32) | Exit code of the dbt command |
| std\_out | [ bytes](#bytes) | Standard output log of the dbt command |
| std\_err | [ bytes](#bytes) | Standard error log of the dbt command |
| environment\_vars | [map EnvironmentVarsEntry](#environmentvarsentry) | Environment variables collected during execution |
| artifacts | [repeated DbtArtifact](#dbtartifact) | Artifacts generated by the dbt command |
| uploader\_version | [ string](#string) | Version of the uploader tool |
| uploader\_build\_time | [ string](#string) | Build time of the uploader tool |
| git\_context | [ GitContext](#gitcontext) | Git context of the project |
### IngestInvocationRequest.EnvironmentVarsEntry
(synq.ingest.dbt.v1.IngestInvocationRequest.EnvironmentVarsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### IngestInvocationResponse
(synq.ingest.dbt.v1.IngestInvocationResponse)
### IngestExecutionRequest
(synq.ingest.sqlmesh.v1.IngestExecutionRequest)
| Field | Type | Description |
| --------------------- | ------------------------------------------------- | ------------------------------------------------ |
| command | [repeated string](#string) | Command passed to the sqlmesh tool |
| exit\_code | [ int32](#int32) | Exit code of the sqlmesh command |
| std\_out | [ bytes](#bytes) | Standard output log of the SqlMesh command |
| std\_err | [ bytes](#bytes) | Standard error log of the SqlMesh command |
| environment\_vars | [map EnvironmentVarsEntry](#environmentvarsentry) | Environment variables collected during execution |
| uploader\_version | [ string](#string) | Version of the uploader tool |
| uploader\_build\_time | [ string](#string) | Build time of the uploader tool |
| started\_at | [ Timestamp](#timestamp) | Time at which the execution started |
| finished\_at | [ Timestamp](#timestamp) | Time at which the execution finished |
| git\_context | [ GitContext](#gitcontext) | Git context of the project |
### IngestExecutionRequest.EnvironmentVarsEntry
(synq.ingest.sqlmesh.v1.IngestExecutionRequest.EnvironmentVarsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### IngestExecutionResponse
(synq.ingest.sqlmesh.v1.IngestExecutionResponse)
### IngestMetadataRequest
(synq.ingest.sqlmesh.v1.IngestMetadataRequest)
| Field | Type | Description |
| --------------------- | ------------------------------------------- | ------------------------------------------------------ |
| api\_meta | [ bytes](#bytes) | Data from /api/meta |
| models | [ bytes](#bytes) | Data from /api/models |
| model\_details | [map ModelDetailsEntry](#modeldetailsentry) | Data from /api/models/\{model\_id} |
| model\_lineage | [map ModelLineageEntry](#modellineageentry) | Data from /api/lineage/\{model\_id} |
| files | [ bytes](#bytes) | Data from /api/files |
| file\_content | [map FileContentEntry](#filecontententry) | Data from /api/file/\{file\_path} |
| environments | [ bytes](#bytes) | Data from /api/environments |
| uploader\_version | [ string](#string) | Version of the uploader tool |
| uploader\_build\_time | [ string](#string) | Build time of the uploader tool |
| state\_at | [ Timestamp](#timestamp) | Time at which state was collected |
| git\_context | [ GitContext](#gitcontext) | Git context of the project |
| errors | [repeated Error](#error) | Optional errors indicating why some data wasn't loaded |
### IngestMetadataRequest.Error
(synq.ingest.sqlmesh.v1.IngestMetadataRequest.Error)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_path.path | [optional string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_code.code | [optional int64](#int64) | none |
| message | [ string](#string) | none |
### IngestMetadataRequest.FileContentEntry
(synq.ingest.sqlmesh.v1.IngestMetadataRequest.FileContentEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ bytes](#bytes) | none |
### IngestMetadataRequest.ModelDetailsEntry
(synq.ingest.sqlmesh.v1.IngestMetadataRequest.ModelDetailsEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ bytes](#bytes) | none |
### IngestMetadataRequest.ModelLineageEntry
(synq.ingest.sqlmesh.v1.IngestMetadataRequest.ModelLineageEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ bytes](#bytes) | none |
### IngestMetadataResponse
(synq.ingest.sqlmesh.v1.IngestMetadataResponse)
### GitContext
(synq.ingest.git.v1.GitContext)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| clone\_url | [ string](#string) | none |
| branch | [ string](#string) | none |
| commit\_sha | [ string](#string) | none |
### CronSchedule
(synq.schedule.v1.CronSchedule)
CronSchedule uses standard cron expression syntax.
| Field | Type | Description |
| ---------- | ------------------ | -------------------------------------------------- |
| expression | [ string](#string) | Standard cron expression (e.g. "0 \*/6 \* \* \*"). |
### ICalSchedule
(synq.schedule.v1.ICalSchedule)
ICalSchedule uses RFC 5545 RRULE recurrence rules.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| recurrence\_rule | [ string](#string) | RFC 5545 RRULE recurrence rule (e.g. "FREQ=MONTHLY;BYDAY=TH;BYSETPOS=-1"). DTSTART should be set via the dtstart field below rather than inline in the rule. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dtstart.dtstart | [optional Timestamp](#timestamp) | Anchor time for the recurrence rule. Wall-clock time interpreted in the schedule's timezone. Defines when the schedule starts and aligns occurrences. If not set and no DTSTART is present in the recurrence\_rule, defaults to now(). |
### Schedule
(synq.schedule.v1.Schedule)
Schedule defines a recurring schedule with timezone context.
| Field | Type | Description |
| --------------------------------------------------------------------------------------- | ------------------------------ | --------------------------------------------------------- |
| timezone | [ string](#string) | IANA timezone, e.g. "Europe/Warsaw", "America/New\_York". |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.cron | [ CronSchedule](#cronschedule) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.ical | [ ICalSchedule](#icalschedule) | none |
### FixedQuantumGrid
(synq.schedule.v1.FixedQuantumGrid)
FixedQuantumGrid snaps onto a fixed-size grid anchored at the Unix epoch
(1970-01-01T00:00:00Z): \[epoch, epoch+quantum, epoch+2\*quantum, ...].
| Field | Type | Description |
| ------- | ---------------------- | -------------------------------------- |
| quantum | [ Duration](#duration) | Spacing between grid points, e.g. 10m. |
### IntegrationAnchorGrid
(synq.schedule.v1.IntegrationAnchorGrid)
IntegrationAnchorGrid snaps onto the shared, stable grid an integration's
periodic warehouse scrape already fires on. Aligning to it lets a run reuse
the same warehouse wake as the scrape.
The integration is resolved in the caller's own workspace (taken from the
authenticated identity, never from the request), and the caller must be
authorized to read it — a token without integration read access is rejected.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| integration\_id | [ string](#string) | The integration whose scrape grid to align to. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_period.period | [optional Duration](#duration) | Spacing between grid points. When unset, the integration's configured scrape cadence is used — this is what actually resumes the warehouse once per tick. Set it only to override for unusual cases. |
### PreviewScheduleParams
(synq.schedule.v1.PreviewScheduleParams)
Parameters for evaluating a single schedule.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| schedule | [ Schedule](#schedule) | The schedule to evaluate. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_after.after | [optional Timestamp](#timestamp) | Starting point for computing occurrences. Defaults to now if not set. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_limit.limit | [optional int32](#int32) | Number of occurrences to return. Defaults to 7, maximum 100. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_snap.snap | [optional ScheduleSnap](#schedulesnap) | Optional. When set, each computed occurrence is mapped to the nearest matching grid point before being returned, so the job co-fires with existing activity (e.g. a warehouse that is already awake) instead of triggering its own resume. When unset, occurrences are returned exactly as the schedule expression produces them. |
### PreviewScheduleResult
(synq.schedule.v1.PreviewScheduleResult)
Result for a single schedule evaluation.
| Field | Type | Description |
| ----------- | -------------------------------- | ------------------------------------------------------------------------------------------------- |
| occurrences | [repeated Timestamp](#timestamp) | The next occurrences in chronological order. Empty if error is set. |
| error | [ string](#string) | Error message if the schedule expression is invalid or cannot be evaluated. Empty on success. |
| snap\_info | [repeated SnapInfo](#snapinfo) | Per-occurrence snap outcome, index-aligned with `occurrences`. Empty when snap was not requested. |
### PreviewSchedulesRequest
(synq.schedule.v1.PreviewSchedulesRequest)
| Field | Type | Description |
| --------- | -------------------------------------------------------- | --------------------------------------------------------------- |
| schedules | [repeated PreviewScheduleParams](#previewscheduleparams) | Schedules to evaluate. An empty list returns an empty response. |
### PreviewSchedulesResponse
(synq.schedule.v1.PreviewSchedulesResponse)
| Field | Type | Description |
| ------- | -------------------------------------------------------- | ------------------------------------------------ |
| results | [repeated PreviewScheduleResult](#previewscheduleresult) | Results matching the request schedules by index. |
### ScheduleSnap
(synq.schedule.v1.ScheduleSnap)
ScheduleSnap maps each schedule occurrence onto a grid so runs line up with
activity that is already happening, avoiding a separate warehouse resume.
Pick one grid source and, optionally, how far an occurrence may move.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) grid.integration\_anchor | [ IntegrationAnchorGrid](#integrationanchorgrid) | Snap onto the shared warehouse-scrape grid for an integration, so the run co-fires with the periodic scrape and reuses the same warehouse wake instead of paying for another resume. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) grid.fixed\_quantum | [ FixedQuantumGrid](#fixedquantumgrid) | Snap onto a fixed-quantum grid (e.g. every 10 minutes from the Unix epoch, UTC). Useful for tidy round-minute fire times without coupling to integration activity. |
| tolerance | [ Duration](#duration) | How far an occurrence may be moved to land on the grid. If the nearest eligible grid point is farther away than this, the occurrence is returned unmoved and flagged as not snapped (see SnapInfo). Unset or zero means an occurrence snaps only when it already lands exactly on a grid point. |
| direction | [ SnapDirection](#snapdirection) | Direction an occurrence is allowed to move. Unspecified behaves as NEAREST. |
### SnapInfo
(synq.schedule.v1.SnapInfo)
SnapInfo records, for one occurrence, whether snapping moved it onto the grid.
| Field | Type | Description |
| -------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| original | [ Timestamp](#timestamp) | The occurrence as the schedule expression produced it, before snapping. |
| snapped | [ bool](#bool) | True if the occurrence was moved onto the grid. False if the nearest grid point was farther than the tolerance (or none was available), in which case the aligned `occurrences` entry equals `original`. |
### BatchGetRequest
(synq.savedviews.v1.BatchGetRequest)
| Field | Type | Description |
| ----- | -------------------------- | ----------------------------- |
| ids | [repeated string](#string) | Ids to fetch (1–200, unique). |
### BatchGetResponse
(synq.savedviews.v1.BatchGetResponse)
| Field | Type | Description |
| ----- | ----------------------------- | ----------------------------------------------------------------------------- |
| views | [map ViewsEntry](#viewsentry) | Views keyed by id. Ids the caller cannot see or that do not exist are absent. |
### BatchGetResponse.ViewsEntry
(synq.savedviews.v1.BatchGetResponse.ViewsEntry)
| Field | Type | Description |
| ----- | ------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ SavedView](#savedview) | none |
### DeleteRequest
(synq.savedviews.v1.DeleteRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------- |
| id | [ string](#string) | Id of the view to delete. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. |
### DeleteResponse
(synq.savedviews.v1.DeleteResponse)
### ListRequest
(synq.savedviews.v1.ListRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| scopes | [repeated SavedViewRelationship](#savedviewrelationship) | Relationship buckets to include. Empty returns every view the caller can see. For example \[SAVED\_VIEW\_RELATIONSHIP\_MINE] returns only the caller's own views. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_context.context | [optional SavedViewContext](#savedviewcontext) | Restrict to a single surface. Omit to return views for all contexts. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_only\_pinned.only\_pinned | [optional bool](#bool) | Restrict to views the caller has pinned. |
| pagination | [ Pagination](#pagination) | Pagination. |
### ListResponse
(synq.savedviews.v1.ListResponse)
| Field | Type | Description |
| ---------- | -------------------------------- | ------------------------------------ |
| views | [repeated SavedView](#savedview) | The matching views. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### SetPinRequest
(synq.savedviews.v1.SetPinRequest)
| Field | Type | Description |
| ------ | ------------------ | ------------------------------------------------- |
| id | [ string](#string) | Id of the view to pin/unpin for the calling user. |
| pinned | [ bool](#bool) | Desired pin state: true to pin, false to unpin. |
### SetPinResponse
(synq.savedviews.v1.SetPinResponse)
### UpsertRequest
(synq.savedviews.v1.UpsertRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Client-supplied UUID identifying the view. The same id updates the same view; a new id creates a new view. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Title. Required when creating; omit to keep the existing title on update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Description. Omit to keep the existing description. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_context.context | [optional SavedViewContext](#savedviewcontext) | Surface the view applies to. Omit to keep the existing context. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_selection.selection | [optional SavedViewSelection](#savedviewselection) | The selection. Required when creating; omit to keep the existing selection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config.config | [optional SavedViewConfig](#savedviewconfig) | Display configuration. Omit to keep the existing config. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_visibility.visibility | [optional SavedViewVisibility](#savedviewvisibility) | Sharing state. Omit to keep the existing visibility. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_grants.grants | [optional GrantList](#grantlist) | Access grants. When present, replaces the entire grant set (an empty list clears all grants); when omitted, grants are left unchanged. Changing grants requires manage/admin permission on the view. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the update fails with a conflict if the view was modified since this etag was read. |
### UpsertResponse
(synq.savedviews.v1.UpsertResponse)
| Field | Type | Description |
| ----- | ------------------------ | --------------------------------- |
| view | [ SavedView](#savedview) | The stored view after the upsert. |
### Grant
(synq.savedviews.v1.Grant)
A single access grant on a saved view.
| Field | Type | Description |
| ----------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| grantee\_identity | [ string](#string) | Identity of the grantee. Currently a user email (`user@example.com`); the view becomes visible to that user once they exist in the workspace, so a view can be shared with someone before their first login. |
| role | [ GrantRole](#grantrole) | What the grantee may do. Defaults to VIEW. |
### GrantList
(synq.savedviews.v1.GrantList)
A wrapper giving the grant set explicit presence on write, so a partial
update can distinguish "replace the grants" (present, possibly empty) from
"leave grants unchanged" (absent).
| Field | Type | Description |
| ------ | ------------------------ | ----------- |
| grants | [repeated Grant](#grant) | none |
### SavedView
(synq.savedviews.v1.SavedView)
A saved view: a named, reusable selection over entities (or another context)
with display configuration, sharing and per-user pinning.
| Field | Type | Description |
| ------------ | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Client-supplied UUID identifying the view. |
| context | [ SavedViewContext](#savedviewcontext) | The surface this view applies to. |
| title | [ string](#string) | Human-readable title. |
| description | [ string](#string) | Optional longer description. |
| selection | [ SavedViewSelection](#savedviewselection) | The selection captured by the view. |
| config | [ SavedViewConfig](#savedviewconfig) | Display configuration. |
| visibility | [ SavedViewVisibility](#savedviewvisibility) | Sharing state. |
| grants | [repeated Grant](#grant) | Access grants (populated for GRANTED views). |
| owner | [ Actor](#actor) | Who created the view. Output-only. |
| updated\_by | [ Actor](#actor) | Who last edited the view. Output-only. |
| relationship | [ SavedViewRelationship](#savedviewrelationship) | How this view relates to the calling user. Output-only. |
| permissions | [ SavedViewPermissions](#savedviewpermissions) | What the calling user may do with this view. Output-only. |
| pinned | [ bool](#bool) | Whether the calling user has pinned this view to their main screen. Output-only; change with SetPin. |
| etag | [ string](#string) | Entity tag for optimistic concurrency: pass back on Upsert/Delete to guard against overwriting a concurrent change. Form: `W/"-"`. |
| created\_at | [ Timestamp](#timestamp) | When the view was created. Output-only. |
| updated\_at | [ Timestamp](#timestamp) | When the view was last updated. Output-only. |
### SavedViewConfig
(synq.savedviews.v1.SavedViewConfig)
How a saved view is displayed once opened. This message is intentionally
permissive and forward-compatible: new presentation options are added as new
fields, never as a breaking change, so older clients keep working.
| Field | Type | Description |
| ------------ | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| layout | [ Layout](#layout) | How results are laid out (list, cards, table). Unspecified lets the client pick its default for the context. |
| card\_fields | [repeated string](#string) | Which fields to surface on each result (e.g. "last\_run", "owner", "status", "platform"). Interpreted by the client; unknown field names are ignored. |
### SavedViewPermissions
(synq.savedviews.v1.SavedViewPermissions)
What the calling user is allowed to do with a saved view. Output-only:
computed per request from ownership, the caller's grant (if any) and their
workspace permissions. Viewing and pinning are always allowed for any view
the caller can see, so they are not represented here.
| Field | Type | Description |
| ------------------- | -------------- | --------------------------------------------------------------------------- |
| can\_edit | [ bool](#bool) | The caller can update the view's definition, title, description and config. |
| can\_delete | [ bool](#bool) | The caller can delete the view. |
| can\_manage\_grants | [ bool](#bool) | The caller can change the view's sharing/visibility and grants. |
### SavedViewQuery
(synq.savedviews.v1.SavedViewQuery)
The query behind a saved view, expressed for the public API.
On write, provide the query in ONE of two forms:
* `public_query` — a structured query (the same shape used elsewhere for
asset selection), convenient to build from a filter UI; or
* `resolver_ql` — the SYNQ resolver query language, a compact text form
that additionally expresses severity/status and time-window filters
(e.g. `with_severity(statuses=["error"], since="24h")`).
When both are set, `resolver_ql` wins. The server compiles the query and
stores it canonically; the raw text is not preserved verbatim.
On read, the server returns `rendered_resolver_ql` (the stored query rendered
back to canonical resolver query language) and, best-effort, `public_query`
(the structured representation; parts with no structured equivalent are marked
unsupported). `resolver_ql` is not echoed back — read `rendered_resolver_ql`.
| Field | Type | Description |
| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| resolver\_ql | [ string](#string) | WRITE (option A). The query in resolver query language. Superset form — the only way to express severity/status and time-window filters. |
| rendered\_resolver\_ql | [ string](#string) | READ, output-only. The stored query rendered back to canonical resolver query language. Deterministically derived; does not preserve original hand-typed formatting or comments. |
| public\_query | [ Query](#query) | WRITE (option B) and READ. On write, the structured query to store (used when `resolver_ql` is empty). On read, a structured representation of the stored query — lossy: parts with no structured equivalent are represented as unsupported, so prefer `rendered_resolver_ql` for full fidelity. |
### SavedViewSelection
(synq.savedviews.v1.SavedViewSelection)
The selection that a saved view captures. Modelled as a oneof so future
contexts (e.g. an issues filter) can add their own selection shape without
reshaping the view.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.entity\_query | [ SavedViewQuery](#savedviewquery) | Entity-backed selection (catalog/assets and checks contexts). |
### DatacheckResult
(synq.datachecks.v1.DatacheckResult)
Result from a single datacheck execution.
| Field | Type | Description |
| ----------------- | ------------------------------------ | ----------- |
| status | [ DatacheckStatus](#datacheckstatus) | none |
| message | [ string](#string) | none |
| sql\_test\_result | [ SqlTestResult](#sqltestresult) | none |
| monitor\_result | [ MonitorResult](#monitorresult) | none |
### MonitorPrediction
(synq.datachecks.v1.MonitorPrediction)
| Field | Type | Description |
| -------- | ------------------------------------ | ----------- |
| status | [ DatacheckStatus](#datacheckstatus) | none |
| message | [ string](#string) | none |
| value | [ double](#double) | none |
| expected | [ double](#double) | none |
| field | [ string](#string) | none |
| segment | [ string](#string) | none |
### MonitorResult
(synq.datachecks.v1.MonitorResult)
Result of a monitor execution.
| Field | Type | Description |
| ---------------- | ------------------------------------------------ | --------------------------------------------------------------------- |
| monitor\_id | [ string](#string) | The monitor ID that was executed. |
| monitor\_name | [ string](#string) | none |
| monitor\_path | [ string](#string) | none |
| metrics\_version | [ int32](#int32) | none |
| entity\_id | [ Identifier](#identifier) | The entity that was monitored. |
| execution\_id | [ string](#string) | Execution ID that can be used to retrieve detailed audit information. |
| executed\_at | [ Timestamp](#timestamp) | Timestamp when the monitor was executed. |
| predictions | [repeated MonitorPrediction](#monitorprediction) | Individual segment predictions. |
### SqlTestResult
(synq.datachecks.v1.SqlTestResult)
Result of a SQL test execution.
| Field | Type | Description |
| -------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| sql\_test\_id | [ string](#string) | The SQL test ID that was executed. |
| entity\_ids | [repeated Identifier](#identifier) | The entities that the test was executed on. |
| rows\_count | [ int32](#int32) | Number of rows returned by the test query. For a passing test, this should typically be 0 (no violations found). |
| execution\_id | [ string](#string) | Execution ID that can be used to retrieve detailed audit information. |
| executed\_at | [ Timestamp](#timestamp) | Timestamp when the test was executed. |
| error\_message | [ string](#string) | Optional error message if the execution failed. |
| result\_data | [ string](#string) | Optional result data or sample rows from the test execution. |
### TriggerDatachecksRequest
(synq.datachecks.v1.TriggerDatachecksRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------------------------------------------------- |
| entity\_ids | [repeated Identifier](#identifier) | List of entity identifiers to trigger datachecks for. |
### TriggerDatachecksResponse
(synq.datachecks.v1.TriggerDatachecksResponse)
| Field | Type | Description |
| ------- | -------------------------------------------- | -------------------------------------- |
| results | [repeated DatacheckResult](#datacheckresult) | Results from all datacheck executions. |
### AcceptedValuesTest
(synq.datachecks.sqltests.v1.AcceptedValuesTest)
| Field | Type | Description |
| ---------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the column to validate |
| accepted\_values | [repeated SqlValue](#sqlvalue) | List of allowed values for the column |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### BusinessQueryTest
(synq.datachecks.sqltests.v1.BusinessQueryTest)
| Field | Type | Description |
| ---------- | ------------------ | ------------------------------------------------------------ |
| sql\_query | [ string](#string) | Full SELECT statement. Result rows are reported as failures. |
Format: a single SELECT (CTEs allowed); no semicolon. May read any tables the integration has access to. The engine wraps it as `WITH raw_query AS () SELECT * FROM raw_query`.
Use this when the failure set requires GROUP BY, JOINs, window functions, or other shape that a per-row predicate (BusinessRuleTest) cannot express.
Example: SELECT customer\_id, SUM(amount) AS total FROM orders WHERE status = 'paid' GROUP BY customer\_id HAVING SUM(amount) \< 0
Template.identifier still anchors the test to a primary table for ownership, alerts, and UI grouping.
Note: this test does not expose a `select_columns` option. The author controls the SELECT shape directly in `sql_query`. |
### BusinessRuleTest
(synq.datachecks.sqltests.v1.BusinessRuleTest)
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
| sql\_expression | [ string](#string) | Boolean SQL predicate evaluated per row of the anchor table (Template.identifier); rows where the predicate is TRUE are reported as failures. |
Format: a single boolean expression — no SELECT, WITH, or semicolons. References columns on the anchor table. The engine executes it as `SELECT * FROM WHERE `.
Example: "total\_amount != subtotal + tax" reports rows where totals disagree. Use BusinessQueryTest for SELECT / GROUP BY / multi-table logic. |
\| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### CountDistinctTest
(synq.datachecks.sqltests.v1.CountDistinctTest)
Note: this test does not expose a `select_columns` option. The result is
an aggregate count, not a set of failure rows.
| Field | Type | Description |
| ------------- | -------------------------- | ---------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns to count distinct combinations |
### CountDuplicatesTest
(synq.datachecks.sqltests.v1.CountDuplicatesTest)
Note: this test does not expose a `select_columns` option. The result is
an aggregate count, not a set of failure rows.
| Field | Type | Description |
| ------------- | -------------------------- | --------------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns to check for duplicate combinations |
### EmptyTest
(synq.datachecks.sqltests.v1.EmptyTest)
| Field | Type | Description |
| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_names | [repeated string](#string) | List of column names to check for empty values |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### Evaluator
(synq.datachecks.sqltests.v1.Evaluator)
Evaluator is a named condition attached to a SqlTest that produces
an independent pass/fail signal. A single SqlTest may carry multiple
evaluators, each targeting a different concern (nullability, value
ranges, row counts, etc.).
| Field | Type | Description |
| --------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Stable identifier for the evaluator, unique within the parent SqlTest. Must contain only ASCII letters, digits, hyphens, or underscores. |
| name | [ string](#string) | Human friendly name. |
| sql\_expression | [ string](#string) | SQL expression evaluated against the test rows. The expression is a FAIL condition: a row is flagged when the expression evaluates to TRUE. NULL evaluates as pass (equivalent to FALSE). |
| severity | [ Severity](#severity) | Severity routed to alerting when this evaluator fails. Defaults to the parent SqlTest severity when left unspecified. |
### EvaluatorResult
(synq.datachecks.sqltests.v1.EvaluatorResult)
EvaluatorResult is the execution outcome of a single Evaluator within a SqlTest run.
Fields id/name/sql\_expression/severity are a snapshot of the evaluator definition
at execution time so historical results survive later edits to the test.
| Field | Type | Description |
| --------------- | ------------------------------------ | ---------------------------------------------------------------- |
| id | [ string](#string) | Evaluator id, matching Evaluator.id on the parent SqlTest. |
| name | [ string](#string) | Human-friendly evaluator name at time of execution. |
| sql\_expression | [ string](#string) | SQL expression that was evaluated. |
| severity | [ Severity](#severity) | Severity of this evaluator as configured at execution time. |
| fail\_count | [ int64](#int64) | Number of rows that failed this evaluator's condition. |
| status | [ ExecutionStatus](#executionstatus) | Execution outcome for this evaluator. |
| message | [ string](#string) | Human-readable result message (e.g. "OK" or "Got 3 failure(s)"). |
### FreshnessTest
(synq.datachecks.sqltests.v1.FreshnessTest)
| Field | Type | Description |
| ----------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| time\_partition\_column\_name | [ string](#string) | Name of the timestamp column used for freshness check |
| time\_window\_seconds | [ int64](#int64) | Time window for freshness check (in seconds) |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### InputTable
(synq.datachecks.sqltests.v1.InputTable)
InputTable is a table reference resolved from the SQL expression of a SqlTest.
| Field | Type | Description |
| ----------- | ------------------ | --------------------------------------------------------------------------------- |
| fqn | [ Fqn](#fqn) | Fully-qualified name of the referenced table. |
| table\_path | [ string](#string) | Synq-internal path for the table asset (e.g. "bq-prod::project::dataset::table"). |
### MaxValueTest
(synq.datachecks.sqltests.v1.MaxValueTest)
| Field | Type | Description |
| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| max\_value | [ SqlValue](#sqlvalue) | Maximum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, the maximum value is exclusive |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### MinMaxTest
(synq.datachecks.sqltests.v1.MinMaxTest)
| Field | Type | Description |
| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| min\_value | [ SqlValue](#sqlvalue) | Minimum allowed value (inclusive) |
| max\_value | [ SqlValue](#sqlvalue) | Maximum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, bounds are exclusive |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### MinValueTest
(synq.datachecks.sqltests.v1.MinValueTest)
| Field | Type | Description |
| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| min\_value | [ SqlValue](#sqlvalue) | Minimum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, the minimum value is exclusive |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### NotNullTest
(synq.datachecks.sqltests.v1.NotNullTest)
| Field | Type | Description |
| --------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_names | [repeated string](#string) | List of column names to check for NULL values |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### RejectedValuesTest
(synq.datachecks.sqltests.v1.RejectedValuesTest)
| Field | Type | Description |
| ---------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the column to validate |
| rejected\_values | [repeated SqlValue](#sqlvalue) | List of disallowed values for the column |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### RelationshipColumn
(synq.datachecks.sqltests.v1.RelationshipColumn)
| Field | Type | Description |
| --------- | ------------------ | ---------------------------------- |
| source | [ string](#string) | Column name in the source table |
| reference | [ string](#string) | Column name in the reference table |
### RelationshipReference
(synq.datachecks.sqltests.v1.RelationshipReference)
| Field | Type | Description |
| ------- | -------------------------------------------------- | ---------------------------------------------------------- |
| entity | [ Identifier](#identifier) | The reference entity (table to check foreign keys against) |
| columns | [repeated RelationshipColumn](#relationshipcolumn) | Column mappings between source and reference tables |
### RelationshipsTest
(synq.datachecks.sqltests.v1.RelationshipsTest)
| Field | Type | Description |
| ----------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| references | [repeated RelationshipReference](#relationshipreference) | List of reference table relationships to check |
| ignore\_nulls | [ bool](#bool) | If true, source rows where all join columns are NULL are excluded from results |
| time\_partition\_column | [ string](#string) | Column name used to filter source rows by time (e.g., "created\_at") |
| time\_window\_seconds | [ int64](#int64) | Time window in seconds - only check source rows within this window |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### RelativeTimeTest
(synq.datachecks.sqltests.v1.RelativeTimeTest)
| Field | Type | Description |
| ---------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_name | [ string](#string) | Name of the first time column to compare |
| relative\_column\_name | [ string](#string) | Name of the second time column that should be later than the first |
| select\_columns | [repeated string](#string) | Optional list of columns to include in the SELECT clause of the generated SQL. When empty (default), SELECT \* is used — all columns are returned. |
### SqlTest
(synq.datachecks.sqltests.v1.SqlTest)
The SqlTest is a SQL test that is executed on a Coalesce Quality entity.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| platform | [ DataPlatformIdentifier](#dataplatformidentifier) | Identifier for the data platform which the SqlTest would be executed on. |
| id | [ string](#string) | Unique resource identifier for the SqlTest. This is externally maintained and can be used to fetch/update/delete this test. |
| name | [ string](#string) | Human friendly name. |
| description | [ string](#string) | Description of purpose and motivation. |
| severity | [ Severity](#severity) | none |
| sql\_expression | [ string](#string) | A valid SQL expression which is the test. |
| recurrence\_rule | [ string](#string) | [Recurrence rule](https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html) for the execution schedule of the SqlTest. |
| annotations | [repeated Annotation](#annotation) | Annotations for the given SqlTest.These help filter the SqlTests for later operations like listing by API, selection in UI, analytics, etc. |
| save\_failures | [ bool](#bool) | Boolean flag to to toggle saving of failure runs. |
| template | [ Template](#template) | Template for the SqlTest. required when sql\_expression is not provided |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | Config ID for the SqlTest. |
| source | [ Source](#source) | none |
| timezone | [ string](#string) | IANA timezone name (e.g., "Europe/Prague", "America/New\_York"). Used to interpret the recurrence\_rule in the given timezone. If empty, defaults to UTC. |
| evaluators | [repeated Evaluator](#evaluator) | Named evaluators attached to this test. Each evaluator has its own SQL boolean expression and severity. When present, the test outcome is determined by the worst severity among failing evaluators; tests with no evaluators fall back to the single-expression pass/fail rule. |
| input\_tables | [repeated InputTable](#inputtable) | Tables referenced by the SQL expression, resolved at upsert time. |
### SqlTestAudit
(synq.datachecks.sqltests.v1.SqlTestAudit)
| Field | Type | Description |
| --------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| execution\_id | [ string](#string) | none |
| rows\_count | [ int32](#int32) | none |
| result | [ string](#string) | JSON array of failing-row objects. Each object contains the original SELECT-list columns plus an `_failed_evaluators` array of evaluator IDs that flagged that row (only present when the SqlTest has evaluators). |
| created\_at | [ Timestamp](#timestamp) | none |
| evaluators | [repeated EvaluatorResult](#evaluatorresult) | Per-evaluator metadata for the run that produced this audit. Empty when the SqlTest has no evaluators. Use to resolve the evaluator IDs found in each row's `_failed_evaluators` array to their names and severities. |
| sql\_test\_path | [ string](#string) | Path of the SqlTest that produced this audit. |
| status | [ ExecutionStatus](#executionstatus) | Overall run status of the SqlTest execution that produced this audit. |
| status\_message | [ string](#string) | Short human-readable status message describing the overall run outcome. |
### SqlValue
(synq.datachecks.sqltests.v1.SqlValue)
Represents a value that can be either a literal (to be quoted in SQL) or a SQL expression (to be used as plain text).
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------------------------------------------------------ |
| string\_literal | [ string](#string) | Literal value that should be quoted in SQL (e.g., '2025-05-12', 'active') |
| expression | [ string](#string) | SQL expression, numbers to be used as plain text (e.g., NOW(), COUNT(\*), true, 1.1) |
### Template
(synq.datachecks.sqltests.v1.Template)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
| identifier | [ Identifier](#identifier) | Read-only path of matched entity. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.not\_null\_test | [ NotNullTest](#notnulltest) | Checks if specified columns contain no NULL values (e.g., user\_id should never be null) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.empty\_test | [ EmptyTest](#emptytest) | Checks if specified columns contain empty values (e.g., description field can be empty) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.accepted\_values\_test | [ AcceptedValuesTest](#acceptedvaluestest) | Validates that column values are within an allowed set (e.g., status in \['active', 'inactive', 'pending']) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.rejected\_values\_test | [ RejectedValuesTest](#rejectedvaluestest) | Validates that column values are not in a forbidden set (e.g., country not in \['UNKNOWN', 'TEST']) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.unique\_test | [ UniqueTest](#uniquetest) | Ensures specified columns form a unique key combination (e.g., order\_id is unique) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.freshness\_test | [ FreshnessTest](#freshnesstest) | Checks if data is up-to-date based on a time column (e.g., latest event\_timestamp within 24h) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.min\_max\_test | [ MinMaxTest](#minmaxtest) | Validates numeric values are within specified range (e.g., price between 0 and 1000) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.relative\_time\_test | [ RelativeTimeTest](#relativetimetest) | Compares time-based columns for logical order (e.g., start\_date before end\_date) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.business\_rule\_test | [ BusinessRuleTest](#businessruletest) | Per-row boolean predicate; rows matching are reported as failures (e.g., total\_amount != subtotal + tax) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.min\_value\_test | [ MinValueTest](#minvaluetest) | Validates numeric values are greater than or equal to a minimum value (e.g., price >= 0) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.max\_value\_test | [ MaxValueTest](#maxvaluetest) | Validates numeric values are less than or equal to a maximum value (e.g., price \<= 1000) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.relationships\_test | [ RelationshipsTest](#relationshipstest) | Validates referential integrity between source and reference tables |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.business\_query\_test | [ BusinessQueryTest](#businessquerytest) | Full SELECT whose result rows are reported as failures; supports GROUP BY, JOINs, etc. |
### UniqueTest
(synq.datachecks.sqltests.v1.UniqueTest)
Note: this test does not expose a `select_columns` option. The SELECT shape
is fixed by the aggregation (DISTINCT columns + duplicate count); failure
rows are the duplicate keys, not raw table rows.
| Field | Type | Description |
| ----------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns that should form a unique combination |
| time\_partition\_column\_name | [ string](#string) | If provided, the check will be applied to the time window of the time partition column If not provided, the check will be applied to all rows |
| time\_window\_seconds | [ int64](#int64) | Time window for uniqueness check (in seconds) |
### BatchDeleteSqlTestsRequest
(synq.datachecks.sqltests.v1.BatchDeleteSqlTestsRequest)
| Field | Type | Description |
| ----- | -------------------------- | ------------------------------ |
| ids | [repeated string](#string) | IDs of the SqlTests to delete. |
### BatchDeleteSqlTestsResponse
(synq.datachecks.sqltests.v1.BatchDeleteSqlTestsResponse)
### BatchGetSqlTestsRequest
(synq.datachecks.sqltests.v1.BatchGetSqlTestsRequest)
| Field | Type | Description |
| ----- | -------------------------- | ----------------------------- |
| ids | [repeated string](#string) | IDs of the SqlTests to fetch. |
### BatchGetSqlTestsResponse
(synq.datachecks.sqltests.v1.BatchGetSqlTestsResponse)
| Field | Type | Description |
| ---------- | ----------------------------------- | ----------- |
| sql\_tests | [map SqlTestsEntry](#sqltestsentry) | none |
### BatchGetSqlTestsResponse.SqlTestsEntry
(synq.datachecks.sqltests.v1.BatchGetSqlTestsResponse.SqlTestsEntry)
| Field | Type | Description |
| ----- | -------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ SqlTest](#sqltest) | none |
### BatchUpsertSqlTestsRequest
(synq.datachecks.sqltests.v1.BatchUpsertSqlTestsRequest)
| Field | Type | Description |
| ------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------- |
| sql\_tests | [repeated SqlTest](#sqltest) | List of SqlTests to upsert. The upsert is performed based on the unique path provided for each SqlTest. |
| sql\_test\_ids\_to\_reset | [repeated string](#string) | List of SqlTest IDs to reset. Some updates might require resetting the SqlTest to a fresh state. |
### BatchUpsertSqlTestsResponse
(synq.datachecks.sqltests.v1.BatchUpsertSqlTestsResponse)
| Field | Type | Description |
| ------------ | ------------------------------------ | ---------------------------------------------------------------------------- |
| created\_ids | [repeated string](#string) | IDs for which SqlTests were created without error. |
| updated\_ids | [repeated string](#string) | IDs for which SqlTests were updated without error. |
| errors | [repeated UpsertError](#upserterror) | Errors raised while upsert. This list will be empty if there were no errors. |
### BatchUpsertSqlTestsResponse.UpsertError
(synq.datachecks.sqltests.v1.BatchUpsertSqlTestsResponse.UpsertError)
Details of errors encountered during the upsert operation.
| Field | Type | Description |
| ------ | ------------------ | ----------- |
| id | [ string](#string) | none |
| reason | [ string](#string) | none |
### ConfigsFilter
(synq.datachecks.sqltests.v1.ConfigsFilter)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
### GetSqlTestAuditRequest
(synq.datachecks.sqltests.v1.GetSqlTestAuditRequest)
### GetSqlTestAuditResponse
(synq.datachecks.sqltests.v1.GetSqlTestAuditResponse)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| audit | [ SqlTestAudit](#sqltestaudit) | none |
### ListSqlTestsRequest
(synq.datachecks.sqltests.v1.ListSqlTestsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| annotations | [repeated Annotation](#annotation) | Optional annotations to fetch SqlTests for. |
| integration\_ids | [repeated string](#string) | none |
| ids | [repeated string](#string) | none |
| config\_ids | [repeated string](#string) | none |
| configs\_filter | [ ConfigsFilter](#configsfilter) | Filter SqlTests by config IDs. Pass `ConfigsFilter{ids: ["config1", "config2"]}` to filter by specific configs. If nil, no config\_id filtering is applied. If empty, the one with NULL config\_id will be excluded. |
| sources | [repeated Source](#source) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | none |
### ListSqlTestsResponse
(synq.datachecks.sqltests.v1.ListSqlTestsResponse)
| Field | Type | Description |
| ---------- | ---------------------------- | ------------------ |
| sql\_tests | [repeated SqlTest](#sqltest) | none |
| page\_info | [ PageInfo](#pageinfo) | Paging information |
### BatchAcceptTestSuggestionsRequest
(synq.datachecks.testsuggestions.v1.BatchAcceptTestSuggestionsRequest)
| Field | Type | Description |
| ---------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| ids | [repeated string](#string) | none |
| recurrence\_rule | [ string](#string) | [Recurrence rule](https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html) for the execution schedule of the SqlTest. |
| annotations | [repeated Annotation](#annotation) | Annotations for the given test.These help filter the tests for later operations like listing by API, selection in UI, analytics, etc. |
| save\_failures | [ bool](#bool) | Boolean flag to to toggle saving of failure runs. |
### BatchAcceptTestSuggestionsResponse
(synq.datachecks.testsuggestions.v1.BatchAcceptTestSuggestionsResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------------------------- |
| identifiers | [repeated Identifier](#identifier) | Identifiers of created tests. |
### BatchCreateTestSuggestionsRequest
(synq.datachecks.testsuggestions.v1.BatchCreateTestSuggestionsRequest)
| Field | Type | Description |
| ----------- | ------------------------------------------ | ----------- |
| suggestions | [repeated TestSuggestion](#testsuggestion) | none |
### BatchCreateTestSuggestionsResponse
(synq.datachecks.testsuggestions.v1.BatchCreateTestSuggestionsResponse)
### BatchGetTestSuggestionsForEntitiesRequest
(synq.datachecks.testsuggestions.v1.BatchGetTestSuggestionsForEntitiesRequest)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| identifiers | [repeated Identifier](#identifier) | none |
### BatchGetTestSuggestionsForEntitiesResponse
(synq.datachecks.testsuggestions.v1.BatchGetTestSuggestionsForEntitiesResponse)
| Field | Type | Description |
| ----------- | ------------------------------------------ | ----------- |
| suggestions | [repeated TestSuggestion](#testsuggestion) | none |
### BatchRejectTestSuggestionsRequest
(synq.datachecks.testsuggestions.v1.BatchRejectTestSuggestionsRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reason.reason | [optional string](#string) | none |
### BatchRejectTestSuggestionsResponse
(synq.datachecks.testsuggestions.v1.BatchRejectTestSuggestionsResponse)
### AcceptedValuesTest
(synq.datachecks.testsuggestions.v1.AcceptedValuesTest)
| Field | Type | Description |
| ---------------- | -------------------------- | ------------------------------------- |
| column\_name | [ string](#string) | Name of the column to validate |
| accepted\_values | [repeated string](#string) | List of allowed values for the column |
### BusinessRuleTest
(synq.datachecks.testsuggestions.v1.BusinessRuleTest)
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------------------------------- |
| sql\_expression | [ string](#string) | SQL expression that should evaluate to TRUE for valid records |
### CountDistinctTest
(synq.datachecks.testsuggestions.v1.CountDistinctTest)
| Field | Type | Description |
| ------------- | -------------------------- | ---------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns to count distinct combinations |
### CountDuplicatesTest
(synq.datachecks.testsuggestions.v1.CountDuplicatesTest)
| Field | Type | Description |
| ------------- | -------------------------- | --------------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns to check for duplicate combinations |
### EmptyTest
(synq.datachecks.testsuggestions.v1.EmptyTest)
| Field | Type | Description |
| ------------- | -------------------------- | ---------------------------------------------- |
| column\_names | [repeated string](#string) | List of column names to check for empty values |
### FreshnessTest
(synq.datachecks.testsuggestions.v1.FreshnessTest)
| Field | Type | Description |
| ----------------------------- | ------------------ | ----------------------------------------------------- |
| time\_partition\_column\_name | [ string](#string) | Name of the timestamp column used for freshness check |
| time\_window\_seconds | [ int64](#int64) | Time window for freshness check (in seconds) |
### MaxValueTest
(synq.datachecks.testsuggestions.v1.MaxValueTest)
| Field | Type | Description |
| ------------ | ------------------ | --------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| max\_value | [ double](#double) | Maximum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, the maximum value is exclusive |
### MinMaxTest
(synq.datachecks.testsuggestions.v1.MinMaxTest)
| Field | Type | Description |
| ------------ | ------------------ | -------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| min\_value | [ double](#double) | Minimum allowed value (inclusive) |
| max\_value | [ double](#double) | Maximum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, bounds are exclusive |
### MinValueTest
(synq.datachecks.testsuggestions.v1.MinValueTest)
| Field | Type | Description |
| ------------ | ------------------ | --------------------------------------- |
| column\_name | [ string](#string) | Name of the numeric column to validate |
| min\_value | [ double](#double) | Minimum allowed value (inclusive) |
| strictly | [ bool](#bool) | If true, the minimum value is exclusive |
### NotNullTest
(synq.datachecks.testsuggestions.v1.NotNullTest)
| Field | Type | Description |
| ------------- | -------------------------- | --------------------------------------------- |
| column\_names | [repeated string](#string) | List of column names to check for NULL values |
### RejectedValuesTest
(synq.datachecks.testsuggestions.v1.RejectedValuesTest)
| Field | Type | Description |
| ---------------- | -------------------------- | ---------------------------------------- |
| column\_name | [ string](#string) | Name of the column to validate |
| rejected\_values | [repeated string](#string) | List of disallowed values for the column |
### RelativeTimeTest
(synq.datachecks.testsuggestions.v1.RelativeTimeTest)
| Field | Type | Description |
| ---------------------- | ------------------ | ------------------------------------------------------------------ |
| column\_name | [ string](#string) | Name of the first time column to compare |
| relative\_column\_name | [ string](#string) | Name of the second time column that should be later than the first |
### RowCountTest
(synq.datachecks.testsuggestions.v1.RowCountTest)
### TestSuggestion
(synq.datachecks.testsuggestions.v1.TestSuggestion)
Test types that can be suggested
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| identifier | [ Identifier](#identifier) | none |
| explanation | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entity\_synq\_path.entity\_synq\_path | [optional string](#string) | Read-only path of matched entity. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_id.id | [optional string](#string) | Read-only Coalesce Quality ID of matched entity. This is a unique ID that can be used to access the entity in the Coalesce Quality UI. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.not\_null\_test | [ NotNullTest](#notnulltest) | Checks if specified columns contain no NULL values (e.g., user\_id should never be null) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.empty\_test | [ EmptyTest](#emptytest) | Checks if specified columns contain empty values (e.g., description field can be empty) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.accepted\_values\_test | [ AcceptedValuesTest](#acceptedvaluestest) | Validates that column values are within an allowed set (e.g., status in \['active', 'inactive', 'pending']) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.rejected\_values\_test | [ RejectedValuesTest](#rejectedvaluestest) | Validates that column values are not in a forbidden set (e.g., country not in \['UNKNOWN', 'TEST']) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.unique\_test | [ UniqueTest](#uniquetest) | Ensures specified columns form a unique key combination (e.g., order\_id is unique) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.freshness\_test | [ FreshnessTest](#freshnesstest) | Checks if data is up-to-date based on a time column (e.g., latest event\_timestamp within 24h) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.row\_count\_test | [ RowCountTest](#rowcounttest) | Deprecated: Validates the total number of rows in a table (e.g., orders table should have records) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.min\_max\_test | [ MinMaxTest](#minmaxtest) | Validates numeric values are within specified range (e.g., price between 0 and 1000) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.relative\_time\_test | [ RelativeTimeTest](#relativetimetest) | Compares time-based columns for logical order (e.g., start\_date before end\_date) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.business\_rule\_test | [ BusinessRuleTest](#businessruletest) | Custom SQL-based business logic validation (e.g., total\_amount = subtotal + tax) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.min\_value\_test | [ MinValueTest](#minvaluetest) | Validates numeric values are greater than or equal to a minimum value (e.g., price >= 0) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) test.max\_value\_test | [ MaxValueTest](#maxvaluetest) | Validates numeric values are less than or equal to a maximum value (e.g., price \<= 1000) |
### UniqueTest
(synq.datachecks.testsuggestions.v1.UniqueTest)
| Field | Type | Description |
| ----------------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| column\_names | [repeated string](#string) | List of columns that should form a unique combination |
| time\_partition\_column\_name | [ string](#string) | If provided, the check will be applied to the time window of the time partition column If not provided, the check will be applied to all rows |
| time\_window\_seconds | [ int64](#int64) | Time window for uniqueness check (in seconds) |
### DuckDBCloudConf
(synq.integrations.v1.DuckDBCloudConf)
DuckDB (via MotherDuck) cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_motherduck\_account.motherduck\_account | [optional string](#string) | MotherDuck account name or identifier. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_access\_token.access\_token | [optional string](#string) | MotherDuck access token. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### PostgresCloudConf
(synq.integrations.v1.PostgresCloudConf)
PostgreSQL cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Host address or IP. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Port (typically 5432). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database to connect to and ingest metadata from. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### FabricCloudConf
(synq.integrations.v1.FabricCloudConf)
Microsoft Fabric cloud-managed connection.
Fabric is workspace-scoped with cross-database queries (like Snowflake or
Databricks, not a single database): the workspace SQL analytics endpoint
exposes every warehouse / lakehouse in the workspace as a database, queryable
via three-part \[database].\[schema].\[table] T-SQL names.
Authentication is Microsoft Entra ID only — Fabric rejects SQL logins, so the
headless identity is an Entra service principal (application id + secret), or
a pre-acquired Entra access token.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Workspace SQL analytics endpoint host, e.g. "\.datawarehouse.fabric.microsoft.com". |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Default execution database — the context in which unqualified ad-hoc / monitor SQL resolves. Defaults to "master" (the always-present workspace entry point) when empty. Metadata reads and generated metrics SQL are fully database-qualified, so this only affects unqualified queries. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.service\_principal | [ FabricServicePrincipalAuth](#fabricserviceprincipalauth) | Entra service principal (application id + secret). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_access\_token.access\_token | [optional string](#string) | Pre-acquired Entra OAuth access token for the SQL scope ([https://database.windows.net/.default](https://database.windows.net/.default)). When set, takes precedence over the service principal — for callers that mint their own token out of band (managed identity / workload-identity federation). Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Fetch Fabric query history for cost attribution and SQL / column-level lineage. Management-plane reads only, no per-query billing. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scope.scope | [optional ScopeFilter](#scopefilter) | Include/exclude scope filter. ScopeRule.database = Fabric database / warehouse, ScopeRule.schema = schema, ScopeRule.table = table / view. |
### FabricServicePrincipalAuth
(synq.integrations.v1.FabricServicePrincipalAuth)
Microsoft Fabric Entra service-principal credentials.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_client\_id.client\_id | [optional string](#string) | Entra application (client) ID of the service principal. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_client\_secret.client\_secret | [optional string](#string) | Service principal client secret. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_tenant\_id.tenant\_id | [optional string](#string) | Entra tenant (directory) ID. Optional: inferred from the Fabric endpoint when empty; set it when the authority is not the service principal's home tenant. |
### OracleCloudConf
(synq.integrations.v1.OracleCloudConf)
Oracle Database cloud-managed connection. Oracle connections are scoped to a
Pluggable Database (PDB) via the service name.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Host address or IP (OCI Autonomous DB e.g. "adb.eu-frankfurt-1.oraclecloud.com"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Listener port (typically 1521; OCI Autonomous DB with mTLS uses 1522). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_service\_name.service\_name | [optional string](#string) | Service name / PDB name (OCI Autonomous DB e.g. "mydb\_high"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_username.username | [optional string](#string) | Username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ssl.ssl | [optional bool](#bool) | Enable TLS/SSL (TCPS). Required for OCI Autonomous Database. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ssl\_verify.ssl\_verify | [optional bool](#bool) | Verify the server certificate when SSL is enabled. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs (V\$SQL by default, DBA\_HIST with the Diagnostics Pack). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_diagnostics\_pack.use\_diagnostics\_pack | [optional bool](#bool) | Use the Oracle Diagnostics Pack (AWR) for persistent query-log history (requires a license; included with OCI Autonomous Database). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### RedshiftCloudConf
(synq.integrations.v1.RedshiftCloudConf)
Amazon Redshift cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Cluster endpoint hostname. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Port (typically 5439). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database to connect to and ingest metadata from. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from system views. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_freshness\_from\_query\_logs.freshness\_from\_query\_logs | [optional bool](#bool) | Estimate table freshness from query logs (SYS\_QUERY\_DETAIL). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### SnowflakeCloudConf
(synq.integrations.v1.SnowflakeCloudConf)
Snowflake cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Snowflake username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.password | [ string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.key\_pair | [ SnowflakeKeyPairAuth](#snowflakekeypairauth) | Key-pair authentication. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_account.account | [optional string](#string) | Account identifier (e.g. "xy12345.us-east-1") without scheme or trailing slash. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_warehouse.warehouse | [optional string](#string) | Warehouse to run queries on. |
| databases | [repeated string](#string) | Databases to monitor and ingest metadata from. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_role.role | [optional string](#string) | Role to use for metadata access and queries. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from the ACCOUNT\_USAGE schema. |
| fetch\_query\_logs\_databases | [repeated string](#string) | Databases to fetch query logs from (defaults to all configured databases). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_no\_get\_ddl.no\_get\_ddl | [optional bool](#bool) | Skip GET\_DDL for table definitions (use query logs instead). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_tasks.fetch\_tasks | [optional bool](#bool) | Ingest Snowflake Tasks metadata. |
| fetch\_tasks\_databases | [repeated string](#string) | Databases to retrieve tasks from (defaults to all configured databases). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_tasks\_executions\_from\_account\_usage.fetch\_tasks\_executions\_from\_account\_usage | [optional bool](#bool) | Use ACCOUNT\_USAGE.TASK\_HISTORY for task execution history. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_tasks\_executions\_duration.fetch\_tasks\_executions\_duration | [optional Duration](#duration) | Time range for fetching task execution history (minimum 5 minutes). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_table\_lineage.fetch\_table\_lineage | [optional bool](#bool) | Produce table-level lineage via GET\_LINEAGE (Enterprise edition or higher). |
| fetch\_table\_lineage\_databases | [repeated string](#string) | Databases to fetch upstream lineage from (defaults to `databases`). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_account\_usage\_db.account\_usage\_db | [optional string](#string) | Database where the ACCOUNT\_USAGE schema lives (defaults to "SNOWFLAKE"). |
### SnowflakeKeyPairAuth
(synq.integrations.v1.SnowflakeKeyPairAuth)
Snowflake key-pair authentication.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_private\_key\_secret.private\_key\_secret | [optional string](#string) | PEM-encoded private key (PKCS#8). Write-only — masked on reads. Required when using key-pair auth. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_public\_key.public\_key | [optional string](#string) | Public key corresponding to the private key. For a Coalesce Quality–managed key pair this is returned so you can register it on the Snowflake user; when you supply your own key it is optional. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_private\_key\_passphrase.private\_key\_passphrase | [optional string](#string) | Optional passphrase for an encrypted private key. Write-only — masked on reads. |
### AthenaAccessKeyAuth
(synq.integrations.v1.AthenaAccessKeyAuth)
Amazon Athena access-key authentication (long-lived IAM user credentials).
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_access\_key\_id.access\_key\_id | [optional string](#string) | AWS access key id (e.g. "AKIA..."). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_secret\_access\_key.secret\_access\_key | [optional string](#string) | AWS secret access key. Write-only — masked on reads. |
### AthenaCloudConf
(synq.integrations.v1.AthenaCloudConf)
Amazon Athena cloud-managed connection. Athena is serverless — there is no
host/port; the endpoint is implied by the AWS region.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_region.region | [optional string](#string) | AWS region hosting Athena and the Glue Data Catalog (e.g. "eu-central-1"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_workgroup.workgroup | [optional string](#string) | Workgroup to run queries under. Defaults to "primary" when empty; must have a query result location configured. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.access\_key | [ AthenaAccessKeyAuth](#athenaaccesskeyauth) | Long-lived IAM user access key. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_show\_create\_table.use\_show\_create\_table | [optional bool](#bool) | Use SHOW CREATE TABLE per object to retrieve full table DDL. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_show\_create\_view\.use\_show\_create\_view | [optional bool](#bool) | Use SHOW CREATE VIEW per view to retrieve full view DDL. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Fetch Athena query history (management API calls; no per-scan billing). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_iceberg\_metrics\_scan.use\_iceberg\_metrics\_scan | [optional bool](#bool) | For Iceberg tables, scan metadata tables for row counts and file sizes (one Athena query per table). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scope.scope | [optional ScopeFilter](#scopefilter) | Include/exclude scope filter. ScopeRule.database = Glue catalog (usually "AwsDataCatalog"), ScopeRule.schema = Glue database, ScopeRule.table = table/view. |
### AthenaOutputs
(synq.integrations.v1.AthenaOutputs)
Athena generated outputs.
| Field | Type | Description |
| -------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| account\_id | [ string](#string) | AWS account id resolved from the supplied credentials. |
| principal\_arn | [ string](#string) | ARN of the IAM principal Coalesce Quality authenticates as. Reference it in your Athena / Glue resource policies. |
### BigQueryOutputs
(synq.integrations.v1.BigQueryOutputs)
BigQuery generated outputs.
| Field | Type | Description |
| ----------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| service\_account\_email | [ string](#string) | Email of the service account derived from the supplied credentials. Grant this principal access to the datasets you want Coalesce Quality to read. |
### Capabilities
(synq.integrations.v1.Capabilities)
Capabilities advertise which actions are valid for an integration in its
current state, so a client can decide what to offer before calling.
Capabilities are a hint computed from the integration's type and current
state; the server still enforces every action. A `false` flag means the
action would be rejected right now (unsupported for this type, or not
applicable in the current state — for example `can_enable` is false for an
already-enabled integration).
| Field | Type | Description |
| ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| can\_patch | [ bool](#bool) | The configuration can be changed via `UpdateIntegration`. False for read-only / externally-owned integrations. |
| can\_refresh | [ bool](#bool) | An ad-hoc refresh can be triggered via `RefreshIntegration`. |
| can\_disable | [ bool](#bool) | The integration can be disabled via `DisableIntegration` (true only when currently enabled). |
| can\_enable | [ bool](#bool) | The integration can be enabled via `EnableIntegration` (true only when currently disabled). |
| can\_delete | [ bool](#bool) | The integration can be deleted via `DeleteIntegration`. |
| is\_dwh | [ bool](#bool) | Whether this is a data warehouse or database connection (rather than a transformation tool, catalog, etc.). Querying features — data preview, SQL tests, and reconciliation — are only available for these. |
| can\_reconcile\_deploy | [ bool](#bool) | Whether scheduled and API-triggered reconciliations can run against this integration. True only when it is an enabled data warehouse and your workspace has enabled reconciliation for it. These runs use the integration's workspace-level credentials, so this does not depend on any individual user's personal connection. |
### Integration
(synq.integrations.v1.Integration)
Integration is a connection from Coalesce Quality to one of your data
systems (a warehouse, database, or transformation tool).
| Field | Type | Description |
| ------------ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Server-assigned unique identifier (UUID). Use it to address the integration in `GetIntegration`, `UpdateIntegration`, `DeleteIntegration`, and the enable / disable / refresh / health RPCs. |
| title | [ string](#string) | Human-friendly name shown in the Coalesce Quality UI. Set by you on create and editable via update. |
| disabled | [ bool](#bool) | Whether the integration is currently disabled. A disabled integration keeps its configuration but is not scheduled or refreshed. Toggle with `EnableIntegration` / `DisableIntegration`. |
| created\_at | [ Timestamp](#timestamp) | When the integration was created. |
| updated\_at | [ Timestamp](#timestamp) | When the integration was last modified (configuration, title, or enabled / disabled state). |
| etag | [ string](#string) | Opaque entity tag for optimistic concurrency. Pass it back as `UpdateIntegrationRequest.etag` / `DeleteIntegrationRequest.etag` to ensure you are modifying the version you last read; a mismatch is rejected with a 409 / ABORTED. The value is weak (prefixed `W/`) and opaque — do not parse it. |
| platform | [ DataPlatformType](#dataplatformtype) | The data platform this integration connects to (for example POSTGRES, CLICKHOUSE, SNOWFLAKE). UNSPECIFIED for integrations that are not data warehouses or databases. |
| dialect | [ SqlDialect](#sqldialect) | The SQL dialect this integration understands — useful when writing SQL against it, such as custom monitors or reconciliation queries. Determined by the platform. UNSPECIFIED for integrations that are not data warehouses or databases. |
| config | [ IntegrationConfig](#integrationconfig) | Connection configuration. Secret fields are masked (empty) on reads. |
| outputs | [ IntegrationOutputs](#integrationoutputs) | Server-generated outputs (read-only). Empty for types that produce none. |
| capabilities | [ Capabilities](#capabilities) | Actions valid for this integration in its current state (read-only hint). |
### IntegrationConfig
(synq.integrations.v1.IntegrationConfig)
IntegrationConfig is the connection configuration for an integration.
Exactly one variant of the `config` oneof is set; the populated variant
determines the integration's type. The config holds the connection details
(host, credentials, scope) for the connected system.
Secret fields (passwords, tokens, keys) follow write-only semantics: they are
masked (returned empty) on reads. See each `*Conf` message and
`IntegrationsService.UpdateIntegration` for preserve / rotate / clear rules.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.bigquery | [ BigQueryCloudConf](#bigquerycloudconf) | Google BigQuery connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.snowflake | [ SnowflakeCloudConf](#snowflakecloudconf) | Snowflake connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.redshift | [ RedshiftCloudConf](#redshiftcloudconf) | Amazon Redshift connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.postgres | [ PostgresCloudConf](#postgrescloudconf) | PostgreSQL connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.mysql | [ MySQLCloudConf](#mysqlcloudconf) | MySQL connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.clickhouse | [ ClickhouseCloudConf](#clickhousecloudconf) | ClickHouse connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.databricks | [ DatabricksCloudConf](#databrickscloudconf) | Databricks connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.trino | [ TrinoCloudConf](#trinocloudconf) | Trino / Presto connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.mssql | [ MSSQLCloudConf](#mssqlcloudconf) | Microsoft SQL Server / Azure SQL connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.oracle | [ OracleCloudConf](#oraclecloudconf) | Oracle Database connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.duckdb | [ DuckDBCloudConf](#duckdbcloudconf) | DuckDB / MotherDuck connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.athena | [ AthenaCloudConf](#athenacloudconf) | Amazon Athena connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.dbt\_cloud | [ DbtCloudConf](#dbtcloudconf) | dbt Cloud connection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.fabric | [ FabricCloudConf](#fabriccloudconf) | Microsoft Fabric connection. |
### IntegrationOutputs
(synq.integrations.v1.IntegrationOutputs)
Generated, non-secret values produced by the server when an integration is
created (for example a service-account email to grant access to, or a public
key to install). Outputs are read-only and are never accepted on writes.
At most one variant is set, matching the integration's type. Types that
produce no outputs leave this message empty.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) outputs.bigquery | [ BigQueryOutputs](#bigqueryoutputs) | BigQuery: the service-account identity to grant dataset access to. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) outputs.snowflake | [ SnowflakeOutputs](#snowflakeoutputs) | Snowflake: the public key to register when using key-pair auth. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) outputs.athena | [ AthenaOutputs](#athenaoutputs) | Athena: the resolved AWS caller identity. |
### SnowflakeOutputs
(synq.integrations.v1.SnowflakeOutputs)
Snowflake generated outputs.
| Field | Type | Description |
| ----------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| public\_key | [ string](#string) | Public key (PEM) to register on the Snowflake user when authenticating with a Coalesce Quality–managed key pair. Empty when you supply your own credentials. |
### TrinoBasicAuth
(synq.integrations.v1.TrinoBasicAuth)
Trino basic (username / password) authentication.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Trino username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Trino password. Write-only — masked on reads. |
### TrinoCloudConf
(synq.integrations.v1.TrinoCloudConf)
Trino / Presto cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Coordinator hostname or IP. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Port (leave unset for the driver default — typically 443 for HTTPS, 8080 for HTTP). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.basic | [ TrinoBasicAuth](#trinobasicauth) | Basic username/password auth. |
| catalogs | [repeated string](#string) | Catalogs to ingest metadata from (e.g. \["hive", "postgresql"]). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from system tables. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_no\_show\_create\_view\.no\_show\_create\_view | [optional bool](#bool) | Disable SHOW CREATE VIEW for view DDL. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_no\_show\_create\_table.no\_show\_create\_table | [optional bool](#bool) | Disable SHOW CREATE TABLE for table DDL. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_no\_materialized\_views.no\_materialized\_views | [optional bool](#bool) | Disable fetching materialized views from system.metadata.materialized\_views. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_table\_comments.fetch\_table\_comments | [optional bool](#bool) | Fetch table comments from system.metadata.table\_comments. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_plaintext.use\_plaintext | [optional bool](#bool) | Use plaintext HTTP instead of HTTPS. Only enable when SSL is unsupported or the connection is otherwise secured (e.g. a VPN). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### MySQLCloudConf
(synq.integrations.v1.MySQLCloudConf)
MySQL cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Host address or IP. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Port (typically 3306). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### BatchGetIntegrationsRequest
(synq.integrations.v1.BatchGetIntegrationsRequest)
Request to fetch multiple integrations by id.
| Field | Type | Description |
| ---------------- | -------------------------- | ------------------------------------------------------------------- |
| integration\_ids | [repeated string](#string) | Integration ids (UUIDs). Unknown ids are omitted from the response. |
### BatchGetIntegrationsResponse
(synq.integrations.v1.BatchGetIntegrationsResponse)
Response with the requested integrations.
| Field | Type | Description |
| ------------ | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| integrations | [map IntegrationsEntry](#integrationsentry) | The integrations that were found, keyed by integration id. Requested ids that do not exist are absent from the map. |
### BatchGetIntegrationsResponse.IntegrationsEntry
(synq.integrations.v1.BatchGetIntegrationsResponse.IntegrationsEntry)
| Field | Type | Description |
| ----- | ---------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Integration](#integration) | none |
### CreateIntegrationRequest
(synq.integrations.v1.CreateIntegrationRequest)
Request to create an integration.
| Field | Type | Description |
| ------ | ---------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| title | [ string](#string) | Human-friendly name for the integration. |
| config | [ IntegrationConfig](#integrationconfig) | Connection configuration. Exactly one `config` variant must be set; it fixes the integration's type. |
### CreateIntegrationResponse
(synq.integrations.v1.CreateIntegrationResponse)
Response from creating an integration.
| Field | Type | Description |
| ----------- | ---------------------------- | ------------------------------------------------------------------------------------ |
| integration | [ Integration](#integration) | The created integration, including its assigned id, etag, and any generated outputs. |
### DeleteIntegrationRequest
(synq.integrations.v1.DeleteIntegrationRequest)
Request to delete an integration.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration to delete (UUID). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard (see `UpdateIntegrationRequest.etag`). |
### DeleteIntegrationResponse
(synq.integrations.v1.DeleteIntegrationResponse)
Response from deleting an integration.
### DisableIntegrationRequest
(synq.integrations.v1.DisableIntegrationRequest)
Request to disable an integration.
| Field | Type | Description |
| --------------- | ------------------ | ---------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration to disable (UUID). |
### DisableIntegrationResponse
(synq.integrations.v1.DisableIntegrationResponse)
Response from disabling an integration.
| Field | Type | Description |
| ----------- | ---------------------------- | -------------------------------- |
| integration | [ Integration](#integration) | The integration after disabling. |
### EnableIntegrationRequest
(synq.integrations.v1.EnableIntegrationRequest)
Request to enable an integration.
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration to enable (UUID). |
### EnableIntegrationResponse
(synq.integrations.v1.EnableIntegrationResponse)
Response from enabling an integration.
| Field | Type | Description |
| ----------- | ---------------------------- | ------------------------------- |
| integration | [ Integration](#integration) | The integration after enabling. |
### GetIntegrationHealthRequest
(synq.integrations.v1.GetIntegrationHealthRequest)
Request for an integration's health and run history.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration (UUID). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Cursor-based pagination over the run history. Omit for a bounded recent window (most recent runs from the last 7 days). |
### GetIntegrationHealthResponse
(synq.integrations.v1.GetIntegrationHealthResponse)
Response with current health plus a page of recent runs.
| Field | Type | Description |
| ---------- | ------------------------------------------ | ----------------------------------------------------------------- |
| health | [ IntegrationHealth](#integrationhealth) | Current health summary. |
| runs | [repeated IntegrationRun](#integrationrun) | Recent runs, most recent first. |
| page\_info | [ PageInfo](#pageinfo) | Pagination metadata; pass `page_info.last_id` as the next cursor. |
### GetIntegrationRequest
(synq.integrations.v1.GetIntegrationRequest)
Request to fetch a single integration.
| Field | Type | Description |
| --------------- | ------------------ | ---------------------- |
| integration\_id | [ string](#string) | Integration id (UUID). |
### GetIntegrationResponse
(synq.integrations.v1.GetIntegrationResponse)
Response with a single integration.
| Field | Type | Description |
| ----------- | ---------------------------- | -------------------------- |
| integration | [ Integration](#integration) | The requested integration. |
### IntegrationHealth
(synq.integrations.v1.IntegrationHealth)
Current health summary for an integration.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| status | [ HealthStatus](#healthstatus) | Status derived from the most recent run. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_run\_at.last\_run\_at | [optional Timestamp](#timestamp) | When the most recent run occurred. Unset when no runs are observed. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_success\_at.last\_success\_at | [optional Timestamp](#timestamp) | When the most recent successful run occurred. Unset when none is observed. |
| message | [ string](#string) | Human-readable message from the most recent run (for example an error summary). Empty when there is nothing to report. |
| healthy | [ bool](#bool) | Convenience flag: true when `status` is OK and the last run is recent relative to the integration's expected refresh cadence. |
### IntegrationRun
(synq.integrations.v1.IntegrationRun)
A single observed run (refresh / sync) of an integration.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| run\_id | [ string](#string) | Run identifier. |
| status | [ HealthStatus](#healthstatus) | Outcome of this run. |
| started\_at | [ Timestamp](#timestamp) | When the run started. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_finished\_at.finished\_at | [optional Timestamp](#timestamp) | When the run finished. Unset while still running. |
| message | [ string](#string) | Human-readable message for this run (for example an error summary). Empty when there is nothing to report. |
### ListIntegrationsRequest
(synq.integrations.v1.ListIntegrationsRequest)
Request to list integrations.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_disabled.disabled | [optional bool](#bool) | Optional filter: when set, return only enabled (false) or only disabled (true) integrations. Unset means both. |
### ListIntegrationsResponse
(synq.integrations.v1.ListIntegrationsResponse)
Response with the workspace's integrations.
| Field | Type | Description |
| ------------ | ------------------------------------ | -------------------------------------- |
| integrations | [repeated Integration](#integration) | All integrations matching the request. |
### RefreshIntegrationRequest
(synq.integrations.v1.RefreshIntegrationRequest)
Request to trigger an ad-hoc refresh.
| Field | Type | Description |
| --------------- | ------------------ | ---------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration to refresh (UUID). |
### RefreshIntegrationResponse
(synq.integrations.v1.RefreshIntegrationResponse)
Response from triggering a refresh.
### UpdateIntegrationRequest
(synq.integrations.v1.UpdateIntegrationRequest)
Request to update an integration. The `config` is replaced wholesale; `title`
is patch-style (omit to leave unchanged).
| Field | Type | Description |
| ------------------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Id of the integration to update (UUID). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | New human-friendly name. Omit to leave the title unchanged. |
| config | [ IntegrationConfig](#integrationconfig) | New connection configuration. The populated `config` variant must match the existing integration's type. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the update is applied only if it matches the integration's current etag; otherwise ABORTED (HTTP 409). Omit for last-write-wins. |
### UpdateIntegrationResponse
(synq.integrations.v1.UpdateIntegrationResponse)
Response from updating an integration.
| Field | Type | Description |
| ----------- | ---------------------------- | ---------------------------------------- |
| integration | [ Integration](#integration) | The updated integration with a new etag. |
### DbtCloudConf
(synq.integrations.v1.DbtCloudConf)
dbt Cloud transformation orchestration cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_account\_id.account\_id | [optional string](#string) | dbt Cloud account id (the numeric id from your dbt Cloud URL). |
| job\_ids | [repeated string](#string) | dbt Cloud jobs to track, by job id. Provide the full set on every update (the list is replaced, not merged). When empty, all jobs visible to the API token are tracked. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_token.token | [optional string](#string) | dbt Cloud API token (service token recommended). Write-only — masked on reads; omit to keep the stored token, send a new value to rotate it. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_project\_id.project\_id | [optional string](#string) | Project id used to generate asset identifiers. Use the same id for multiple projects that should be merged. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_api\_endpoint.api\_endpoint | [optional string](#string) | dbt Cloud API hostname without scheme (e.g. "cloud.getdbt.com", "emea.dbt.com"). Empty uses the multi-tenant default. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_default\_database\_instance.default\_database\_instance | [optional string](#string) | Database instance identifier, required where database names are not globally unique (e.g. a Snowflake account). |
### MSSQLCloudConf
(synq.integrations.v1.MSSQLCloudConf)
Microsoft SQL Server / Azure SQL Database cloud-managed connection. SQL Server
connections are scoped to a single database; create one integration per
database.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Hostname or IP (Azure SQL e.g. "yourserver.database.windows.net"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | Port (typically 1433). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database to connect to and ingest metadata from. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_username.username | [optional string](#string) | Login username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Login password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_trust\_cert.trust\_cert | [optional bool](#bool) | Skip TLS server certificate verification (not recommended for Azure SQL). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_encrypt.encrypt | [optional string](#string) | Encryption mode: "true" (default, required for Azure SQL), "false", "disable". |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from Query Store (must be enabled on the database; Azure SQL has it on by default). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scope.scope | [optional ScopeFilter](#scopefilter) | Include/exclude scope filter (by schema and table; database-level filtering does not apply since the connection targets one database). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### DatabricksCloudConf
(synq.integrations.v1.DatabricksCloudConf)
Databricks cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_workspace\_url.workspace\_url | [optional string](#string) | Workspace URL (e.g. "[https://your-workspace.cloud.databricks.com](https://your-workspace.cloud.databricks.com)"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.token | [ string](#string) | Personal access token. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) authentication.oauth\_m2m | [ DatabricksOAuthM2M](#databricksoauthm2m) | OAuth 2.0 machine-to-machine (service principal) auth. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_warehouse\_id.warehouse\_id | [optional string](#string) | SQL warehouse id (or cluster id) used to execute queries. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from system tables. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_table\_metrics.fetch\_table\_metrics | [optional bool](#bool) | Run ANALYZE TABLE to refresh and collect statistics. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_table\_metrics\_scan.fetch\_table\_metrics\_scan | [optional bool](#bool) | Run ANALYZE TABLE ... SCAN for detailed metrics incl. row counts (more resource-intensive). |
| catalog\_blocklist | [repeated string](#string) | Catalog name patterns to exclude from ingestion. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_table\_tags.fetch\_table\_tags | [optional bool](#bool) | Retrieve Unity Catalog table tags. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_use\_show\_create\_table.use\_show\_create\_table | [optional bool](#bool) | Use SHOW CREATE TABLE for table DDL (otherwise extracted from query logs). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_disable\_unity\_table\_lineage.disable\_unity\_table\_lineage | [optional bool](#bool) | Disable retrieval of Unity Catalog table-to-table lineage. Coalesce Quality already computes lineage from query logs, so the Unity Catalog edges can be redundant noise. When unset/false, Unity Catalog table-to-table lineage is retrieved and published (the default). |
### DatabricksOAuthM2M
(synq.integrations.v1.DatabricksOAuthM2M)
Databricks OAuth 2.0 machine-to-machine (service principal) credentials.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------- | -------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_client\_id.client\_id | [optional string](#string) | OAuth client id of the service principal. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_client\_secret.client\_secret | [optional string](#string) | OAuth client secret. Write-only — masked on reads. |
### BigQueryCloudConf
(synq.integrations.v1.BigQueryCloudConf)
Google BigQuery cloud-managed connection.
All fields are optional so an update can carry only what changes: omit a field
to leave it unchanged, or send a new value to set it. Secret fields are
write-only (masked, returned empty, on reads); omit to keep the stored value
or send a new value to rotate it.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_project\_id.project\_id | [optional string](#string) | Google Cloud project id containing the datasets to monitor. |
| blacklisted\_datasets | [repeated string](#string) | Dataset name patterns to exclude from ingestion. Mutually exclusive with `datasets` — when `datasets` is set, this is ignored. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_service\_account\_key.service\_account\_key | [optional string](#string) | Service-account key JSON. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_region.region | [optional string](#string) | Google Cloud region for the project (e.g. "us-central1", "EU"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest BigQuery query logs from INFORMATION\_SCHEMA. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs (e.g. "project.dataset.table"). |
| datasets | [repeated string](#string) | Explicit list of datasets to scrape. When set, only these are queried (no project-level dataset listing needed). When empty, all visible datasets are discovered. Mutually exclusive with `blacklisted_datasets`. |
### ClickhouseCloudConf
(synq.integrations.v1.ClickhouseCloudConf)
ClickHouse cloud-managed connection.
Fields are optional so an update can carry only what changes (omit = leave
unchanged). Secret fields are write-only (masked on reads); omit to keep or
send a new value to rotate.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_host.host | [optional string](#string) | Host address or IP. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional string](#string) | Port (e.g. "8123" for HTTP, "9440" for HTTPS). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_username.username | [optional string](#string) | Username. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password. Write-only — masked on reads. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_default\_dataset.default\_dataset | [optional string](#string) | Default database/schema used when not specified in a reference. |
| additional\_parameters | [map AdditionalParametersEntry](#additionalparametersentry) | Additional connection parameters as key/value pairs (e.g. "max\_execution\_time": "30"). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ssl.ssl | [optional bool](#bool) | Enable SSL/TLS. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database\_name.database\_name | [optional string](#string) | Database to connect to and ingest metadata from. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Ingest query logs from system.query\_log. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_audit\_table\_fqn.audit\_table\_fqn | [optional string](#string) | Fully-qualified table for storing SQL test audit logs. |
### ClickhouseCloudConf.AdditionalParametersEntry
(synq.integrations.v1.ClickhouseCloudConf.AdditionalParametersEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ string](#string) | none |
### IssuesCommand
(synq.issues.commands.v1.IssuesCommand)
Not to be used directly. Use the IssuesService instead when calling via API.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ----------- |
| workspace | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.mark\_investigating | [ MarkInvestigatingRequest](#markinvestigatingrequest) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.mark\_fixed | [ MarkFixedRequest](#markfixedrequest) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.mark\_expected | [ MarkExpectedRequest](#markexpectedrequest) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.mark\_no\_action\_needed | [ MarkNoActionNeededRequest](#marknoactionneededrequest) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.post\_comment | [ PostCommentRequest](#postcommentrequest) | none |
### BatchGetIssuesRequest
(synq.issues.v2.BatchGetIssuesRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------- |
| issue\_ids | [repeated string](#string) | IDs of the issues to get. |
### BatchGetIssuesResponse
(synq.issues.v2.BatchGetIssuesResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ----------- |
| issues | [map IssuesEntry](#issuesentry) | Issues. |
### BatchGetIssuesResponse.IssuesEntry
(synq.issues.v2.BatchGetIssuesResponse.IssuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Issue](#issue) | none |
### ClearStatusRequest
(synq.issues.v2.ClearStatusRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue whose status should be cleared. |
| actor | [ Actor](#actor) | Actor clearing the status. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time.time | [optional Timestamp](#timestamp) | Time at which the status was cleared. Defaults to the current time when not provided. |
### ClearStatusResponse
(synq.issues.v2.ClearStatusResponse)
### InteractionFilter
(synq.issues.v2.InteractionFilter)
Filter for matching issues where an actor interacted with them.
If none of status\_changes/comments/activities is set, all interaction types are matched.
| Field | Type | Description |
| --------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| identities | [repeated string](#string) | Identity strings to match against the actor that performed the interaction. The caller is responsible for resolving a user to all their known identities (e.g. via GetUserIdentities or GetUserAliases + actoridentities.FromUserAliases()) before calling this API. Format: "synq:\", "email:\", "slack:\", etc. |
| status\_changes | [ bool](#bool) | Match issues where the user set a status (investigating, fixed, expected, etc.). |
| comments | [ bool](#bool) | Match issues where the user posted a comment. |
| activities | [ bool](#bool) | Match issues where the user has an activity record. |
### ListIssuesRequest
(synq.issues.v2.ListIssuesRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entities\_query.entities\_query | [optional Query](#query) | Filter by entities. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time.time | [optional Time](#time) | Time range filter |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sort.sort | [optional Sort](#sort) | Sort options |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_lifecycle\_state.lifecycle\_state | [optional LifecycleState](#lifecyclestate) | Filter by issue lifecycle state |
| lifecycle\_states | [repeated LifecycleState](#lifecyclestate) | Filter by issue lifecycle states |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_interacted\_by.interacted\_by | [optional InteractionFilter](#interactionfilter) | Filter issues by users who interacted with them (status change, comment, or activity). |
| severities | [repeated Severity](#severity) | Filter by issue severity. If empty, issues of any severity are returned. |
### ListIssuesRequest.Sort
(synq.issues.v2.ListIssuesRequest.Sort)
| Field | Type | Description |
| -------- | ---------------- | ----------- |
| sort\_by | [ Field](#field) | none |
| order | [ Order](#order) | none |
### ListIssuesRequest.Time
(synq.issues.v2.ListIssuesRequest.Time)
| Field | Type | Description |
| ----- | ------------------------ | ----------- |
| field | [ Field](#field) | none |
| from | [ Timestamp](#timestamp) | none |
| to | [ Timestamp](#timestamp) | none |
### ListIssuesResponse
(synq.issues.v2.ListIssuesResponse)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------- |
| page\_info | [ PageInfo](#pageinfo) | Paging information. |
| issue\_ids | [repeated string](#string) | none |
### MarkExpectedRequest
(synq.issues.v2.MarkExpectedRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ----------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as expected. |
| actor | [ Actor](#actor) | Actor marking the issue as expected. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as expected. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkExpectedResponse
(synq.issues.v2.MarkExpectedResponse)
### MarkFixedRequest
(synq.issues.v2.MarkFixedRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | -------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as fixed. |
| actor | [ Actor](#actor) | Actor marking the issue as fixed. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as fixed. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkFixedResponse
(synq.issues.v2.MarkFixedResponse)
### MarkInvestigatingRequest
(synq.issues.v2.MarkInvestigatingRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ---------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as investigating. |
| actor | [ Actor](#actor) | Actor marking the issue as investigating. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as investigating. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkInvestigatingResponse
(synq.issues.v2.MarkInvestigatingResponse)
### MarkNoActionNeededRequest
(synq.issues.v2.MarkNoActionNeededRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ------------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as no action needed. |
| actor | [ Actor](#actor) | Actor marking the issue as no action needed. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as no action needed. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkNoActionNeededResponse
(synq.issues.v2.MarkNoActionNeededResponse)
### PostCommentRequest
(synq.issues.v2.PostCommentRequest)
| Field | Type | Description |
| --------- | ------------------------ | ------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to post a comment on. |
| actor | [ Actor](#actor) | Actor posting the comment. |
| comment | [ string](#string) | Comment to post. |
| time | [ Timestamp](#timestamp) | Time at which the comment was posted. Defaults to the current time. |
### PostCommentResponse
(synq.issues.v2.PostCommentResponse)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| comment\_id | [ string](#string) | none |
### Issue
(synq.issues.issues.v1.Issue)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------ | ------------------------------------------------ |
| id | [ string](#string) | ID of the issue. |
| name | [ string](#string) | Name of the issue. |
| message | [ string](#string) | Original message of the issue. |
| current\_message | [ string](#string) | Current message on the issue. |
| last\_error\_message | [ string](#string) | Last error message on the issue. |
| severity | [ Severity](#severity) | Severity of the issue. |
| trigger\_entity | [ Identifier](#identifier) | Entity that triggered this issue. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) trigger\_details.monitor | [ MonitorTriggerDetails](#monitortriggerdetails) | none |
| affected\_entities | [repeated Identifier](#identifier) | Entities affected by this issue. |
| state | [ State](#state) | State of the issue. |
| started\_at | [ Timestamp](#timestamp) | Started at timestamp. |
| updated\_at | [ Timestamp](#timestamp) | Updated at timestamp. |
| ended\_at | [ Timestamp](#timestamp) | Ended at timestamp. |
| latest\_status | [ Status](#status) | Latest status of the issue. |
| latest\_status\_actor | [ Actor](#actor) | Actor that last updated the status of the issue. |
| comments | [repeated IssueComment](#issuecomment) | List of comments posted on the issue. |
| lifecycle\_state | [ LifecycleState](#lifecyclestate) | Lifecycle state of the issue. |
### IssueComment
(synq.issues.issues.v1.IssueComment)
| Field | Type | Description |
| ----------- | ------------------------ | ----------- |
| id | [ string](#string) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| actor | [ Actor](#actor) | none |
### MonitorTriggerDetails
(synq.issues.issues.v1.MonitorTriggerDetails)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ----------- |
| monitor | [ MonitorIdentifier](#monitoridentifier) | none |
| metric\_id | [ string](#string) | none |
| metric\_version | [ int32](#int32) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segment\_value.segment\_value | [optional string](#string) | none |
### BatchGetIssuesRequest
(synq.issues.issues.v1.BatchGetIssuesRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ------------------------- |
| issue\_ids | [repeated string](#string) | IDs of the issues to get. |
### BatchGetIssuesResponse
(synq.issues.issues.v1.BatchGetIssuesResponse)
| Field | Type | Description |
| ------ | ------------------------------- | ----------- |
| issues | [map IssuesEntry](#issuesentry) | Issues. |
### BatchGetIssuesResponse.IssuesEntry
(synq.issues.issues.v1.BatchGetIssuesResponse.IssuesEntry)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ Issue](#issue) | none |
### Limit
(synq.issues.issues.v1.Limit)
| Field | Type | Description |
| --------- | ------------------ | ----------- |
| max | [ int32](#int32) | none |
| after\_id | [ string](#string) | none |
### ListIssuesRequest
(synq.issues.issues.v1.ListIssuesRequest)
| Field | Type | Description |
| -------- | ---------------------------------- | --------------------- |
| from | [ Timestamp](#timestamp) | Filter by time range. |
| to | [ Timestamp](#timestamp) | Filter by time range. |
| limit | [ Limit](#limit) | none |
| entities | [repeated Identifier](#identifier) | Filter by entities. |
### ListIssuesResponse
(synq.issues.issues.v1.ListIssuesResponse)
| Field | Type | Description |
| ------ | ------------------------ | ----------- |
| issues | [repeated Issue](#issue) | Issues. |
### MarkExpectedRequest
(synq.issues.issues.v1.MarkExpectedRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ----------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as expected. |
| actor | [ Actor](#actor) | Actor marking the issue as expected. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as expected. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkExpectedResponse
(synq.issues.issues.v1.MarkExpectedResponse)
### MarkFixedRequest
(synq.issues.issues.v1.MarkFixedRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | -------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as fixed. |
| actor | [ Actor](#actor) | Actor marking the issue as fixed. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as fixed. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkFixedResponse
(synq.issues.issues.v1.MarkFixedResponse)
### MarkInvestigatingRequest
(synq.issues.issues.v1.MarkInvestigatingRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ---------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as investigating. |
| actor | [ Actor](#actor) | Actor marking the issue as investigating. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as investigating. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkInvestigatingResponse
(synq.issues.issues.v1.MarkInvestigatingResponse)
### MarkNoActionNeededRequest
(synq.issues.issues.v1.MarkNoActionNeededRequest)
| Field | Type | Description |
| ----------------------------- | ------------------------ | ------------------------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to mark as no action needed. |
| actor | [ Actor](#actor) | Actor marking the issue as no action needed. |
| time | [ Timestamp](#timestamp) | Time at which the issue was marked as no action needed. Defaults to the current time. |
| require\_no\_existing\_status | [ bool](#bool) | Ignore status change if the issue already has a status. |
### MarkNoActionNeededResponse
(synq.issues.issues.v1.MarkNoActionNeededResponse)
### PostCommentRequest
(synq.issues.issues.v1.PostCommentRequest)
| Field | Type | Description |
| --------- | ------------------------ | ------------------------------------------------------------------- |
| issue\_id | [ string](#string) | ID of the issue to post a comment on. |
| actor | [ Actor](#actor) | Actor posting the comment. |
| comment | [ string](#string) | Comment to post. |
| time | [ Timestamp](#timestamp) | Time at which the comment was posted. Defaults to the current time. |
### PostCommentResponse
(synq.issues.issues.v1.PostCommentResponse)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| comment\_id | [ string](#string) | none |
### Actor
(synq.issues.actor.v1.Actor)
Actor identifies who performed a write — set by the calling client and
carried end-to-end through the public API into stored audit trails (issue
status changes, comments, incident assignments) and rendered downstream
(e.g. Slack/MSTeams/email alerts).
Producers should populate:
1. `name` — human-readable display label, derived from
`synq.auth.iam.v1.IamResponse.user_name` when available, falling back
to `user_email`. Avoid generic placeholders ("MCP", "API"); readers
treat those as "no identity resolved" and fall back to impersonal copy.
2. `user` — the strongest identifier the caller can prove. For human
callers, set `email` from `IamResponse.user_email` so the server can
resolve the caller back to a workspace user.
3. `via` — entry-point label for the channel through which the request
arrived (e.g. VIA\_MCP for the MCP server), regardless of who the
caller is.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------- | -------------------------------- | ----------- |
| name | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) user.slack | [ SlackUser](#slackuser) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) user.email | [ EmailUser](#emailuser) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) user.pagerduty | [ PagerdutyUser](#pagerdutyuser) | none |
| via | [ Via](#via) | none |
### EmailUser
(synq.issues.actor.v1.EmailUser)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| user\_email | [ string](#string) | none |
### PagerdutyUser
(synq.issues.actor.v1.PagerdutyUser)
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
### SlackUser
(synq.issues.actor.v1.SlackUser)
| Field | Type | Description |
| -------- | ------------------ | ----------- |
| user\_id | [ string](#string) | none |
### Prediction
(synq.monitors.history.v1.Prediction)
| Field | Type | Description |
| ----- | ---------------------------- | ------------------ |
| f | [ string](#string) | Field |
| s | [ string](#string) | Segment |
| m | [ string](#string) | Metric |
| v | [ double](#double) | Value |
| vu | [ DoubleValue](#doublevalue) | Upper bound |
| vl | [ DoubleValue](#doublevalue) | Lower bound |
| p | [ string](#string) | Pattern |
| e | [ double](#double) | Expected value |
| st | [ double](#double) | Standard deviation |
| t | [ Timestamp](#timestamp) | Timestamp |
### HistoryRequest
(synq.monitors.history.v1.HistoryRequest)
| Field | Type | Description |
| ---------------- | -------------------------- | ---------------------------------------------- |
| monitor\_path | [ string](#string) | Experimental: Will be replaced with identifier |
| metrics\_version | [ int32](#int32) | none |
| segments | [repeated string](#string) | none |
| from | [ Timestamp](#timestamp) | none |
| to | [ Timestamp](#timestamp) | none |
### HistoryResponse
(synq.monitors.history.v1.HistoryResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| predictions | [repeated Prediction](#prediction) | none |
### MonitorInfoRequest
(synq.monitors.info.v1.MonitorInfoRequest)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| id | [ Identifier](#identifier) | none |
### MonitorInfoResponse
(synq.monitors.info.v1.MonitorInfoResponse)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_monitor\_info.monitor\_info | [optional MonitorInfo](#monitorinfo) | none |
### ColumnSource
(synq.monitors.info.v1.ColumnSource)
| Field | Type | Description |
| ------ | ------------------ | ----------- |
| column | [ string](#string) | none |
### Condition
(synq.monitors.info.v1.Condition)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| expression | [ string](#string) | none |
### CountRows
(synq.monitors.info.v1.CountRows)
### DatabaseFqn
(synq.monitors.info.v1.DatabaseFqn)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_instance.instance | [optional string](#string) | Usually it is the hostname of the server |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database\_name.database\_name | [optional string](#string) | Database name for databases with multi-db support |
| schema\_name | [ string](#string) | One level |
| object\_name | [ string](#string) | Name of the table or view |
### ExpressionSource
(synq.monitors.info.v1.ExpressionSource)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| expression | [ string](#string) | none |
### MetadataSource
(synq.monitors.info.v1.MetadataSource)
### Metric
(synq.monitors.info.v1.Metric)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| metric\_id | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.freshness | [ MonitorFreshness](#monitorfreshness) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.volume | [ MonitorVolume](#monitorvolume) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.value | [ MonitorValue](#monitorvalue) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.failed\_rows | [ MonitorFailedRows](#monitorfailedrows) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.field\_stats | [ MonitorFieldStats](#monitorfieldstats) | A statistical profile of a single column (for example null counts, uniqueness, minimum/maximum, mean/standard deviation or byte size). The specific statistic is identified by metric\_id; this variant carries the column the statistic is computed on. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) metric\_type.category\_distribution | [ MonitorCategoryDistribution](#monitorcategorydistribution) | A shift in the distribution of the distinct values of a categorical column, scored against a learned baseline. This variant carries the column whose value distribution is monitored. |
### MonitorCategoryDistribution
(synq.monitors.info.v1.MonitorCategoryDistribution)
| Field | Type | Description |
| ------ | ------------------ | --------------------------------------------------------------------- |
| column | [ string](#string) | Name of the categorical column whose value distribution is monitored. |
### MonitorFailedRows
(synq.monitors.info.v1.MonitorFailedRows)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| sql | [ string](#string) | none |
### MonitorFieldStats
(synq.monitors.info.v1.MonitorFieldStats)
| Field | Type | Description |
| ------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| column | [ string](#string) | Name of the column whose statistical profile is monitored, as it appears in the monitored object. Empty when the statistic is computed at the table level rather than on a specific column. |
### MonitorFreshness
(synq.monitors.info.v1.MonitorFreshness)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) freshness\_source.expression | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) freshness\_source.table\_metadata | [ MetadataSource](#metadatasource) | none |
### MonitorInfo
(synq.monitors.info.v1.MonitorInfo)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ MonitorIdentifier](#monitoridentifier) | Identifier of the monitor |
| monitor\_id | [ Identifier](#identifier) | Identifier of the monitor |
| monitor\_synq\_path | [ string](#string) | Coalesce Quality Path to the entity. |
| name | [ string](#string) | Name of the monitor |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segmentation.segmentation | [optional Segmentation](#segmentation) | Information how this monitor segments the data |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_partitioning.partitioning | [optional Partitioning](#partitioning) | Information how this monitor partitions the data |
| conditions | [repeated Condition](#condition) | Optional conditions which are applied to the monitor metrics retrieval |
| metrics | [repeated Metric](#metric) | Metrics which this monitor monitors |
| monitored | [repeated Monitored](#monitored) | Entity which is monitored |
| managed\_by\_rule | [ bool](#bool) | Whether this monitor is governed by a deployment rule. When true, the monitor's configuration is managed centrally by a rule and manual edits may be overwritten the next time the rule is applied. False for monitors that are configured individually. |
### MonitorValue
(synq.monitors.info.v1.MonitorValue)
| Field | Type | Description |
| ---------- | ------------------ | ----------- |
| expression | [ string](#string) | none |
### MonitorVolume
(synq.monitors.info.v1.MonitorVolume)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------ | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) volume\_source.expression | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) volume\_source.count\_rows | [ CountRows](#countrows) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) volume\_source.table\_metadata | [ MetadataSource](#metadatasource) | none |
### Monitored
(synq.monitors.info.v1.Monitored)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the monitored entity. |
| synq\_path | [ string](#string) | Coalesce Quality Path to the monitored entity. |
| name | [ string](#string) | Name of the monitored entity |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Description of the monitored entity |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Id of the integration which provided information about monitored entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_object\_fqn.object\_fqn | [optional DatabaseFqn](#databasefqn) | Coordinates to the physical table/view which is monitored (when applicable) |
| sql\_dialect | [ SqlDialect](#sqldialect) | SQL dialect used for monitoring |
### Partitioning
(synq.monitors.info.v1.Partitioning)
| Field | Type | Description |
| ------ | ---------------------- | ----------- |
| column | [ string](#string) | none |
| period | [ Duration](#duration) | none |
### Segmentation
(synq.monitors.info.v1.Segmentation)
| Field | Type | Description |
| ------ | ------------------ | ----------- |
| column | [ string](#string) | none |
### ModeAnomalyEngine
(synq.monitors.custom\_monitors.v1.ModeAnomalyEngine)
| Field | Type | Description |
| ----------- | ---------------------------- | ----------- |
| sensitivity | [ Sensitivity](#sensitivity) | none |
### ModeFixedThresholds
(synq.monitors.custom\_monitors.v1.ModeFixedThresholds)
| Field | Type | Description |
| ----- | ---------------------------- | ----------- |
| min | [ DoubleValue](#doublevalue) | none |
| max | [ DoubleValue](#doublevalue) | none |
### MonitorCategoryDistribution
(synq.monitors.custom\_monitors.v1.MonitorCategoryDistribution)
| Field | Type | Description |
| ------------- | ------------------ | ------------------------------------------------------------------------------- |
| field | [ string](#string) | Categorical column whose value distribution is monitored. |
| top\_k\_limit | [ int32](#int32) | Max categories to track; the rest are aggregated into "other". 0 = use default. |
### MonitorCustomNumeric
(synq.monitors.custom\_monitors.v1.MonitorCustomNumeric)
| Field | Type | Description |
| ------------------- | ------------------ | ----------- |
| metric\_aggregation | [ string](#string) | none |
### MonitorDefinition
(synq.monitors.custom\_monitors.v1.MonitorDefinition)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | none |
| monitored\_id | [ Identifier](#identifier) | none |
| time\_partitioning | [ TimePartitioning](#timepartitioning) | How the monitored data is split into time segments. When omitted, the monitor takes one whole-data snapshot per scheduled run instead of segmenting by time (and gets no historical backfill on its first run). Must be omitted for table\_stats monitors. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segmentation.segmentation | [optional Segmentation](#segmentation) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_filter.filter | [optional string](#string) | none |
| severity | [ Severity](#severity) | none |
| name | [ string](#string) | none |
| description | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | none |
| source | [ Source](#source) | Source of the monitor. |
| timezone | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.freshness | [ MonitorFreshness](#monitorfreshness) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.volume | [ MonitorVolume](#monitorvolume) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.custom\_numeric | [ MonitorCustomNumeric](#monitorcustomnumeric) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.field\_stats | [ MonitorFieldStats](#monitorfieldstats) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.table\_stats | [ MonitorTableStats](#monitortablestats) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) monitor.category\_distribution | [ MonitorCategoryDistribution](#monitorcategorydistribution) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mode.anomaly\_engine | [ ModeAnomalyEngine](#modeanomalyengine) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mode.fixed\_thresholds | [ ModeFixedThresholds](#modefixedthresholds) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) schedule.daily | [ ScheduleDaily](#scheduledaily) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) schedule.hourly | [ ScheduleHourly](#schedulehourly) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) schedule.on\_demand | [ ScheduleOnDemand](#scheduleondemand) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sql\_source.sql\_source | [optional SqlSource](#sqlsource) | Optional SQL source. When set, the monitor queries against this SQL (wrapped as a CTE) instead of the table identified by monitored\_id directly. Column references in time\_partitioning, segmentation, and filter refer to columns in the SQL output. |
### MonitorFieldStats
(synq.monitors.custom\_monitors.v1.MonitorFieldStats)
| Field | Type | Description |
| ------ | -------------------------- | ----------- |
| fields | [repeated string](#string) | none |
### MonitorFreshness
(synq.monitors.custom\_monitors.v1.MonitorFreshness)
| Field | Type | Description |
| ---------- | ------------------ | ----------------------------------------------------------------------- |
| expression | [ string](#string) | The expression to filter on (eg. "created\_at", "meta\['created\_at']") |
### MonitorTableStats
(synq.monitors.custom\_monitors.v1.MonitorTableStats)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| metric\_options | [repeated MetricOption](#metricoption) | Metrics to monitor. If empty, all metrics are monitored. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) freshness\_source.field | [ string](#string) | Timestamp column name, e.g. "updated\_at" (used as max(updated\_at)). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) freshness\_source.sql | [ string](#string) | Row-level SQL expression yielding a timestamp, e.g. "coalesce(updated\_at, created\_at)". Do NOT wrap it in an aggregate — max() is applied automatically. |
### MonitorVolume
(synq.monitors.custom\_monitors.v1.MonitorVolume)
### ScheduleDaily
(synq.monitors.custom\_monitors.v1.ScheduleDaily)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| minutes\_since\_midnight | [ int32](#int32) | Minutes since midnight (0-1439) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_delay\_num\_days.delay\_num\_days | [optional int32](#int32) | Delay monitoring by given number of days. |
| only\_schedule\_delay | [ bool](#bool) | if true, the minutes\_since\_midnight will be related to delay scheduling/execution instead of time shifting time partitions |
### ScheduleHourly
(synq.monitors.custom\_monitors.v1.ScheduleHourly)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| minute\_of\_hour | [ int32](#int32) | Minute of hour (0-59) |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_delay\_num\_hours.delay\_num\_hours | [optional int32](#int32) | Delay monitoring by given number of hours. |
| only\_schedule\_delay | [ bool](#bool) | if true, the minute\_of\_hour will be related to delay scheduling/execution instead of time shifting time partitions |
### ScheduleOnDemand
(synq.monitors.custom\_monitors.v1.ScheduleOnDemand)
### Segmentation
(synq.monitors.custom\_monitors.v1.Segmentation)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| expression | [ string](#string) | The expression to segment on (eg. "country", "meta\['country']") You can optionally specify values to include or exclude from segmentation. If neither are provided, all values are included by default. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_include\_values.include\_values | [optional ValueList](#valuelist) | List of expression values to include for segmentation (eg. "UK", "France") |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_exclude\_values.exclude\_values | [optional ValueList](#valuelist) | List of expression values to exclude for segmentation (eg. "NA", "") |
### SqlSource
(synq.monitors.custom\_monitors.v1.SqlSource)
SQL query to use as the data source for a monitor instead of querying a table directly.
The SQL is wrapped as a CTE, and the monitor's metric query runs against its output.
Column references (time partitioning, segmentation, filter) refer to columns in the SQL output.
| Field | Type | Description |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| sql | [ string](#string) | The SQL query providing the data source. Example: "SELECT created\_at, country, amount FROM orders WHERE status = 'completed'" |
### TimePartitioning
(synq.monitors.custom\_monitors.v1.TimePartitioning)
| Field | Type | Description |
| ---------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| expression | [ string](#string) | The expression to partition on (eg. "created\_at", "meta\['created\_at']"). Required whenever time\_partitioning is set. To monitor without time segmentation, omit the whole time\_partitioning message rather than sending an empty expression. |
| interval | [ Duration](#duration) | Length of one time segment. Optional: defaults to the interval implied by the schedule (24h for daily, 1h for hourly) and must equal it when set. On-demand monitors have no schedule interval to inherit, so they must set it explicitly whenever time\_partitioning is set. |
### ValueList
(synq.monitors.custom\_monitors.v1.ValueList)
| Field | Type | Description |
| ------ | -------------------------- | ----------- |
| values | [repeated string](#string) | none |
### BatchCreateMonitorRequest
(synq.monitors.custom\_monitors.v1.BatchCreateMonitorRequest)
| Field | Type | Description |
| -------- | ------------------------------------------------ | ----------- |
| monitors | [repeated MonitorDefinition](#monitordefinition) | none |
### BatchCreateMonitorResponse
(synq.monitors.custom\_monitors.v1.BatchCreateMonitorResponse)
| Field | Type | Description |
| --------------------- | -------------------------- | ----------- |
| created\_monitor\_ids | [repeated string](#string) | none |
### BatchDeleteMonitorRequest
(synq.monitors.custom\_monitors.v1.BatchDeleteMonitorRequest)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
### BatchDeleteMonitorResponse
(synq.monitors.custom\_monitors.v1.BatchDeleteMonitorResponse)
| Field | Type | Description |
| ------------ | -------------------------- | ----------- |
| deleted\_ids | [repeated string](#string) | none |
### BatchUpdateMonitorModeRequest
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorModeRequest)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------- | -------------------------------------------- | ----------- |
| ids | [repeated string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mode.anomaly\_engine | [ ModeAnomalyEngine](#modeanomalyengine) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) mode.fixed\_thresholds | [ ModeFixedThresholds](#modefixedthresholds) | none |
### BatchUpdateMonitorModeResponse
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorModeResponse)
| Field | Type | Description |
| ------------ | -------------------------- | ----------- |
| updated\_ids | [repeated string](#string) | none |
### BatchUpdateMonitorRequest
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorRequest)
| Field | Type | Description |
| ----------------------- | ------------------------------------------------ | ----------- |
| monitor\_ids\_to\_reset | [repeated string](#string) | none |
| monitors | [repeated MonitorDefinition](#monitordefinition) | none |
### BatchUpdateMonitorResponse
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorResponse)
| Field | Type | Description |
| ------------ | -------------------------- | ----------- |
| updated\_ids | [repeated string](#string) | none |
### BatchUpdateMonitorSeverityRequest
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorSeverityRequest)
| Field | Type | Description |
| -------- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
| severity | [ Severity](#severity) | none |
### BatchUpdateMonitorSeverityResponse
(synq.monitors.custom\_monitors.v1.BatchUpdateMonitorSeverityResponse)
| Field | Type | Description |
| ------------ | -------------------------- | ----------- |
| updated\_ids | [repeated string](#string) | none |
### ChangeOverview
(synq.monitors.custom\_monitors.v1.ChangeOverview)
| Field | Type | Description |
| -------------------- | ---------------------------------------- | ----------- |
| monitor\_id | [ string](#string) | none |
| origin\_definition | [ MonitorDefinition](#monitordefinition) | none |
| new\_definition | [ MonitorDefinition](#monitordefinition) | none |
| changes | [ string](#string) | none |
| changes\_delta\_json | [ string](#string) | none |
| should\_reset | [ bool](#bool) | none |
### ConfigChangesOverviewRequest
(synq.monitors.custom\_monitors.v1.ConfigChangesOverviewRequest)
| Field | Type | Description |
| ----------- | ------------------------------------------------ | ----------- |
| config\_ids | [repeated string](#string) | none |
| monitors | [repeated MonitorDefinition](#monitordefinition) | none |
### ConfigChangesOverviewResponse
(synq.monitors.custom\_monitors.v1.ConfigChangesOverviewResponse)
| Field | Type | Description |
| ------------------------------------- | ------------------------------------------------ | ----------- |
| monitors\_managed\_by\_app | [repeated MonitorDefinition](#monitordefinition) | none |
| monitors\_managed\_by\_other\_configs | [repeated MonitorDefinition](#monitordefinition) | none |
| monitors\_to\_create | [repeated MonitorDefinition](#monitordefinition) | none |
| monitors\_to\_delete | [repeated MonitorDefinition](#monitordefinition) | none |
| monitors\_unchanged | [repeated MonitorDefinition](#monitordefinition) | none |
| monitors\_changes\_overview | [repeated ChangeOverview](#changeoverview) | none |
### ConfigsFilter
(synq.monitors.custom\_monitors.v1.ConfigsFilter)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
### ListConfigsMonitorsRequest
(synq.monitors.custom\_monitors.v1.ListConfigsMonitorsRequest)
| Field | Type | Description |
| ----------- | -------------------------- | ----------- |
| config\_ids | [repeated string](#string) | none |
### ListConfigsMonitorsResponse
(synq.monitors.custom\_monitors.v1.ListConfigsMonitorsResponse)
| Field | Type | Description |
| -------- | ------------------------------------------------ | ----------- |
| monitors | [repeated MonitorDefinition](#monitordefinition) | none |
### ListMonitorsRequest
(synq.monitors.custom\_monitors.v1.ListMonitorsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| integration\_ids | [repeated string](#string) | none |
| monitored\_asset\_paths | [repeated string](#string) | none |
| monitor\_ids | [repeated string](#string) | none |
| source | [repeated string](#string) | none |
| config\_ids | [repeated string](#string) | none |
| configs\_filter | [ ConfigsFilter](#configsfilter) | Filter SqlTests by config IDs. Pass `ConfigsFilter{ids: ["config1", "config2"]}` to filter by specific configs. If nil, no config\_id filtering is applied. If empty, the one with NULL config\_id will be excluded. |
| sources | [repeated Source](#source) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination |
### ListMonitorsResponse
(synq.monitors.custom\_monitors.v1.ListMonitorsResponse)
| Field | Type | Description |
| ---------- | ------------------------------------------------ | ------------------- |
| monitors | [repeated MonitorDefinition](#monitordefinition) | none |
| page\_info | [ PageInfo](#pageinfo) | Paging information. |
### BatchGetLatestEntityMetricsRequest
(synq.monitors.predictions.v1.BatchGetLatestEntityMetricsRequest)
| Field | Type | Description |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------ |
| synq\_paths | [repeated string](#string) | Entity synq\_paths to look up. Duplicates are allowed and de-duplicated server-side. |
### BatchGetLatestEntityMetricsResponse
(synq.monitors.predictions.v1.BatchGetLatestEntityMetricsResponse)
| Field | Type | Description |
| ---------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| latest\_by\_synq\_path | [map LatestBySynqPathEntry](#latestbysynqpathentry) | Latest observed data point keyed by the requested synq\_path. Entities with no recent sample are omitted — callers should treat a missing key as "no metrics available". |
### BatchGetLatestEntityMetricsResponse.LatestBySynqPathEntry
(synq.monitors.predictions.v1.BatchGetLatestEntityMetricsResponse.LatestBySynqPathEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ EntityMetricDataPoint](#entitymetricdatapoint) | none |
### GetEntityMetricsRequest
(synq.monitors.predictions.v1.GetEntityMetricsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------- |
| synq\_path | [ string](#string) | Entity synq\_path (table, view, or dbt model). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_from.from | [optional Timestamp](#timestamp) | Start of time range. Defaults to 30 days before `to`. Max lookback: 30 days. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_to.to | [optional Timestamp](#timestamp) | End of time range. Defaults to now. |
### GetEntityMetricsResponse
(synq.monitors.predictions.v1.GetEntityMetricsResponse)
| Field | Type | Description |
| ------------ | -------------------------------------------------------- | ----------- |
| data\_points | [repeated EntityMetricDataPoint](#entitymetricdatapoint) | none |
### GetMonitorPredictionsRequest
(synq.monitors.predictions.v1.GetMonitorPredictionsRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------- |
| synq\_path | [ string](#string) | Monitor synq\_path. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_metrics\_version.metrics\_version | [optional int32](#int32) | Metrics version. Defaults to the monitor's current version. |
| segments | [repeated string](#string) | Segment filters. If empty, all segments are returned. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_from.from | [optional Timestamp](#timestamp) | Start of time range. Defaults to 30 days before `to`. Max lookback: 30 days. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_to.to | [optional Timestamp](#timestamp) | End of time range. Defaults to now. |
### GetMonitorPredictionsResponse
(synq.monitors.predictions.v1.GetMonitorPredictionsResponse)
| Field | Type | Description |
| ----------- | ------------------------------------------------ | ----------- |
| predictions | [repeated MonitorPrediction](#monitorprediction) | none |
### EntityMetricDataPoint
(synq.monitors.predictions.v1.EntityMetricDataPoint)
Single observation of table-level metrics collected from the data warehouse.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------- |
| synq\_path | [ string](#string) | Entity synq\_path. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_num\_rows.num\_rows | [optional Int64Value](#int64value) | Row count. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_loaded\_at.last\_loaded\_at | [optional Timestamp](#timestamp) | Last loaded time as reported by the data warehouse. |
| scheduled\_at | [ Timestamp](#timestamp) | When the metric was scheduled for collection. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_snapshotted\_at.snapshotted\_at | [optional Timestamp](#timestamp) | Data warehouse snapshot time. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_size\_bytes.size\_bytes | [optional Int64Value](#int64value) | Physical size in bytes as reported by the data warehouse. |
### MonitorPrediction
(synq.monitors.predictions.v1.MonitorPrediction)
Single prediction data point from the anomaly detection model.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------- |
| field | [ string](#string) | Monitored field. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segment.segment | [optional string](#string) | Segment. |
| metric\_id | [ string](#string) | Metric identifier. |
| value | [ double](#double) | Observed value. |
| expected | [ double](#double) | Model's expected value. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_stddev.stddev | [optional double](#double) | Prediction standard deviation. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_upper\_bound.upper\_bound | [optional DoubleValue](#doublevalue) | Confidence band upper bound. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_lower\_bound.lower\_bound | [optional DoubleValue](#doublevalue) | Confidence band lower bound. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pattern.pattern | [optional string](#string) | Anomaly pattern (e.g., "spike", "drop"). |
| scheduled\_at | [ Timestamp](#timestamp) | When the prediction was scheduled. |
| is\_corrected | [ bool](#bool) | Whether a user has marked this prediction as expected behavior. |
### BatchDeleteDeploymentRulesRequest
(synq.monitors.automated\_monitors.v1.BatchDeleteDeploymentRulesRequest)
| Field | Type | Description |
| ----- | -------------------------- | ------------------------------------- |
| ids | [repeated string](#string) | IDs of the DeploymentRules to delete. |
### BatchDeleteDeploymentRulesResponse
(synq.monitors.automated\_monitors.v1.BatchDeleteDeploymentRulesResponse)
### BatchDeployDeploymentRulesRequest
(synq.monitors.automated\_monitors.v1.BatchDeployDeploymentRulesRequest)
| Field | Type | Description |
| ----------------- | ---------------------------------------------------------- | ---------------------------------- |
| deployment\_rules | [repeated MonitorsDeploymentRule](#monitorsdeploymentrule) | List of DeploymentRules to deploy. |
### BatchDeployDeploymentRulesResponse
(synq.monitors.automated\_monitors.v1.BatchDeployDeploymentRulesResponse)
| Field | Type | Description |
| ------------- | ------------------------------------ | ------------------------------------------------------------------------------- |
| deployed\_ids | [repeated string](#string) | IDs for which DeploymentRules were deployed without error. |
| errors | [repeated DeployError](#deployerror) | Errors raised while deploying. This list will be empty if there were no errors. |
### BatchDeployDeploymentRulesResponse.DeployError
(synq.monitors.automated\_monitors.v1.BatchDeployDeploymentRulesResponse.DeployError)
Details of errors encountered during the deploy operation.
| Field | Type | Description |
| ------ | ------------------ | ----------- |
| id | [ string](#string) | none |
| reason | [ string](#string) | none |
### BatchGetDeploymentRulesRequest
(synq.monitors.automated\_monitors.v1.BatchGetDeploymentRulesRequest)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
### BatchGetDeploymentRulesResponse
(synq.monitors.automated\_monitors.v1.BatchGetDeploymentRulesResponse)
| Field | Type | Description |
| ----------------- | ------------------------------------------------- | ----------- |
| deployment\_rules | [map DeploymentRulesEntry](#deploymentrulesentry) | none |
### BatchGetDeploymentRulesResponse.DeploymentRulesEntry
(synq.monitors.automated\_monitors.v1.BatchGetDeploymentRulesResponse.DeploymentRulesEntry)
| Field | Type | Description |
| ----- | ---------------------------------------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ MonitorsDeploymentRuleView](#monitorsdeploymentruleview) | none |
### BatchUpdateDeploymentRuleTitleRequest
(synq.monitors.automated\_monitors.v1.BatchUpdateDeploymentRuleTitleRequest)
| Field | Type | Description |
| ----------------- | ------------------------------------------------------------------------------ | ----------- |
| deployment\_rules | [repeated UpdateDeploymentRuleTitleRequest](#updatedeploymentruletitlerequest) | none |
### BatchUpdateDeploymentRuleTitleResponse
(synq.monitors.automated\_monitors.v1.BatchUpdateDeploymentRuleTitleResponse)
### BatchUpsertDeploymentRulesRequest
(synq.monitors.automated\_monitors.v1.BatchUpsertDeploymentRulesRequest)
| Field | Type | Description |
| ----------------- | ---------------------------------------------------------- | ---------------------------------- |
| deployment\_rules | [repeated MonitorsDeploymentRule](#monitorsdeploymentrule) | List of DeploymentRules to upsert. |
### BatchUpsertDeploymentRulesResponse
(synq.monitors.automated\_monitors.v1.BatchUpsertDeploymentRulesResponse)
| Field | Type | Description |
| ------------ | ------------------------------------ | ---------------------------------------------------------------------------- |
| created\_ids | [repeated string](#string) | IDs for which DeploymentRules were created without error. |
| updated\_ids | [repeated string](#string) | IDs for which DeploymentRules were updated without error. |
| errors | [repeated UpsertError](#upserterror) | Errors raised while upsert. This list will be empty if there were no errors. |
### BatchUpsertDeploymentRulesResponse.UpsertError
(synq.monitors.automated\_monitors.v1.BatchUpsertDeploymentRulesResponse.UpsertError)
Details of errors encountered during the upsert operation.
| Field | Type | Description |
| ------ | ------------------ | ----------- |
| id | [ string](#string) | none |
| reason | [ string](#string) | none |
### ConfigsFilter
(synq.monitors.automated\_monitors.v1.ConfigsFilter)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| ids | [repeated string](#string) | none |
### DeleteDeploymentRuleRequest
(synq.monitors.automated\_monitors.v1.DeleteDeploymentRuleRequest)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| id | [ string](#string) | none |
### DeleteDeploymentRuleResponse
(synq.monitors.automated\_monitors.v1.DeleteDeploymentRuleResponse)
### DeployDeploymentRuleRequest
(synq.monitors.automated\_monitors.v1.DeployDeploymentRuleRequest)
| Field | Type | Description |
| ---------------- | -------------------------------------------------- | ----------- |
| deployment\_rule | [ MonitorsDeploymentRule](#monitorsdeploymentrule) | none |
### DeployDeploymentRuleResponse
(synq.monitors.automated\_monitors.v1.DeployDeploymentRuleResponse)
### GetDeployDeleteOverviewRequest
(synq.monitors.automated\_monitors.v1.GetDeployDeleteOverviewRequest)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| id | [ string](#string) | none |
### GetDeployDeleteOverviewResponse
(synq.monitors.automated\_monitors.v1.GetDeployDeleteOverviewResponse)
| Field | Type | Description |
| -------- | ---------------------------------------------------------- | ----------- |
| overview | [ MonitorsDeploymentOverview](#monitorsdeploymentoverview) | none |
### GetDeployOverviewRequest
(synq.monitors.automated\_monitors.v1.GetDeployOverviewRequest)
| Field | Type | Description |
| ---------------- | -------------------------------------------------- | ----------- |
| deployment\_rule | [ MonitorsDeploymentRule](#monitorsdeploymentrule) | none |
### GetDeployOverviewResponse
(synq.monitors.automated\_monitors.v1.GetDeployOverviewResponse)
| Field | Type | Description |
| -------- | ---------------------------------------------------------- | ----------- |
| overview | [ MonitorsDeploymentOverview](#monitorsdeploymentoverview) | none |
### ListDeploymentRulesForAssetRequest
(synq.monitors.automated\_monitors.v1.ListDeploymentRulesForAssetRequest)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| asset\_path | [ string](#string) | none |
### ListDeploymentRulesForAssetResponse
(synq.monitors.automated\_monitors.v1.ListDeploymentRulesForAssetResponse)
| Field | Type | Description |
| ----------------- | ------------------------------------------------------------------ | ----------- |
| deployment\_rules | [repeated MonitorsDeploymentRuleView](#monitorsdeploymentruleview) | none |
### ListDeploymentRulesRequest
(synq.monitors.automated\_monitors.v1.ListDeploymentRulesRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| sources | [repeated Source](#source) | none |
| config\_ids | [repeated string](#string) | none |
| configs\_filter | [ ConfigsFilter](#configsfilter) | Filter SqlTests by config IDs. Pass `ConfigsFilter{ids: ["config1", "config2"]}` to filter by specific configs. If nil, no config\_id filtering is applied. If empty, the one with NULL config\_id will be excluded. |
| rule\_ids | [repeated string](#string) | none |
| rule\_types | [repeated DeploymentRuleType](#deploymentruletype) | Filter by rule type. When empty, rules of every type are returned. When set, only rules whose type is listed are returned (e.g. pass \[DEPLOYMENT\_RULE\_TYPE\_QUERY, DEPLOYMENT\_RULE\_TYPE\_PRODUCT] to exclude single-path rules). The filter is applied server-side before paging, so every page reflects only the selected types. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. An unset/zero page\_size applies the server default; the server never returns all rules in one response. Pass page\_info.last\_id from the previous response as the cursor to fetch the next page. |
### ListDeploymentRulesResponse
(synq.monitors.automated\_monitors.v1.ListDeploymentRulesResponse)
| Field | Type | Description |
| ----------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| deployment\_rules | [repeated MonitorsDeploymentRuleView](#monitorsdeploymentruleview) | none |
| page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. This response carries at most one bounded page of rules, never the full set. The cursor is the paging contract: to retrieve every rule, repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty. page\_info.count is the number of rules in this page. page\_info.total\_count is a best-effort total for the same filter, but it is deprecated — do not drive paging off it; loop on last\_id instead. |
### UpdateDeploymentRuleTitleRequest
(synq.monitors.automated\_monitors.v1.UpdateDeploymentRuleTitleRequest)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| id | [ string](#string) | none |
| title | [ string](#string) | none |
### UpsertDeploymentRuleRequest
(synq.monitors.automated\_monitors.v1.UpsertDeploymentRuleRequest)
| Field | Type | Description |
| ---------------- | -------------------------------------------------- | ----------- |
| deployment\_rule | [ MonitorsDeploymentRule](#monitorsdeploymentrule) | none |
### UpsertDeploymentRuleResponse
(synq.monitors.automated\_monitors.v1.UpsertDeploymentRuleResponse)
### AutomatedMonitorSettings
(synq.monitors.automated\_monitors.v1.AutomatedMonitorSettings)
| Field | Type | Description |
| --------------- | -------------------------------------- | --------------------------------- |
| severity | [ Severity](#severity) | none |
| sensitivity | [ Sensitivity](#sensitivity) | LEGACY - global sensitivity |
| metric\_ids | [repeated MetricId](#metricid) | LEGACY - which metrics to monitor |
| metric\_options | [repeated MetricOption](#metricoption) | NEW - per-metric sensitivity |
### CustomMonitorSettingsChange
(synq.monitors.automated\_monitors.v1.CustomMonitorSettingsChange)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ----------- |
| monitored\_asset\_path | [ string](#string) | none |
| original\_settings | [ AutomatedMonitorSettings](#automatedmonitorsettings) | none |
| new\_settings | [ AutomatedMonitorSettings](#automatedmonitorsettings) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_resolved\_freshness\_field.resolved\_freshness\_field | [optional string](#string) | none |
### EntitySelectionQuery
(synq.monitors.automated\_monitors.v1.EntitySelectionQuery)
| Field | Type | Description |
| ------- | -------------------------------- | ----------- |
| parts | [repeated QueryPart](#querypart) | none |
| operand | [ QueryOperand](#queryoperand) | none |
### EntitySelectionQuery.QueryPart
(synq.monitors.automated\_monitors.v1.EntitySelectionQuery.QueryPart)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.identifier\_list | [ IdentifierList](#identifierlist) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_name\_search | [ WithNameSearch](#withnamesearch) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_type | [ WithType](#withtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.with\_annotation | [ WithAnnotation](#withannotation) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.in\_folder | [ InFolder](#infolder) | synq.queries.v1.InDataPlatform in\_data\_platform = 5; |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.query | [ EntitySelectionQuery](#entityselectionquery) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) part.unsupported | [ Unsupported](#unsupported) | none |
### ExclusiveQueryConfig
(synq.monitors.automated\_monitors.v1.ExclusiveQueryConfig)
| Field | Type | Description |
| ---------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| query | [ EntitySelectionQuery](#entityselectionquery) | none |
| resolver\_ql | [ string](#string) | ResolverQL selection string for the exclusion set. Same semantics as QueryConfig.resolver\_ql: when set on write it takes precedence over `query`; on read it is echoed back VERBATIM for ResolverQL-authored rules and is empty for structured-`query` rules (whose ResolverQL form is in `rendered_resolver_ql`). `query` is always populated. |
| rendered\_resolver\_ql | [ string](#string) | Canonical ResolverQL rendering of the exclusion selection. Same semantics as QueryConfig.rendered\_resolver\_ql: OUTPUT ONLY, populated for every rule, ignored on write. |
### ExclusiveStaticConfig
(synq.monitors.automated\_monitors.v1.ExclusiveStaticConfig)
| Field | Type | Description |
| ----- | ------------------ | ----------- |
| path | [ string](#string) | none |
### MetricOption
(synq.monitors.automated\_monitors.v1.MetricOption)
| Field | Type | Description |
| ----------- | ---------------------------- | ----------- |
| sensitivity | [ Sensitivity](#sensitivity) | none |
| metric\_id | [ MetricId](#metricid) | none |
### MonitorSettingsChange
(synq.monitors.automated\_monitors.v1.MonitorSettingsChange)
| Field | Type | Description |
| ---------------------- | ------------------------------------------------------ | ----------- |
| monitored\_asset\_path | [ string](#string) | none |
| original\_settings | [ AutomatedMonitorSettings](#automatedmonitorsettings) | none |
| new\_settings | [ AutomatedMonitorSettings](#automatedmonitorsettings) | none |
### MonitorsDeploymentOverview
(synq.monitors.automated\_monitors.v1.MonitorsDeploymentOverview)
| Field | Type | Description |
| ---------------------------------- | -------------------------------------------------------------------- | ----------- |
| monitors\_to\_create\_for | [repeated string](#string) | none |
| monitors\_to\_delete\_for | [repeated string](#string) | none |
| active\_monitors\_for | [repeated string](#string) | none |
| monitor\_settings\_changes | [repeated MonitorSettingsChange](#monitorsettingschange) | none |
| custom\_monitors\_to\_create\_for | [repeated string](#string) | none |
| custom\_monitors\_to\_delete\_for | [repeated string](#string) | none |
| active\_custom\_monitors\_for | [repeated string](#string) | none |
| custom\_monitor\_settings\_changes | [repeated CustomMonitorSettingsChange](#custommonitorsettingschange) | none |
| skipped\_assets | [repeated SkippedAsset](#skippedasset) | none |
### MonitorsDeploymentRule
(synq.monitors.automated\_monitors.v1.MonitorsDeploymentRule)
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- |
| id | [ string](#string) | none |
| title | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.query\_config | [ QueryConfig](#queryconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_query\_config | [ ExclusiveQueryConfig](#exclusivequeryconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.static\_config | [ StaticConfig](#staticconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_static\_config | [ ExclusiveStaticConfig](#exclusivestaticconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.product\_config | [ ProductConfig](#productconfig) | none |
| source | [ Source](#source) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | none |
### MonitorsDeploymentRuleView
(synq.monitors.automated\_monitors.v1.MonitorsDeploymentRuleView)
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------- |
| id | [ string](#string) | none |
| title | [ string](#string) | none |
| monitor\_count | [ int32](#int32) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.query\_config | [ QueryConfig](#queryconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_query\_config | [ ExclusiveQueryConfig](#exclusivequeryconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.static\_config | [ StaticConfig](#staticconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_static\_config | [ ExclusiveStaticConfig](#exclusivestaticconfig) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.product\_config | [ ProductConfig](#productconfig) | none |
| source | [ Source](#source) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | none |
### ProductConfig
(synq.monitors.automated\_monitors.v1.ProductConfig)
| Field | Type | Description |
| ----------------------- | ---------------------------------------------------------------- | ----------- |
| product\_id | [ string](#string) | none |
| severity | [ Severity](#severity) | none |
| sensitivity | [ Sensitivity](#sensitivity) | none |
| metric\_ids | [repeated MetricId](#metricid) | none |
| upstream | [ ProductConfigUpstreamStrategy](#productconfigupstreamstrategy) | none |
| self | [ ProductConfigSelfStrategy](#productconfigselfstrategy) | none |
| keep\_deleted\_monitors | [ bool](#bool) | none |
| metric\_options | [repeated MetricOption](#metricoption) | NEW |
### ProductConfigSelfStrategy
(synq.monitors.automated\_monitors.v1.ProductConfigSelfStrategy)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.all | [ ProductConfigSelfStrategyAll](#productconfigselfstrategyall) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.selection | [ ProductConfigSelfStrategySelection](#productconfigselfstrategyselection) | none |
### ProductConfigSelfStrategyAll
(synq.monitors.automated\_monitors.v1.ProductConfigSelfStrategyAll)
### ProductConfigSelfStrategySelection
(synq.monitors.automated\_monitors.v1.ProductConfigSelfStrategySelection)
| Field | Type | Description |
| ----- | ---------------------------------------------- | ----------- |
| query | [ EntitySelectionQuery](#entityselectionquery) | none |
### ProductConfigUpstreamStrategy
(synq.monitors.automated\_monitors.v1.ProductConfigUpstreamStrategy)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.all | [ ProductConfigUpstreamStrategyAll](#productconfigupstreamstrategyall) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) strategy.sources | [ ProductConfigUpstreamStrategySources](#productconfigupstreamstrategysources) | none |
### ProductConfigUpstreamStrategyAll
(synq.monitors.automated\_monitors.v1.ProductConfigUpstreamStrategyAll)
### ProductConfigUpstreamStrategySources
(synq.monitors.automated\_monitors.v1.ProductConfigUpstreamStrategySources)
### QueryConfig
(synq.monitors.automated\_monitors.v1.QueryConfig)
| Field | Type | Description |
| ----------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| query | [ EntitySelectionQuery](#entityselectionquery) | none |
| severity | [ Severity](#severity) | none |
| sensitivity | [ Sensitivity](#sensitivity) | none |
| metric\_ids | [repeated MetricId](#metricid) | none |
| keep\_deleted\_monitors | [ bool](#bool) | none |
| metric\_options | [repeated MetricOption](#metricoption) | NEW - optional per-metric config |
| resolver\_ql | [ string](#string) | ResolverQL selection string — an advanced, more expressive alternative to `query`. ResolverQL is a superset of the structured `query`: use it for selections `query` cannot express (e.g. lineage walks, column predicates). When set (non-empty) on write, `resolver_ql` is the source of truth and the structured `query` is ignored. On read it is echoed back VERBATIM (exactly as written, not normalized) for rules authored via ResolverQL, and is empty for rules authored via the structured `query` — so writing a read response back unchanged preserves the rule's authored form (a structured rule stays structured rather than being silently rewritten to ResolverQL). To read the ResolverQL form of a structured rule, use `rendered_resolver_ql`. `query` is always populated regardless. |
| rendered\_resolver\_ql | [ string](#string) | Canonical ResolverQL rendering of this rule's selection, populated for every query rule regardless of how it was authored. OUTPUT ONLY — it is ignored on write; set `resolver_ql` to author a selection in ResolverQL. Use it to read the ResolverQL form of a rule authored via the structured `query`; for ResolverQL-authored rules it equals `resolver_ql`. Empty only for selections that have no ResolverQL representation. |
### SkippedAsset
(synq.monitors.automated\_monitors.v1.SkippedAsset)
| Field | Type | Description |
| ----------- | ------------------ | ----------- |
| asset\_path | [ string](#string) | none |
| reason | [ string](#string) | none |
### StaticConfig
(synq.monitors.automated\_monitors.v1.StaticConfig)
| Field | Type | Description |
| --------------- | -------------------------------------- | ----------- |
| path | [ string](#string) | none |
| severity | [ Severity](#severity) | none |
| sensitivity | [ Sensitivity](#sensitivity) | none |
| metric\_ids | [repeated MetricId](#metricid) | none |
| metric\_options | [repeated MetricOption](#metricoption) | NEW |
### IdentityRule
(synq.entities.identities.v2.IdentityRule)
IdentityRule declares how entities are recognized as the same logical entity.
A rule is evaluated against the current set of entities, so it automatically
applies to entities that appear after the rule is created. The `kind` field
selects the matching strategy and must be set to a supported rule type.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.prefix\_rewrite\_identity\_rule | [ PrefixRewriteIdentityRule](#prefixrewriteidentityrule) | none |
### PrefixRewriteIdentityRule
(synq.entities.identities.v2.PrefixRewriteIdentityRule)
PrefixRewriteIdentityRule treats two identifier prefixes as the same instance:
any entity whose identifier begins with source\_prefix is considered identical
to the entity with the same identifier under target\_prefix. The relationship
is bidirectional.
| Field | Type | Description |
| -------------- | ------------------ | ------------------------------------------------------------------------ |
| source\_prefix | [ string](#string) | Identifier prefix to match (for example, an instance or account prefix). |
| target\_prefix | [ string](#string) | Identifier prefix that matched entities are unified with. |
### GetCoverageRequest
(synq.entities.checks.v1.GetCoverageRequest)
GetCoverageRequest contains the parameters needed to retrieve check coverage for a specific entity.
| Field | Type | Description |
| ------------------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get checks coverage for. This can be a path identifier that uniquely identifies the entity in the system. |
| propagation\_filter | [ PropagationFilter](#propagationfilter) | Filter to control which checks are included in the coverage response. Default (UNSPECIFIED) returns both direct and propagated checks. |
### GetCoverageResponse
(synq.entities.checks.v1.GetCoverageResponse)
GetCoverageResponse contains the check coverage information for the requested entity.
| Field | Type | Description |
| -------- | -------------------------------- | ----------------------------------------------------------- |
| coverage | [ ChecksSummary](#checkssummary) | The complete coverage information for the requested entity. |
### GetCoverageResponse.ChecksSummary
(synq.entities.checks.v1.GetCoverageResponse.ChecksSummary)
ChecksSummary provides a comprehensive overview of checks and their coverage.
| Field | Type | Description |
| ------------------------- | ------------------------------------------------------ | ------------------------------------------------------------- |
| all\_columns | [repeated string](#string) | List of all column names in the entity. |
| table\_checks | [repeated CheckEntity](#checkentity) | List of table-level checks applied to this entity. |
| propagated\_table\_checks | [repeated PropagatedTableCheck](#propagatedtablecheck) | List of table-level checks propagated from upstream entities. |
| column\_info | [repeated ColumnInformation](#columninformation) | Detailed information about each column in the entity. |
### GetCoverageResponse.ChecksSummary.ColumnInformation
(synq.entities.checks.v1.GetCoverageResponse.ChecksSummary.ColumnInformation)
ColumnInformation contains detailed information about a specific column.
| Field | Type | Description |
| --------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------- |
| name | [ string](#string) | Human readable name of the column as present in dbt or data warehouse. |
| native\_type | [ string](#string) | Native data type of the column as present in data warehouse. |
| direct\_check\_entities | [repeated CheckEntity](#checkentity) | Checks running on current model on this column |
| propagated\_check\_entities | [repeated PropagatedColumnCheck](#propagatedcolumncheck) | Checks running on upstream model column, where this is a passthrough of it |
| is\_transformed | [ bool](#bool) | Indicates that there is an expression transforming the data |
| is\_renamed | [ bool](#bool) | Indicates that there is a rename operation |
| is\_passthrough | [ bool](#bool) | Indicates that there is no transformation or rename |
| used\_by\_downstream | [ bool](#bool) | Is this column used by any downstream model column |
| referenced\_by\_downstream | [ bool](#bool) | Is any downstream model referencing this column e.g. in WHERE |
| using\_upstream | [ bool](#bool) | Does this column pull any data from upstream |
| referencing\_upstream | [ bool](#bool) | Does this column reference any columns in upstream |
| downstream\_usage | [ ColumnUsage](#columnusage) | Statistics about column impact |
### GetCoverageResponse.ColumnUpstream
(synq.entities.checks.v1.GetCoverageResponse.ColumnUpstream)
ColumnUpstream represents an upstream column that a check is propagated from.
| Field | Type | Description |
| ------ | -------------------------- | ------------------------------------------ |
| id | [ Identifier](#identifier) | Identifier of the upstream entity. |
| column | [ string](#string) | Name of the column in the upstream entity. |
### GetCoverageResponse.ColumnUsage
(synq.entities.checks.v1.GetCoverageResponse.ColumnUsage)
ColumnUsage contains statistics about how a column is used by downstream entities.
| Field | Type | Description |
| --------------------------- | ---------------- | ------------------------------------------------------------------------------ |
| used\_as\_data\_direct | [ int32](#int32) | Number of times this column is directly used as data. |
| used\_as\_data\_cumulative | [ int32](#int32) | Total number of times this column is used as data (including indirect usage). |
| used\_as\_logic\_direct | [ int32](#int32) | Number of times this column is directly used in logic (e.g., WHERE clauses). |
| used\_as\_logic\_cumulative | [ int32](#int32) | Total number of times this column is used in logic (including indirect usage). |
### GetCoverageResponse.PropagatedColumnCheck
(synq.entities.checks.v1.GetCoverageResponse.PropagatedColumnCheck)
PropagatedColumnCheck represents a check that is propagated from an upstream column.
| Field | Type | Description |
| ----------- | ------------------------------------------ | ---------------------------------------------------------- |
| check | [ CheckEntity](#checkentity) | The check entity being propagated. |
| propagation | [repeated ColumnUpstream](#columnupstream) | List of upstream columns where this check originates from. |
### GetCoverageResponse.PropagatedColumnChecks
(synq.entities.checks.v1.GetCoverageResponse.PropagatedColumnChecks)
PropagatedColumnChecks contains a list of checks propagated from upstream columns.
| Field | Type | Description |
| ------ | -------------------------------------------------------- | --------------------------------- |
| checks | [repeated PropagatedColumnCheck](#propagatedcolumncheck) | List of propagated column checks. |
### GetCoverageResponse.PropagatedTableCheck
(synq.entities.checks.v1.GetCoverageResponse.PropagatedTableCheck)
PropagatedTableCheck represents a check that is propagated from an upstream table.
| Field | Type | Description |
| ------------- | ---------------------------------- | --------------------------------------------------------------------- |
| check | [ CheckEntity](#checkentity) | The check entity being propagated. |
| upstream\_ids | [repeated Identifier](#identifier) | List of upstream entity identifiers where this check originates from. |
### CheckCategory
(synq.entities.checks.v1.CheckCategory)
CheckCategory is the complete explicit category state for one check,
carrying both dimensions. It overrides the categories the
categorisation rules would otherwise compute for the check.
| Field | Type | Description |
| -------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------- |
| check\_path | [ string](#string) | check\_path of the check this applies to (matches the check's identifier in the catalogue). |
| category | [ string](#string) | Explicit structural category (empty = no explicit structural category; the rule-computed one is used instead). |
| governance\_category | [ string](#string) | Explicit governance category (empty = no explicit governance category; the rule-computed one is used instead). |
| actor\_identity | [ string](#string) | Identity of the actor that last set this category. Server-derived from the request context; ignored on input. |
| updated\_at | [ Timestamp](#timestamp) | When this category was last updated. Server-set; ignored on input. |
### DeleteCheckCategoriesRequest
(synq.entities.checks.v1.DeleteCheckCategoriesRequest)
| Field | Type | Description |
| ------------ | -------------------------- | --------------------------------------------------------------------------- |
| check\_paths | [repeated string](#string) | check\_paths whose explicit categories (both dimensions) should be cleared. |
### DeleteCheckCategoriesResponse
(synq.entities.checks.v1.DeleteCheckCategoriesResponse)
### ListCheckCategoriesRequest
(synq.entities.checks.v1.ListCheckCategoriesRequest)
### ListCheckCategoriesResponse
(synq.entities.checks.v1.ListCheckCategoriesResponse)
| Field | Type | Description |
| ---------- | ---------------------------------------- | ----------- |
| categories | [repeated CheckCategory](#checkcategory) | none |
### UpsertCheckCategoriesRequest
(synq.entities.checks.v1.UpsertCheckCategoriesRequest)
| Field | Type | Description |
| ---------- | ---------------------------------------- | ----------- |
| categories | [repeated CheckCategory](#checkcategory) | none |
### UpsertCheckCategoriesResponse
(synq.entities.checks.v1.UpsertCheckCategoriesResponse)
| Field | Type | Description |
| ---------- | ---------------------------------------- | ---------------------------------------------------------------- |
| categories | [repeated CheckCategory](#checkcategory) | Echoed categories with server-set actor\_identity / updated\_at. |
### CheckEntity
(synq.entities.checks.v1.CheckEntity)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| check\_id | [ Identifier](#identifier) | Identifier of the check |
| name | [ string](#string) | The name of the check |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_package.package | [optional string](#string) | The package of the check, e.g. "dbt", "sqlmesh", "dbt-utils" |
| kind | [ string](#string) | General kind of the test, e.g. "not\_null", "unique", "foreign\_key" |
| entity\_type | [ EntityType](#entitytype) | Entity type of the check itself, e.g. ENTITY\_TYPE\_DBT\_TEST. ENTITY\_TYPE\_UNSPECIFIED when the type is unknown. |
| data\_platform\_type | [ DataPlatformType](#dataplatformtype) | Platform the check runs on, e.g. DATA\_PLATFORM\_TYPE\_DBT. DATA\_PLATFORM\_TYPE\_UNSPECIFIED when the platform is unknown. |
| is\_platform\_native | [ bool](#bool) | Whether the check is platform native |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Explicit name of the structural category to use for this check |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Explicit name of the governance category to use for this check |
### DatabaseContext
(synq.entities.coordinates.v1.DatabaseContext)
DatabaseContext provides the default database execution context
for resolving unqualified references (e.g. table names in SQL).
| Field | Type | Description |
| -------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| instance\_name | [ string](#string) | Instance identifier (e.g. Snowflake account, Databricks workspace URL, BigQuery project) |
| database\_name | [ string](#string) | Database or catalog name |
| schema\_name | [ string](#string) | Schema name |
| object\_name | [ string](#string) | Object name (e.g. table or view name) that the SQL writes to or creates. Only set when the SQL defines or materializes an object, e.g. `CREATE TABLE AS SELECT ...`. Leave empty for read-only SQL such as dashboard queries or SELECT statements. |
### BatchDatabaseCoordinatesRequest
(synq.entities.coordinates.v1.BatchDatabaseCoordinatesRequest)
BatchGetEntitiesRequest is the request message for the BatchGetEntities method.
| Field | Type | Description |
| ----- | ---------------------------------- | ----------------------------------- |
| ids | [repeated Identifier](#identifier) | Identifiers of the entities to get. |
### BatchDatabaseCoordinatesResponse
(synq.entities.coordinates.v1.BatchDatabaseCoordinatesResponse)
BatchGetEntitiesResponse is the response message for the BatchGetEntities method.
| Field | Type | Description |
| ----------- | ---------------------------------------------------- | --------------------------------- |
| coordinates | [repeated DatabaseCoordinates](#databasecoordinates) | The entities that were retrieved. |
### BatchIdsByCoordinatesRequest
(synq.entities.coordinates.v1.BatchIdsByCoordinatesRequest)
| Field | Type | Description |
| -------- | -------------------------- | ------------------------------------------------------------------- |
| sql\_fqn | [repeated string](#string) | Databases coordinates as present in the SQL, e.g. `db.schema.table` |
### BatchIdsByCoordinatesResponse
(synq.entities.coordinates.v1.BatchIdsByCoordinatesResponse)
| Field | Type | Description |
| -------------------- | -------------------------------------------------- | ----------- |
| matched\_coordinates | [repeated MatchedCoordinates](#matchedcoordinates) | none |
### BatchIdsByCoordinatesResponse.MatchedCoordinates
(synq.entities.coordinates.v1.BatchIdsByCoordinatesResponse.MatchedCoordinates)
| Field | Type | Description |
| ---------- | ---------------------------------------------------- | ----------- |
| sql\_fqn | [ string](#string) | none |
| candidates | [repeated DatabaseCoordinates](#databasecoordinates) | none |
### DatabaseCoordinates
(synq.entities.coordinates.v1.DatabaseCoordinates)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| identifiers | [repeated Identifier](#identifier) | none |
| synq\_paths | [repeated string](#string) | none |
| dialect\_name | [ string](#string) | none |
| dialect | [ SqlDialect](#sqldialect) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_data\_platform.data\_platform | [optional DataPlatformIdentifier](#dataplatformidentifier) | none |
| data\_platform\_type | [ DataPlatformType](#dataplatformtype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_connection\_id.connection\_id | [optional string](#string) | none |
| instance\_name | [ string](#string) | none |
| database\_name | [ string](#string) | none |
| schema\_name | [ string](#string) | none |
| object\_name | [ string](#string) | none |
| sql\_fqn | [ string](#string) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sql\_database\_name.sql\_database\_name | [optional string](#string) | SQL-addressable components (only parts usable in SQL queries). For Postgres, sql\_database\_name is empty since cross-database queries are not supported. |
| sql\_schema\_name | [ string](#string) | none |
| sql\_object\_name | [ string](#string) | none |
### Type
(synq.entities.v1.Type)
Custom entity type that is used to categorize custom entities.
| Field | Type | Description |
| ------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Immutable workspace identifier that this custom entity type belongs to. |
| type\_id | [ int32](#int32) | none |
| name | [ string](#string) | Name of the custom entity type that is displayed to the user. |
| svg\_icon | [ bytes](#bytes) | SVG icon of the custom entity type that is displayed to the user. |
| svg\_icon\_id | [ string](#string) | Coalesce Quality identifier used for CDN purposes, read-only. |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the custom entity type was created. |
| updated\_at | [ Timestamp](#timestamp) | Timestamp when the custom entity type was last updated. |
| deleted\_at | [ Timestamp](#timestamp) | Timestamp when the custom entity type was deleted. If this is set, the custom entity type is considered deleted. |
| traits | [ TypeTraits](#typetraits) | Behavioral traits declared on this type. Every entity of the type inherits them: declaring is\_model, for example, makes its entities rank and behave as transformation models (canonical-entity ranking, monitorability, lineage), the same way a dbt model does. Unset means no declared traits (all false). |
### TypeTraits
(synq.entities.v1.TypeTraits)
TypeTraits are the behavioral traits a custom entity Type can declare.
Declaring a trait makes every entity of that type behave platform-wide as if
it carried the trait natively (e.g. is\_model => transformation-model ranking,
monitorability and lineage).
Every field is `optional` so an unset trait means "not declared, fall through
to the trait default" — distinct from an explicit `false`. An unset/nil message
means no declared traits (every trait at its default).
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_model.is\_model | [optional bool](#bool) | model-like: the dbt-model / Coalesce-node / SQLMesh-model analog. Default when unset: false. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_source.is\_source | [optional bool](#bool) | source-like: an external/raw input to the transformation graph. Default when unset: false. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_bi\_like.is\_bi\_like | [optional bool](#bool) | BI-like: a dashboard, report or other business-intelligence artifact. Default when unset: false. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_test\_type.is\_test\_type | [optional bool](#bool) | check-like: pairs with declarative checks. Default when unset: false. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_ignored\_in\_lineage.is\_ignored\_in\_lineage | [optional bool](#bool) | excluded from lineage rendering. Default when unset: false. |
### Annotation
(synq.entities.v1.Annotation)
Annotations can be used to annotate any entity with a key:value pair.
These annotations can be used for filtering and searching entities.
| Field | Type | Description |
| ------ | -------------------------- | ------------------------------------------------------ |
| name | [ string](#string) | String key for the annotation. |
| values | [repeated string](#string) | Optional list of values that the annotation can carry. |
### EntityChange
(synq.entities.v1.EntityChange)
EntityChange represents a change detected in an entity within the system.
It tracks modifications to entities like Git commits, SQL definitions, and database schemas.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ |
| entity\_id | [ Identifier](#identifier) | Identifier of the entity on which the change was detected when available. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entity\_synq\_path.entity\_synq\_path | [optional string](#string) | Coalesce Quality path representing entity on which the change was detected when available, |
| affected\_entities | [repeated Identifier](#identifier) | Identifiers of entities directly affected by this change. |
| affected\_entities\_synq\_paths | [repeated string](#string) | Coalesce Quality paths of entities directly affected by this change. |
| change\_id | [ string](#string) | Internal identifier of the change event. |
| change\_detected\_at | [ Timestamp](#timestamp) | Timestamp when the change was detected by Coalesce Quality. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) change\_type.git\_commit | [ GitCommitChange](#gitcommitchange) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) change\_type.sql\_definition | [ SqlDefinitionChange](#sqldefinitionchange) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) change\_type.schema | [ SchemaChange](#schemachange) | none |
### GitCommitChange
(synq.entities.v1.GitCommitChange)
GitCommitChange represents a change detected in a Git repository.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| hash | [ string](#string) | Hash of the Git commit. |
| author | [ Signature](#signature) | Author information of the Git commit. |
| committer | [ Signature](#signature) | Committer information of the Git commit. |
| message | [ string](#string) | Commit message describing the changes. |
| short\_message | [ string](#string) | First non-empty line of the message |
| file\_change\_stats | [map FileChangeStatsEntry](#filechangestatsentry) | Statistics about changes made to each modified file. |
| changed\_file\_paths | [repeated string](#string) | All file paths changed in this commit (complete list). For commits with many files, this may be a large array. |
| related\_changed\_file\_paths | [repeated string](#string) | File paths that directly affect the queried entity (filtered subset of changed\_file\_paths). When querying changes for a specific entity (e.g., dbt model "customers"), this contains only the files that directly impact that entity (e.g., "models/customers.sql", "models/staging/stg\_customers.sql"). Empty when retrieving a change by change\_id directly (not scoped to a specific entity). Empty when it's impossible to determine entity-specific file mappings. Example: If a commit changes 50 files but only 2 affect your queried dbt model, this contains those 2 files. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_branch\_name.branch\_name | [optional string](#string) | Name of the branch associated with the commit, if any. |
| clone\_url | [ string](#string) | URL of the Git repository where the commit was made. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_web\_commit\_url.web\_commit\_url | [optional string](#string) | URL to e.g. Github which opens the Commit |
| directory\_changes | [repeated DirectoryChangeSummary](#directorychangesummary) | Hierarchical directory summaries showing where changes occurred. |
| changes\_by\_file\_type | [map ChangesByFileTypeEntry](#changesbyfiletypeentry) | Aggregated statistics by file type/extension. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_statistics.statistics | [optional ChangeStatistics](#changestatistics) | Overall statistical summary of the commit. |
### GitCommitChange.ChangeStatistics
(synq.entities.v1.GitCommitChange.ChangeStatistics)
ChangeStatistics provides statistical summaries of the entire commit.
| Field | Type | Description |
| --------------------- | -------------------------------------------------- | ------------------------------------- |
| total\_files | [ int32](#int32) | Total number of files changed. |
| total\_lines\_added | [ int32](#int32) | Total lines added across all files. |
| total\_lines\_removed | [ int32](#int32) | Total lines removed across all files. |
| distribution | [ FileChangeDistribution](#filechangedistribution) | Distribution of changes by magnitude. |
| top\_changes | [repeated TopChange](#topchange) | Top 10 files by total lines changed. |
### GitCommitChange.ChangeStats
(synq.entities.v1.GitCommitChange.ChangeStats)
ChangeStats contains statistics about changes made to a single file.
| Field | Type | Description |
| --------- | ---------------- | -------------------------------------- |
| additions | [ int32](#int32) | Number of lines added to the file. |
| deletions | [ int32](#int32) | Number of lines removed from the file. |
### GitCommitChange.ChangesByFileTypeEntry
(synq.entities.v1.GitCommitChange.ChangesByFileTypeEntry)
| Field | Type | Description |
| ----- | ------------------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ FileTypeChangeSummary](#filetypechangesummary) | none |
### GitCommitChange.DirectoryChangeSummary
(synq.entities.v1.GitCommitChange.DirectoryChangeSummary)
DirectoryChangeSummary provides hierarchical directory-level statistics.
| Field | Type | Description |
| --------------------- | ---------------------------------------------------------- | --------------------------------------------------------------------- |
| directory\_path | [ string](#string) | Path of the directory. |
| files\_changed | [ int32](#int32) | Number of files changed in this directory (excluding subdirectories). |
| total\_lines\_added | [ int32](#int32) | Total lines added in this directory (excluding subdirectories). |
| total\_lines\_removed | [ int32](#int32) | Total lines removed in this directory (excluding subdirectories). |
| subdirs | [repeated DirectoryChangeSummary](#directorychangesummary) | Subdirectory summaries. |
| top\_files | [repeated TopFileChange](#topfilechange) | Top 3-5 most significant file changes in this directory. |
### GitCommitChange.FileChangeDistribution
(synq.entities.v1.GitCommitChange.FileChangeDistribution)
FileChangeDistribution categorizes files by change magnitude.
| Field | Type | Description |
| ---------------------------- | ---------------- | --------------------------------------- |
| files\_with\_small\_changes | [ int32](#int32) | Files with fewer than 10 lines changed. |
| files\_with\_medium\_changes | [ int32](#int32) | Files with 10-100 lines changed. |
| files\_with\_large\_changes | [ int32](#int32) | Files with more than 100 lines changed. |
| files\_added | [ int32](#int32) | Files that were newly added. |
| files\_modified | [ int32](#int32) | Files that were modified. |
| files\_deleted | [ int32](#int32) | Files that were deleted. |
### GitCommitChange.FileChangeStatsEntry
(synq.entities.v1.GitCommitChange.FileChangeStatsEntry)
| Field | Type | Description |
| ----- | ---------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ ChangeStats](#changestats) | none |
### GitCommitChange.FileTypeChangeSummary
(synq.entities.v1.GitCommitChange.FileTypeChangeSummary)
FileTypeChangeSummary aggregates changes by file type/extension.
| Field | Type | Description |
| --------------------- | -------------------------- | ------------------------------------------------------------------ |
| file\_extension | [ string](#string) | File extension (e.g., ".sql", ".py", ".yml"). |
| files\_count | [ int32](#int32) | Number of files with this extension that were changed. |
| total\_lines\_added | [ int32](#int32) | Total lines added across all files of this type. |
| total\_lines\_removed | [ int32](#int32) | Total lines removed across all files of this type. |
| example\_files | [repeated string](#string) | Example file paths (up to 5) showing where these changes occurred. |
| common\_directories | [repeated string](#string) | Common directories where files of this type were modified. |
### GitCommitChange.Signature
(synq.entities.v1.GitCommitChange.Signature)
Signature contains information about the Git user who made the changes.
| Field | Type | Description |
| ----------- | ------------------------ | ----------------------------------------- |
| name | [ string](#string) | Name of the Git user. |
| email | [ string](#string) | Email address of the Git user. |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the signature was created. |
### GitCommitChange.TopChange
(synq.entities.v1.GitCommitChange.TopChange)
TopChange represents one of the most significant file changes.
| Field | Type | Description |
| --------------------- | ------------------ | -------------------------------------- |
| file\_path | [ string](#string) | Path of the file. |
| lines\_added | [ int32](#int32) | Lines added. |
| lines\_removed | [ int32](#int32) | Lines removed. |
| total\_lines\_changed | [ int32](#int32) | Total lines changed (added + removed). |
### GitCommitChange.TopFileChange
(synq.entities.v1.GitCommitChange.TopFileChange)
TopFileChange represents a significant file change within a directory.
| Field | Type | Description |
| -------------- | ------------------ | ------------------------------------------- |
| file\_path | [ string](#string) | Path of the file relative to the directory. |
| lines\_added | [ int32](#int32) | Number of lines added. |
| lines\_removed | [ int32](#int32) | Number of lines removed. |
### SchemaChange
(synq.entities.v1.SchemaChange)
SchemaChange represents a change detected in a database schema.
| Field | Type | Description |
| --------------- | -------------------------------------------------- | --------------------------------------------------------- |
| column\_changes | [repeated SchemaColumnChange](#schemacolumnchange) | List of changes made to individual columns in the schema. |
### SchemaColumnChange
(synq.entities.v1.SchemaColumnChange)
SchemaColumnChange represents a specific change to a column in the schema.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) column\_change.column\_addition | [ ColumnAdditionChangeType](#columnadditionchangetype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) column\_change.column\_native\_type | [ ColumnNativeTypeChangeType](#columnnativetypechangetype) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) column\_change.column\_removal | [ ColumnRemovalChangeType](#columnremovalchangetype) | none |
### SchemaColumnChange.ColumnAdditionChangeType
(synq.entities.v1.SchemaColumnChange.ColumnAdditionChangeType)
ColumnAdditionChangeType represents the addition of a new column to the schema.
| Field | Type | Description |
| ----------------- | ------------------ | -------------------------------------------------- |
| column\_id | [ string](#string) | Identifier of the new column. |
| native\_type | [ string](#string) | Data type of the new column. |
| ordinal\_position | [ int32](#int32) | Position where the column was added in the schema. |
### SchemaColumnChange.ColumnNativeTypeChangeType
(synq.entities.v1.SchemaColumnChange.ColumnNativeTypeChangeType)
ColumnNativeTypeChangeType represents a change in a column's data type.
| Field | Type | Description |
| ---------------------- | ------------------ | ---------------------------------- |
| column\_id | [ string](#string) | Identifier of the modified column. |
| previous\_native\_type | [ string](#string) | Previous data type of the column. |
| current\_native\_type | [ string](#string) | New data type of the column. |
### SchemaColumnChange.ColumnRemovalChangeType
(synq.entities.v1.SchemaColumnChange.ColumnRemovalChangeType)
ColumnRemovalChangeType represents the removal of a column from the schema.
| Field | Type | Description |
| ----------------- | ------------------ | ---------------------------------------------- |
| column\_id | [ string](#string) | Identifier of the removed column. |
| native\_type | [ string](#string) | Native data type of the removed column. |
| ordinal\_position | [ int32](#int32) | Original position of the column in the schema. |
### SqlDefinitionChange
(synq.entities.v1.SqlDefinitionChange)
SqlDefinitionChange represents a change detected in a SQL definition.
| Field | Type | Description |
| ------------------------ | ------------------------ | ---------------------------------------------------------- |
| previous\_sql | [ string](#string) | Previous version of the SQL definition. |
| previous\_sql\_state\_at | [ Timestamp](#timestamp) | Timestamp when the previous SQL state was valid. |
| current\_sql | [ string](#string) | Current version of the SQL definition. |
| current\_sql\_state\_at | [ Timestamp](#timestamp) | Timestamp when the current SQL state became valid. |
| sql\_diff | [ string](#string) | Diff showing the changes between previous and current SQL. |
### Entity
(synq.entities.v1.Entity)
Entity is the base type for all entities in the system. Its always attached to a given
client workspace and can be uniquely identified by its id.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Immutable workspace identifier that this entity belongs to. |
| id | [ Identifier](#identifier) | Unique identifier for this entity. |
| type\_id | [ int32](#int32) | Id of custom type or default type when 0, ignored for non-custom entities |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entity\_type.entity\_type | [optional EntityType](#entitytype) | Information about entity type |
| name | [ string](#string) | Name of the entity that is displayed to the user. |
| description | [ string](#string) | Description of the entity that is displayed in relevant contexts. Can contain Markdown. |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the entity was created. |
| updated\_at | [ Timestamp](#timestamp) | Timestamp when the entity was last updated. |
| deleted\_at | [ Timestamp](#timestamp) | Timestamp when the entity was deleted. If this is set, the entity is considered deleted. |
| synq\_path | [ string](#string) | Return only value. Coalesce Quality Path to the entity. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| synq\_catalog\_url | [ string](#string) | Return only value. Coalesce Quality URL to the entity. This is a unique URL that can be used to access the entity in the Coalesce Quality UI. |
| ids | [repeated Identifier](#identifier) | Return only value. All identifiers of entities which are tightly related |
| synq\_paths | [repeated string](#string) | Return only value. Coalesce Quality Path to the all identifiers of entities which are tightly related |
| annotations | [repeated Annotation](#annotation) | Annotations attached to the entity. Annotations are key-value pairs that can be used to store metadata about the entity. |
| is\_dwh\_table | [ bool](#bool) | none |
| is\_dwh\_view | [ bool](#bool) | none |
### AirflowDagIdentifier
(synq.entities.v1.AirflowDagIdentifier)
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Coalesce Quality integration\_id that identifies the Airflow instance |
| dag\_id | [ string](#string) | Airflow dag\_id that identifies the DAG |
### AirflowTaskIdentifier
(synq.entities.v1.AirflowTaskIdentifier)
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Coalesce Quality integration\_id that identifies the Airflow instance |
| dag\_id | [ string](#string) | Airflow dag\_id that identifies the DAG |
| task\_id | [ string](#string) | Airflow task\_id that identifies the task within the DAG |
### AthenaTableIdentifier
(synq.entities.v1.AthenaTableIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| instance | [ string](#string) | AWS account and region the Athena workgroup runs in, formatted as "\.\" (e.g. "123456789012.eu-west-1"). Auto-derived from sts:GetCallerIdentity at integration setup time. |
| catalog | [ string](#string) | Glue Data Catalog name. Almost always "AwsDataCatalog" — the default catalog for Athena unless the customer registered a federated catalog. |
| database | [ string](#string) | Glue database (the namespace users typically filter on). |
| table | [ string](#string) | Glue table or view name. |
### BigqueryTableIdentifier
(synq.entities.v1.BigqueryTableIdentifier)
| Field | Type | Description |
| ------- | ------------------ | ------------------- |
| project | [ string](#string) | BigQuery project |
| dataset | [ string](#string) | BigQuery dataset id |
| table | [ string](#string) | BigQuery table name |
### ClickhouseTableIdentifier
(synq.entities.v1.ClickhouseTableIdentifier)
| Field | Type | Description |
| ------ | ------------------ | -------------------------------- |
| host | [ string](#string) | Clickhouse hostname without port |
| schema | [ string](#string) | Clickhouse database |
| table | [ string](#string) | Clickhouse table |
### CustomIdentifier
(synq.entities.v1.CustomIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Id that identifies the custom entity The Id should be unique within the custom entity Identifier. |
### DatabricksTableIdentifier
(synq.entities.v1.DatabricksTableIdentifier)
| Field | Type | Description |
| --------- | ------------------ | --------------------------- |
| workspace | [ string](#string) | URL of Databricks workspace |
| catalog | [ string](#string) | Databricks catalog |
| schema | [ string](#string) | Databricks schema |
| table | [ string](#string) | Databricks table or view |
### DataproductIdentifier
(synq.entities.v1.DataproductIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ---------------------------------------------- |
| id | [ string](#string) | Dataproduct id that identifies the Dataproduct |
### DbtCloudNodeIdentifier
(synq.entities.v1.DbtCloudNodeIdentifier)
| Field | Type | Description |
| ----------- | ------------------ | -------------------------------------------------------------------- |
| project\_id | [ string](#string) | Your dbt Cloud project id |
| account\_id | [ string](#string) | Your dbt Cloud account id |
| node\_id | [ string](#string) | Dbt node\_id that identifies one of dbt DAG nodes (model, test, etc) |
### DbtCoreNodeIdentifier
(synq.entities.v1.DbtCoreNodeIdentifier)
| Field | Type | Description |
| --------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Opaque identifier of the dbt Core project. Usually the Coalesce Quality integration id (a UUID), but may also be the dbt project name from manifest.json when the integration is configured to identify assets by project name. Treat it as an opaque string, not a UUID. |
| node\_id | [ string](#string) | Dbt node\_id that identifies one of dbt DAG nodes (model, test, etc) |
### FabricTableIdentifier
(synq.entities.v1.FabricTableIdentifier)
Microsoft Fabric warehouse/lakehouse table identifier. Fabric is
workspace-scoped with cross-database three-part \[database].\[schema].\[table]
T-SQL names.
| Field | Type | Description |
| ------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| instance | [ string](#string) | Workspace SQL analytics endpoint host, e.g. "\.datawarehouse.fabric.microsoft.com". |
| database | [ string](#string) | Fabric warehouse / lakehouse (database). |
| schema | [ string](#string) | Schema within the database. |
| table | [ string](#string) | Table or view name. |
| workspace\_id | [ string](#string) | Fabric workspace GUID, decoded from the endpoint host in `instance`. Optional and informational: the table is addressed by instance/database/schema/table, so leave it empty if you don't have it — it does not affect how the identifier resolves. |
| tenant\_id | [ string](#string) | Entra (Azure AD) tenant GUID, decoded from the endpoint host in `instance`. Optional and informational, like workspace\_id. |
### Identifier
(synq.entities.v1.Identifier)
Identifier is a unique reference to an entity in Coalesce Quality system. Entity identifiers
are designed to closely mimic identifiers used by data platforms and tools. To construct
an identifier, you need to know the kind of the entity and the ids that you would normally
use to identify it in the data platform or tool. For example, to identify a table in BigQuery,
you would need to know the project, dataset, and table names.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.dbt\_core\_node | [ DbtCoreNodeIdentifier](#dbtcorenodeidentifier) | Dbt node that identifies one of dbt DAG nodes (model, test, etc) in dbt Core project |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.dbt\_cloud\_node | [ DbtCloudNodeIdentifier](#dbtcloudnodeidentifier) | Dbt node that identifies one of dbt DAG nodes (model, test, etc) in dbt Cloud project |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.bigquery\_table | [ BigqueryTableIdentifier](#bigquerytableidentifier) | BigQuery table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.snowflake\_table | [ SnowflakeTableIdentifier](#snowflaketableidentifier) | Snowflake table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.redshift\_table | [ RedshiftTableIdentifier](#redshifttableidentifier) | Redshift table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.postgres\_table | [ PostgresTableIdentifier](#postgrestableidentifier) | Postgres table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.mysql\_table | [ MysqlTableIdentifier](#mysqltableidentifier) | Mysql table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.clickhouse\_table | [ ClickhouseTableIdentifier](#clickhousetableidentifier) | Clickhouse table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.airflow\_dag | [ AirflowDagIdentifier](#airflowdagidentifier) | Airflow DAG identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.airflow\_task | [ AirflowTaskIdentifier](#airflowtaskidentifier) | Airflow task identifier within a given DAG |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.custom | [ CustomIdentifier](#customidentifier) | Custom identifier to be used with all custom created entities |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.dataproduct | [ DataproductIdentifier](#dataproductidentifier) | Dataproduct identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.synq\_path | [ SynqPathIdentifier](#synqpathidentifier) | SynqPath identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.databricks\_table | [ DatabricksTableIdentifier](#databrickstableidentifier) | Databricks table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.trino\_table | [ TrinoTableIdentifier](#trinotableidentifier) | Trino table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.sql\_mesh\_model | [ SqlMeshModelIdentifier](#sqlmeshmodelidentifier) | SQLMesh Model identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.sql\_mesh\_audit | [ SqlMeshAuditIdentifier](#sqlmeshauditidentifier) | SQLMesh Audit identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.monitor | [ MonitorIdentifier](#monitoridentifier) | Monitor identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.mssql\_table | [ MssqlTableIdentifier](#mssqltableidentifier) | SQL Server table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.oracle\_table | [ OracleTableIdentifier](#oracletableidentifier) | Oracle table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.athena\_table | [ AthenaTableIdentifier](#athenatableidentifier) | Amazon Athena (Glue) table identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.saved\_view | [ SavedViewIdentifier](#savedviewidentifier) | Saved view identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.fabric\_table | [ FabricTableIdentifier](#fabrictableidentifier) | Microsoft Fabric table identifier |
### MonitorIdentifier
(synq.entities.v1.MonitorIdentifier)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------ |
| monitored\_id | [ Identifier](#identifier) | Identifier of the monitored entity |
| monitor\_id | [ string](#string) | Identifier of the monitor |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_segment.segment | [optional string](#string) | Optional monitor segmentation identifier |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Coalesce Quality integration\_id of the monitored identifier |
### MssqlTableIdentifier
(synq.entities.v1.MssqlTableIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ----------------------------------- |
| host | [ string](#string) | Hostname of the SQL Server instance |
| database | [ string](#string) | SQL Server database |
| schema | [ string](#string) | SQL Server schema (e.g. "dbo") |
| table | [ string](#string) | SQL Server table or view |
### MysqlTableIdentifier
(synq.entities.v1.MysqlTableIdentifier)
| Field | Type | Description |
| ------ | ------------------ | --------------------------- |
| host | [ string](#string) | Mysql hostname without port |
| schema | [ string](#string) | Mysql database |
| table | [ string](#string) | Mysql table |
### OracleTableIdentifier
(synq.entities.v1.OracleTableIdentifier)
| Field | Type | Description |
| ------------- | ------------------ | ------------------------------- |
| host | [ string](#string) | Hostname of the Oracle instance |
| service\_name | [ string](#string) | Oracle service name (PDB) |
| schema | [ string](#string) | Oracle schema (= owning user) |
| table | [ string](#string) | Oracle table or view |
### OwnerIdentifier
(synq.entities.v1.OwnerIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ---------------------------------- |
| id | [ string](#string) | Owner id that identifies the Owner |
### PostgresTableIdentifier
(synq.entities.v1.PostgresTableIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ------------------------------ |
| host | [ string](#string) | Postgres hostname without port |
| database | [ string](#string) | Postgres database |
| schema | [ string](#string) | Postgres schema |
| table | [ string](#string) | Postgres table |
### RedshiftTableIdentifier
(synq.entities.v1.RedshiftTableIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ----------------- |
| cluster | [ string](#string) | Redshift cluster |
| database | [ string](#string) | Redshift database |
| schema | [ string](#string) | Redshift schema |
| table | [ string](#string) | Redshift table |
### SavedViewIdentifier
(synq.entities.v1.SavedViewIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ------------------------------------------------------------------- |
| id | [ string](#string) | Saved view id (client-supplied UUID) that identifies the saved view |
### SnowflakeTableIdentifier
(synq.entities.v1.SnowflakeTableIdentifier)
| Field | Type | Description |
| -------- | ------------------ | ------------------ |
| account | [ string](#string) | Snowflake account |
| database | [ string](#string) | Snowflake database |
| schema | [ string](#string) | Snowflake schema |
| table | [ string](#string) | Snowflake table |
### SqlMeshAuditIdentifier
(synq.entities.v1.SqlMeshAuditIdentifier)
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Coalesce Quality integration\_id that identifies the dbt Core project |
| fqn | [ string](#string) | SQLMesh model fully qualified name |
| audit\_id | [ string](#string) | Identifier of the audit |
### SqlMeshModelIdentifier
(synq.entities.v1.SqlMeshModelIdentifier)
| Field | Type | Description |
| --------------- | ------------------ | --------------------------------------------------------------------- |
| integration\_id | [ string](#string) | Coalesce Quality integration\_id that identifies the dbt Core project |
| fqn | [ string](#string) | SQLMesh model fully qualified name |
### SynqPathIdentifier
(synq.entities.v1.SynqPathIdentifier)
| Field | Type | Description |
| ----- | ------------------ | ----------------------------------------------------------------------------------------------------- |
| path | [ string](#string) | Coalesce Quality path that identifies the Coalesce Quality entity, needs to be one of supported paths |
### TrinoTableIdentifier
(synq.entities.v1.TrinoTableIdentifier)
| Field | Type | Description |
| ------- | ------------------ | ------------------------------ |
| host | [ string](#string) | Hostname of the Trino instance |
| catalog | [ string](#string) | Trino catalog |
| schema | [ string](#string) | Trino schema |
| table | [ string](#string) | Trino table or view |
### ForeignKeyReference
(synq.entities.v1.ForeignKeyReference)
ForeignKeyReference describes the target of a foreign key constraint.
| Field | Type | Description |
| -------- | -------------------------- | ------------------------------------------- |
| database | [ string](#string) | Target database name |
| schema | [ string](#string) | Target schema name |
| table | [ string](#string) | Target table name |
| columns | [repeated string](#string) | Target column names in the referenced table |
### TableConstraint
(synq.entities.v1.TableConstraint)
TableConstraint represents a single constraint or index on a database table.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | [ string](#string) | Name of the constraint or index |
| type | [ TableConstraintType](#tableconstrainttype) | Type of the constraint (best-effort mapping to enum) |
| columns | [repeated string](#string) | Column names involved in this constraint or index |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_foreign\_key\_reference.foreign\_key\_reference | [optional ForeignKeyReference](#foreignkeyreference) | Foreign key reference details (only set when type is FOREIGN\_KEY) |
| index\_type | [ string](#string) | Index type (e.g. "btree", "hash", "gin", "gist") - only relevant for INDEX type |
| expression | [ string](#string) | Expression for check constraints or expression-based indexes |
| is\_unique | [ bool](#bool) | Whether this constraint or index enforces uniqueness |
| raw\_type | [ string](#string) | Raw constraint type string from the data warehouse (e.g. "PRIMARY KEY", "SORTING KEY", "PARTITION BY", "CLUSTER BY", "DISTRIBUTION KEY", "PROJECTION", "INDEX", "UNIQUE INDEX"). Preserved verbatim for consumers that need platform-specific details beyond the enum. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_enforced.is\_enforced | [optional bool](#bool) | Whether this constraint is enforced by the database. nil/unset = unknown, true = enforced, false = not enforced (e.g. Snowflake NORELY, Oracle DISABLED). |
### FolderRef
(synq.entities.v1.FolderRef)
FolderRef is the human-friendly, structured address of a folder: the entity it
hangs under (`root_entity_id`) plus the ordered folder names from that root
down to the folder (`folders`).
It is the stable way to name a folder across responses. Prefer it over the
opaque folder entity id when you want to log, display, or reconstruct a
location — the segments are the same names a user sees in the catalog, and
they survive changes to the underlying id encoding.
A `FolderRef` with an empty `folders` list names the root entity itself (a
top-level integration or container the hierarchy hangs from).
This type lives in `synq.entities.v1` (rather than a folder-specific package)
so it can be shared by both the folders navigation API and the query API
without an import cycle.
| Field | Type | Description |
| ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| root\_entity\_id | [ string](#string) | Opaque id of the entity the folder hierarchy hangs under — an integration root or container (for example a warehouse instance, a database, or a transformation project). Take it verbatim from `FolderRef.root_entity_id` of a folder you already read, or from an entity id returned elsewhere. |
| folders | [repeated string](#string) | Ordered folder names from the root down to this folder (root first, leaf last), for example \["staging", "sales"]. Empty means the ref points at the root entity itself. Folder names are kept as separate segments (not joined with "/") because some platforms allow "/" inside a single folder name. |
### Code
(synq.entities.v1.Code)
Code represents a piece of code or configuration that can be processed by Coalesce Quality.
This message is used to store and manage various types of code artifacts, such as SQL queries,
Python scripts, dbt models, and other code configurations. Each code piece is associated with
a specific entity that defines or owns it, and includes metadata about its type and state.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| definer\_identifier | [ Identifier](#identifier) | Identifier of the entity that defines or owns this code piece. This could be a dbt model, SQLMesh model, or any other entity type that contains code. |
| definer\_synq\_path | [ string](#string) | Coalesce Quality Path to the entity. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| definer\_entity\_type | [ EntityType](#entitytype) | Information about entity type of the entity defining code |
| state\_at | [ Timestamp](#timestamp) | Timestamp indicating when this specific version of the code was captured or last modified. This helps track the evolution of code over time. |
| code\_type | [ CodeType](#codetype) | Type of code being stored, which determines how Coalesce Quality will process and analyze it. This can be SQL, Python, dbt, SQLMesh, or other supported code types. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sql\_dialect.sql\_dialect | [optional SqlDialect](#sqldialect) | SQL dialect used in the code, if the code\_type is SQL. This helps Coalesce Quality understand the specific SQL syntax and features being used. |
| content | [ string](#string) | The actual content of the code. This can be SQL queries, Python scripts, dbt models, or any other supported code format. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_code\_name.code\_name | [optional string](#string) | Optional human-readable name for the code piece that can be used for display purposes. Might also indicate name of the file. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_file\_path.file\_path | [optional string](#string) | Optional path in e.g. git or project directory which is source of the code |
### Schema
(synq.entities.v1.Schema)
Schema represents a schema of a table like entity
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Immutable workspace identifier that this entity belongs to. |
| id | [ Identifier](#identifier) | Unique identifier for this entity. |
| synq\_path | [ string](#string) | Coalesce Quality Path to the entity. This is a unique path that can be used to access the entity in the Coalesce Quality UI. |
| state\_at | [ Timestamp](#timestamp) | Time when the schema was defined. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Optional description of the schema, might differ from the entity itself |
| columns | [repeated SchemaColumn](#schemacolumn) | Columns of the schema |
### SchemaColumn
(synq.entities.v1.SchemaColumn)
| Field | Type | Description |
| ----------------- | ------------------------------------------------ | --------------------------------------------------------------------------------- |
| name | [ string](#string) | Human readable name of the column as present in dbt or data warehouse. |
| native\_type | [ string](#string) | Native data type of the column as present in data warehouse. |
| description | [ string](#string) | Description of the column |
| ordinal\_position | [ int32](#int32) | Ordinal position of the column in the table, starting from 1 |
| is\_struct | [ bool](#bool) | Indicates that the column type could be used as a struct/json in a data warehouse |
| is\_repeated | [ bool](#bool) | Indicates that the column is a repeated field in a data warehouse (e.g. array) |
| fields | [repeated SchemaColumnField](#schemacolumnfield) | Fields inside of the struct/record like column |
### SchemaColumnField
(synq.entities.v1.SchemaColumnField)
| Field | Type | Description |
| ----------------- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
| name | [ string](#string) | Human readable name of the column as present in dbt or data warehouse. |
| native\_type | [ string](#string) | Native data type of the column as present in data warehouse. |
| description | [ string](#string) | Description of the column |
| ordinal\_position | [ int32](#int32) | Ordinal position of the column in the struct, starting from 1 |
| is\_struct | [ bool](#bool) | Indicates that the field type could be used as a struct/json in a data warehouse |
| is\_repeated | [ bool](#bool) | Indicates that the field is a repeated field in a data warehouse (e.g. array) |
| fields | [repeated SchemaColumnField](#schemacolumnfield) | Fields inside of the struct/record like field |
### BatchOrchestrationRequest
(synq.entities.orchestration.v1.BatchOrchestrationRequest)
| Field | Type | Description |
| -------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| entities | [repeated Identifier](#identifier) | Entities to query for orchestration relationships (e.g., Airflow tasks, dbt models, SQLMesh models, tables) |
### BatchOrchestrationResponse
(synq.entities.orchestration.v1.BatchOrchestrationResponse)
| Field | Type | Description |
| -------------- | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| orchestrations | [repeated Orchestration](#orchestration) | Orchestration relationships for each requested entity. The order corresponds to the order of entities in the request. |
### Orchestration
(synq.entities.orchestration.v1.Orchestration)
Orchestration represents the orchestration relationships for a given entity.
It shows both what the entity orchestrates (downstream) and what orchestrates it (upstream).
| Field | Type | Description |
| ---------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entity | [ OrchestrationGroup](#orchestrationgroup) | The entity being queried along with its other identities. For example, if querying a dbt or SQLMesh model, this group includes both the model and the table it creates, as they represent the same logical concept. |
| downstream | [repeated OrchestrationGroup](#orchestrationgroup) | Downstream entities that this entity orchestrates. Each group contains all identities of the orchestrated concept. Examples: - If entity is an Airflow task: groups containing \[dbt model, table] or \[SQLMesh model, table] - If entity is an Airflow task: groups containing downstream Airflow tasks and their orchestrated entities |
| upstream | [repeated OrchestrationGroup](#orchestrationgroup) | Upstream entities that orchestrate this entity. Each group contains all identities of the orchestrating concept. Examples: - If entity is a dbt/SQLMesh model or table: groups containing the Airflow task that executes it - If entity is an Airflow task: groups containing upstream Airflow tasks that trigger it |
### OrchestrationGroup
(synq.entities.orchestration.v1.OrchestrationGroup)
OrchestrationGroup represents different identities of the same logical concept.
For example, a dbt model and the table it creates are different representations
of the same entity, so they appear together in one group. An Airflow task
typically has only one identity (the task itself).
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entities | [repeated Identifier](#identifier) | Identifiers of all representations of this logical entity. Examples: - For a dbt model: \[dbt model, table it creates] - For a SQLMesh model: \[SQLMesh model, table it creates] - For an Airflow task: \[Airflow task] |
| synq\_paths | [repeated string](#string) | Coalesce Quality paths of the entities for easier reference, in the same order as entities |
### GetTableConstraintsRequest
(synq.entities.constraints.v1.GetTableConstraintsRequest)
| Field | Type | Description |
| ----- | -------------------------- | ------------------------------------------------ |
| id | [ Identifier](#identifier) | Identifier of the entity to get constraints for. |
### GetTableConstraintsResponse
(synq.entities.constraints.v1.GetTableConstraintsResponse)
| Field | Type | Description |
| ------------------ | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| id | [ Identifier](#identifier) | Identifier of the entity whose constraints are returned. May differ from the requested identifier if identity resolution mapped the request to an underlying table (e.g. dbt model → warehouse table). |
| synq\_path | [ string](#string) | Coalesce Quality path of the resolved entity. |
| constraints | [repeated TableConstraint](#tableconstraint) | Constraints and indexes defined on the table. |
| database\_instance | [ string](#string) | Database coordinates of the table whose constraints are returned. |
| database\_name | [ string](#string) | none |
| schema\_name | [ string](#string) | none |
| object\_name | [ string](#string) | none |
### ImpactedDataproduct
(synq.entities.impact.v1.ImpactedDataproduct)
| Field | Type | Description |
| ------------------ | ---------------------------------------------------- | ----------- |
| id | [ DataproductIdentifier](#dataproductidentifier) | none |
| title | [ string](#string) | none |
| description | [ string](#string) | none |
| folder | [ string](#string) | none |
| priority | [ Priority](#priority) | none |
| impacted\_entities | [repeated ImpactedEntityGroup](#impactedentitygroup) | none |
### ImpactedEntityGroup
(synq.entities.impact.v1.ImpactedEntityGroup)
Multiple Entities which form logical group, e.g. dbt Model and it's table
| Field | Type | Description |
| ----------------------------------------------------------------------------------------- | ---------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name.name | [optional string](#string) | none |
| ids | [repeated Identifier](#identifier) | none |
| synq\_paths | [repeated string](#string) | none |
### ImpactedOwner
(synq.entities.impact.v1.ImpactedOwner)
| Field | Type | Description |
| ------------------ | ---------------------------------------------------- | ----------- |
| id | [ OwnerIdentifier](#owneridentifier) | none |
| title | [ string](#string) | none |
| impacted\_entities | [repeated ImpactedEntityGroup](#impactedentitygroup) | none |
### GetImpactRequest
(synq.entities.impact.v1.GetImpactRequest)
| Field | Type | Description |
| ----- | ---------------------------------- | ----------- |
| ids | [repeated Identifier](#identifier) | none |
### GetImpactResponse
(synq.entities.impact.v1.GetImpactResponse)
| Field | Type | Description |
| ------------------------ | ---------------------------------------------------- | ----------- |
| entities | [repeated ImpactedEntityGroup](#impactedentitygroup) | none |
| downstream\_entities | [repeated ImpactedEntityGroup](#impactedentitygroup) | none |
| dataproducts | [repeated ImpactedDataproduct](#impacteddataproduct) | none |
| downstream\_dataproducts | [repeated ImpactedDataproduct](#impacteddataproduct) | none |
| owners | [repeated ImpactedOwner](#impactedowner) | none |
| downstream\_owners | [repeated ImpactedOwner](#impactedowner) | none |
### BatchResolveIdentifiersRequest
(synq.entities.resolve.v1.BatchResolveIdentifiersRequest)
| Field | Type | Description |
| ---------------- | ---------------------------------- | ------------------------------------------------------------------------------- |
| ids | [repeated Identifier](#identifier) | Identifiers to resolve. |
| check\_existence | [ bool](#bool) | When true, also verify that the resolved entities actually exist in the system. |
### BatchResolveIdentifiersResponse
(synq.entities.resolve.v1.BatchResolveIdentifiersResponse)
| Field | Type | Description |
| --------------------- | -------------------------------------------------- | ----------- |
| resolved\_identifiers | [repeated ResolvedIdentifier](#resolvedidentifier) | none |
### ResolvedIdentifier
(synq.entities.resolve.v1.ResolvedIdentifier)
ResolvedIdentifier contains the resolution result for a single input identifier.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------- |
| id | [ Identifier](#identifier) | The original input identifier. |
| synq\_path | [ string](#string) | The Coalesce Quality path for this identifier. |
| identities | [repeated Identifier](#identifier) | All identifiers that are part of the same identity group (including the input identifier). |
| identity\_synq\_paths | [repeated string](#string) | All Coalesce Quality paths in the identity group. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_exists.exists | [optional bool](#bool) | Whether the entity exists in the system. Only populated when check\_existence is true in the request. |
### ListCodeRequest
(synq.entities.code.v1.ListCodeRequest)
ListCodeRequest is the request message for the ListCode method.
| Field | Type | Description |
| ----- | -------------------------- | -------------------------------------------------------------------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to retrieve code for. This can be any entity type that contains code artifacts. |
### ListCodeResponse
(synq.entities.code.v1.ListCodeResponse)
ListCodeResponse is the response message for the ListCode method.
| Field | Type | Description |
| ----------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| codes | [repeated Code](#code) | List of code artifacts associated with the requested entity. Each code artifact includes its content, type, and metadata about when it was captured. |
| identifiers | [repeated Identifier](#identifier) | none |
| synq\_paths | [repeated string](#string) | none |
### Execution
(synq.entities.executions.v1.Execution)
| Field | Type | Description |
| ------------ | ------------------------------------------ | ----------- |
| id | [ Identifier](#identifier) | none |
| status | [ ExecutionStatus](#executionstatus) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| finished\_at | [ Timestamp](#timestamp) | none |
| annotations | [repeated Annotation](#annotation) | none |
| extras | [repeated ExecutionExtra](#executionextra) | none |
### ExecutionExtra
(synq.entities.executions.v1.ExecutionExtra)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) extra.executed\_sql | [ string](#string) | none |
### LogEntry
(synq.entities.executions.v1.LogEntry)
| Field | Type | Description |
| ------------ | ---------------------------------- | ----------- |
| id | [ Identifier](#identifier) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| finished\_at | [ Timestamp](#timestamp) | none |
| annotations | [repeated Annotation](#annotation) | none |
### UpsertExecutionRequest
(synq.entities.executions.v1.UpsertExecutionRequest)
| Field | Type | Description |
| --------- | ------------------------ | ----------- |
| execution | [ Execution](#execution) | none |
### UpsertExecutionResponse
(synq.entities.executions.v1.UpsertExecutionResponse)
### UpsertLogEntryRequest
(synq.entities.executions.v1.UpsertLogEntryRequest)
| Field | Type | Description |
| ---------- | ---------------------- | ----------- |
| log\_entry | [ LogEntry](#logentry) | none |
### UpsertLogEntryResponse
(synq.entities.executions.v1.UpsertLogEntryResponse)
### BatchGetExecutionsRequest
(synq.entities.executions.v2.BatchGetExecutionsRequest)
BatchGetExecutionsRequest requests specific executions by ID.
| Field | Type | Description |
| -------------- | -------------------------- | -------------------------- |
| execution\_ids | [repeated string](#string) | Execution IDs to retrieve. |
### BatchGetExecutionsResponse
(synq.entities.executions.v2.BatchGetExecutionsResponse)
BatchGetExecutionsResponse contains the requested executions.
| Field | Type | Description |
| ---------- | --------------------------------------- | ------------------------------------------------------------------------------------------------ |
| executions | [map ExecutionsEntry](#executionsentry) | Map of execution ID to EntityExecution. Only includes executions that were found and accessible. |
### BatchGetExecutionsResponse.ExecutionsEntry
(synq.entities.executions.v2.BatchGetExecutionsResponse.ExecutionsEntry)
| Field | Type | Description |
| ----- | ------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ EntityExecution](#entityexecution) | none |
### EntityExecution
(synq.entities.executions.v2.EntityExecution)
EntityExecution represents a single execution event on an entity.
This is a public representation of internal Run data, excluding sensitive metadata.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| id | [ string](#string) | Unique identifier for this execution. |
| entities | [repeated Identifier](#identifier) | Primary entities affected by this execution. These are the main entities this execution ran on or modified. |
| entities\_synq\_paths | [repeated string](#string) | Coalesce Quality paths of primary entities affected by this execution. |
| targets | [repeated Identifier](#identifier) | Target entities referenced by this execution. These are secondary entities that were targets of the execution. |
| targets\_synq\_paths | [repeated string](#string) | Coalesce Quality paths of target entities referenced by this execution. |
| extra\_references | [repeated Identifier](#identifier) | Additional entity references. These are other entities referenced during the execution. |
| extra\_references\_synq\_paths | [repeated string](#string) | Coalesce Quality paths of additional entity references. |
| execution\_type | [ ExecutionType](#executiontype) | Type of execution (e.g., query, job, test run). |
| status | [ ExecutionStatus](#executionstatus) | Status of the execution. |
| skipped | [ bool](#bool) | Whether this execution was skipped. |
| message | [ string](#string) | Human-readable message describing the execution result. This typically contains error messages, warnings, or success information. |
| created\_at | [ Timestamp](#timestamp) | When the execution record was created in Coalesce Quality. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_at.started\_at | [optional Timestamp](#timestamp) | When the execution actually started. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_finished\_at.finished\_at | [optional Timestamp](#timestamp) | When the execution finished. |
| parent\_execution\_ids | [repeated string](#string) | IDs of parent executions, if this is a nested execution. For example, a task execution might have a parent DAG execution. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_duration\_seconds.duration\_seconds | [optional double](#double) | Duration of the execution in seconds. Only populated if both started\_at and finished\_at are present. |
### ExecutionStatusCount
(synq.entities.executions.v2.ExecutionStatusCount)
ExecutionStatusCount represents the count of executions by status.
| Field | Type | Description |
| ------ | ------------------------------------ | ----------- |
| status | [ ExecutionStatus](#executionstatus) | none |
| count | [ int64](#int64) | none |
### ExecutionTypeCount
(synq.entities.executions.v2.ExecutionTypeCount)
ExecutionTypeCount represents the count of executions by type.
| Field | Type | Description |
| --------------- | -------------------------------- | ----------- |
| execution\_type | [ ExecutionType](#executiontype) | none |
| count | [ int64](#int64) | none |
### GetExecutionsSummaryRequest
(synq.entities.executions.v2.GetExecutionsSummaryRequest)
GetExecutionsSummaryRequest requests summary statistics for entities.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| entity\_ids | [repeated Identifier](#identifier) | Entity identifiers to get summary for. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_started\_after.execution\_started\_after | [optional Timestamp](#timestamp) | Return executions that started after this timestamp. If not provided, defaults to 30 days before execution\_started\_before. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_started\_before.execution\_started\_before | [optional Timestamp](#timestamp) | Return executions that started before this timestamp. If not provided, defaults to now(). |
### GetExecutionsSummaryResponse
(synq.entities.executions.v2.GetExecutionsSummaryResponse)
GetExecutionsSummaryResponse contains aggregated execution statistics.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------- |
| total\_executions | [ int64](#int64) | Total number of executions matching the criteria. |
| execution\_type\_counts | [repeated ExecutionTypeCount](#executiontypecount) | Count of executions by type. |
| status\_counts | [repeated ExecutionStatusCount](#executionstatuscount) | Count of executions by status. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_earliest\_execution.earliest\_execution | [optional Timestamp](#timestamp) | Time range of available executions. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_latest\_execution.latest\_execution | [optional Timestamp](#timestamp) | none |
| latest\_by\_entity | [map LatestByEntityEntry](#latestbyentityentry) | Latest execution for each requested entity. |
### GetExecutionsSummaryResponse.LatestByEntityEntry
(synq.entities.executions.v2.GetExecutionsSummaryResponse.LatestByEntityEntry)
| Field | Type | Description |
| ----- | ------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ EntityExecution](#entityexecution) | none |
### GetLatestExecutionsRequest
(synq.entities.executions.v2.GetLatestExecutionsRequest)
GetLatestExecutionsRequest requests the latest execution for each entity.
| Field | Type | Description |
| ---------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entity\_ids | [repeated Identifier](#identifier) | Entity identifiers to get latest executions for. Only returns executions where these entities appear in EntityExecution.entities (what executed). Examples that WILL return results: monitors, dbt models, airflow tasks, tests Examples that WON'T return results: tables (they don't execute, they are created/updated by models) |
| statuses | [repeated ExecutionStatus](#executionstatus) | Filter by execution status. If provided, returns the latest execution with one of these statuses. If empty, returns the latest execution regardless of status. |
| execution\_types | [repeated ExecutionType](#executiontype) | Filter by execution types. If provided, returns the latest execution of one of these types. If empty, returns the latest execution regardless of type. |
### GetLatestExecutionsResponse
(synq.entities.executions.v2.GetLatestExecutionsResponse)
GetLatestExecutionsResponse contains the latest execution for each requested entity.
| Field | Type | Description |
| ------------------ | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| latest\_executions | [map LatestExecutionsEntry](#latestexecutionsentry) | Map of entity identifier (as string) to latest execution. Entities with no matching executions are omitted. |
### GetLatestExecutionsResponse.LatestExecutionsEntry
(synq.entities.executions.v2.GetLatestExecutionsResponse.LatestExecutionsEntry)
| Field | Type | Description |
| ----- | ------------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ EntityExecution](#entityexecution) | none |
### ListExecutionsRequest
(synq.entities.executions.v2.ListExecutionsRequest)
ListExecutionsRequest specifies filters for listing executions.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| entity\_ids | [repeated Identifier](#identifier) | Entity identifiers to get executions for. Executions affecting any of these entities will be returned. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_started\_after.execution\_started\_after | [optional Timestamp](#timestamp) | Return executions that started after this timestamp. If not provided, defaults to 7 days before execution\_started\_before. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_started\_before.execution\_started\_before | [optional Timestamp](#timestamp) | Return executions that started before this timestamp. If not provided, defaults to now(). |
| execution\_types | [repeated ExecutionType](#executiontype) | Filter by specific execution types. If empty, all execution types are included. |
| statuses | [repeated ExecutionStatus](#executionstatus) | Filter by execution status. If empty, all statuses are included. |
| include\_referenced\_executions | [ bool](#bool) | Include executions that reference the specified entities (not just primary entities). If true, executions where entity\_ids appear in targets or extra\_references are also returned. |
| pagination | [ Pagination](#pagination) | Pagination parameters. |
### ListExecutionsResponse
(synq.entities.executions.v2.ListExecutionsResponse)
ListExecutionsResponse contains the paginated list of executions.
| Field | Type | Description |
| ---------- | -------------------------------------------- | ----------------------------------------------------------------------------------- |
| executions | [repeated EntityExecution](#entityexecution) | List of executions matching the filter criteria, ordered by started\_at descending. |
| page\_info | [ PageInfo](#pageinfo) | Pagination information. |
### SqlDefinition
(synq.entities.custom.features.v1.SqlDefinition)
SqlDefinition is a feature that allows to define lineage via SQL for a custom entity.
Used to generate dependencies and other metadata. If parsed successfully,
it will provide a code and column level lineage. Can be used to define simplified transformation
of data which component performs using e.g. `INSERT INTO foo SELECT * FROM bar`.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| state\_at | [ Timestamp](#timestamp) | Time when the sql was defined, will default to `now` if not set. |
| dialect | [ SqlDialect](#sqldialect) | SQL dialect used in the SQL. |
| sql | [ string](#string) | Final form of the SQL as executed in the database/data warehouse. Must be a valid SQL in the selected dialect. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database\_context.database\_context | [optional DatabaseContext](#databasecontext) | Optional database context for resolving unqualified table references in the SQL. When provided, helps CLL resolve schema-qualified references (e.g. `PROD.TABLE_NAME`) to the correct database instance and catalog. |
### CheckCategory
(synq.entities.custom.features.v1.CheckCategory)
Checks feature indicates that the entity is testing in some way different entity.
To define the kind of the check use the `kind` field. The `package` field is optional.
It is used to categorize the entities which check other entities.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| package | [ string](#string) | Grouping of check kinds. e.g. "gcs", "sql", "queue" |
| kind | [ string](#string) | Kind of the check. e.g "not\_null", "unique", "foreign\_key", "row\_count". |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Explicit name of the Check category. If it is not defined categorisation rules are applied based on package + kind. |
### GitFileReference
(synq.entities.custom.features.v1.GitFileReference)
GitFileReference represents a reference to a file in a git repository.
| Field | Type | Description |
| --------------- | ------------------ | ---------------------------------------------------- |
| repository\_url | [ string](#string) | URL of the git repository. Preferably SSH clone URL. |
| branch\_name | [ string](#string) | Name of the branch in the git repository. |
| file\_path | [ string](#string) | Path to the file in the git repository. |
### Code
(synq.entities.custom.features.v1.Code)
Code feature represents a code snippet associated with the entity.
If support for code parsing and dependency extraction is needed use [SqlDefinition](sql_definition.proto).
| Field | Type | Description |
| ---------- | ---------------------- | --------------------------------------------- |
| name | [ string](#string) | Might be e.g. name of the file or a function. |
| code\_type | [ CodeType](#codetype) | Type of the code. |
| content | [ string](#string) | Content of the code. Displayed in the UI. |
### Schema
(synq.entities.custom.features.v1.Schema)
Schema represents a schema of a table like entity
| Field | Type | Description |
| --------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| state\_at | [ Timestamp](#timestamp) | Time when the schema was defined, will default to `now` if not set. |
| columns | [repeated SchemaColumn](#schemacolumn) | Columns of the schema Columns are ordered by ordinal\_position, it has to be defined for all or none of the columns, when not defined, ordinal positions are attached according to the order of columns in the list. |
### CheckRelationship
(synq.entities.custom.v1.CheckRelationship)
| Field | Type | Description |
| ---------------- | -------------------------- | ----------- |
| check | [ Identifier](#identifier) | none |
| checked | [ Identifier](#identifier) | none |
| checked\_columns | [repeated string](#string) | none |
### DeleteCheckRelationshipsRequest
(synq.entities.custom.v1.DeleteCheckRelationshipsRequest)
| Field | Type | Description |
| -------------------- | ------------------------------------------------ | ----------- |
| check\_relationships | [repeated CheckRelationship](#checkrelationship) | none |
### DeleteCheckRelationshipsResponse
(synq.entities.custom.v1.DeleteCheckRelationshipsResponse)
### UpsertCheckRelationshipsRequest
(synq.entities.custom.v1.UpsertCheckRelationshipsRequest)
| Field | Type | Description |
| -------------------- | ------------------------------------------------ | ----------- |
| check\_relationships | [repeated CheckRelationship](#checkrelationship) | none |
### UpsertCheckRelationshipsResponse
(synq.entities.custom.v1.UpsertCheckRelationshipsResponse)
### DeleteEntityRequest
(synq.entities.custom.v1.DeleteEntityRequest)
DeleteEntityRequest is the request message for the DeleteEntity method.
| Field | Type | Description |
| ----- | -------------------------- | ----------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to delete. |
### DeleteEntityResponse
(synq.entities.custom.v1.DeleteEntityResponse)
DeleteEntityResponse is the response message for the DeleteEntity method.
### ListEntitiesRequest
(synq.entities.custom.v1.ListEntitiesRequest)
### ListEntitiesResponse
(synq.entities.custom.v1.ListEntitiesResponse)
| Field | Type | Description |
| -------- | -------------------------- | ----------- |
| entities | [repeated Entity](#entity) | none |
### UpsertEntityRequest
(synq.entities.custom.v1.UpsertEntityRequest)
UpsertEntityRequest is the request message for the UpsertEntity method.
| Field | Type | Description |
| ------ | ------------------ | ------------------------------- |
| entity | [ Entity](#entity) | The entity to create or update. |
### UpsertEntityResponse
(synq.entities.custom.v1.UpsertEntityResponse)
UpsertEntityResponse is the response message for the UpsertEntity method.
### DeleteRelationshipsRequest
(synq.entities.custom.v1.DeleteRelationshipsRequest)
| Field | Type | Description |
| ------------- | -------------------------------------- | ----------- |
| relationships | [repeated Relationship](#relationship) | none |
### DeleteRelationshipsResponse
(synq.entities.custom.v1.DeleteRelationshipsResponse)
### ListRelationshipsRequest
(synq.entities.custom.v1.ListRelationshipsRequest)
| Field | Type | Description |
| ----- | ---------------------------------- | ----------------------------------------------------------------------------- |
| ids | [repeated Identifier](#identifier) | Return relationships for the given entity\_id. Either upstream or downstream. |
### ListRelationshipsResponse
(synq.entities.custom.v1.ListRelationshipsResponse)
| Field | Type | Description |
| ------------- | -------------------------------------- | ----------- |
| relationships | [repeated Relationship](#relationship) | none |
### Relationship
(synq.entities.custom.v1.Relationship)
| Field | Type | Description |
| ---------- | -------------------------- | ----------- |
| upstream | [ Identifier](#identifier) | none |
| downstream | [ Identifier](#identifier) | none |
### UpsertRelationshipsRequest
(synq.entities.custom.v1.UpsertRelationshipsRequest)
| Field | Type | Description |
| ------------- | -------------------------------------- | ----------- |
| relationships | [repeated Relationship](#relationship) | none |
### UpsertRelationshipsResponse
(synq.entities.custom.v1.UpsertRelationshipsResponse)
### DeleteEntitiesGroupRequest
(synq.entities.custom.v1.DeleteEntitiesGroupRequest)
| Field | Type | Description |
| --------- | ------------------ | ----------- |
| group\_id | [ string](#string) | none |
### DeleteEntitiesGroupResponse
(synq.entities.custom.v1.DeleteEntitiesGroupResponse)
### Group
(synq.entities.custom.v1.Group)
Group is a collection of entities.
| Field | Type | Description |
| ----------- | ---------------------------------- | ------------------------------------------------- |
| group\_id | [ string](#string) | Identifier of the group. |
| entity\_ids | [repeated Identifier](#identifier) | Identifiers of entities that belong to the group. |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the group was created. |
| updated\_at | [ Timestamp](#timestamp) | Timestamp when the group was last updated. |
### ListEntityGroupsRequest
(synq.entities.custom.v1.ListEntityGroupsRequest)
### ListEntityGroupsResponse
(synq.entities.custom.v1.ListEntityGroupsResponse)
| Field | Type | Description |
| ---------------- | ------------------------ | ----------- |
| entities\_groups | [repeated Group](#group) | none |
### UpsertEntitiesGroupRequest
(synq.entities.custom.v1.UpsertEntitiesGroupRequest)
| Field | Type | Description |
| ----- | ---------------- | ----------- |
| group | [ Group](#group) | none |
### UpsertEntitiesGroupResponse
(synq.entities.custom.v1.UpsertEntitiesGroupResponse)
| Field | Type | Description |
| ------------ | ---------------------------------- | ----------- |
| deleted\_ids | [repeated Identifier](#identifier) | none |
### Execution
(synq.entities.custom.v1.Execution)
| Field | Type | Description |
| ------------ | ------------------------------------------ | ----------- |
| id | [ Identifier](#identifier) | none |
| status | [ ExecutionStatus](#executionstatus) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| finished\_at | [ Timestamp](#timestamp) | none |
| annotations | [repeated Annotation](#annotation) | none |
| extras | [repeated ExecutionExtra](#executionextra) | none |
### ExecutionExtra
(synq.entities.custom.v1.ExecutionExtra)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------- | ------------------ | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) extra.executed\_sql | [ string](#string) | none |
### LogEntry
(synq.entities.custom.v1.LogEntry)
| Field | Type | Description |
| ------------ | ---------------------------------- | ----------- |
| id | [ Identifier](#identifier) | none |
| message | [ string](#string) | none |
| created\_at | [ Timestamp](#timestamp) | none |
| started\_at | [ Timestamp](#timestamp) | none |
| finished\_at | [ Timestamp](#timestamp) | none |
| annotations | [repeated Annotation](#annotation) | none |
### UpsertExecutionRequest
(synq.entities.custom.v1.UpsertExecutionRequest)
| Field | Type | Description |
| --------- | ------------------------ | ----------- |
| execution | [ Execution](#execution) | none |
### UpsertExecutionResponse
(synq.entities.custom.v1.UpsertExecutionResponse)
### UpsertLogEntryRequest
(synq.entities.custom.v1.UpsertLogEntryRequest)
| Field | Type | Description |
| ---------- | ---------------------- | ----------- |
| log\_entry | [ LogEntry](#logentry) | none |
### UpsertLogEntryResponse
(synq.entities.custom.v1.UpsertLogEntryResponse)
### DeleteEntityFeatureRequest
(synq.entities.custom.v1.DeleteEntityFeatureRequest)
| Field | Type | Description |
| ----------- | -------------------------- | ------------------------------------------------ |
| entity\_id | [ Identifier](#identifier) | Identifier of the entity to delete feature from. |
| feature\_id | [ string](#string) | Identifier of the feature to delete. |
### DeleteEntityFeatureResponse
(synq.entities.custom.v1.DeleteEntityFeatureResponse)
### Feature
(synq.entities.custom.v1.Feature)
| Field | Type | Description |
| ---------------------------------------------------------------------------------------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace | [ string](#string) | Immutable workspace identifier that this entity belongs to. |
| entity\_id | [ Identifier](#identifier) | The identifier of the entity to create or update feature for. |
| feature\_id | [ string](#string) | Identifier of the feature. Can be any string, e.g. "sql" for SQL feature. Use same identifier to update the feature. Do not use random identifier as it will create a new feature on every update. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.sql\_definition | [ SqlDefinition](#sqldefinition) | Only one feature per entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.git\_file\_reference | [ GitFileReference](#gitfilereference) | Multiple features per entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.code | [ Code](#code) | Multiple features per entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.schema | [ Schema](#schema) | Only one feature per entity. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.check\_category | [ CheckCategory](#checkcategory) | Only one feature per entity. |
| created\_at | [ Timestamp](#timestamp) | Timestamp when the entity was created. |
| updated\_at | [ Timestamp](#timestamp) | Timestamp when the entity was last updated. |
| deleted\_at | [ Timestamp](#timestamp) | Timestamp when the entity was deleted. If this is set, the entity is considered deleted. |
### ListEntityFeaturesRequest
(synq.entities.custom.v1.ListEntityFeaturesRequest)
| Field | Type | Description |
| ---------- | -------------------------- | --------------------------------------------- |
| entity\_id | [ Identifier](#identifier) | Identifier of the entity to get features for. |
### ListEntityFeaturesResponse
(synq.entities.custom.v1.ListEntityFeaturesResponse)
| Field | Type | Description |
| -------- | ---------------------------- | -------------------------------- |
| features | [repeated Feature](#feature) | List of features for the entity. |
### UpsertEntityFeatureRequest
(synq.entities.custom.v1.UpsertEntityFeatureRequest)
| Field | Type | Description |
| ------- | -------------------- | -------------------------------- |
| feature | [ Feature](#feature) | The feature to create or update. |
### UpsertEntityFeatureResponse
(synq.entities.custom.v1.UpsertEntityFeatureResponse)
### DeleteTypeRequest
(synq.entities.custom.v1.DeleteTypeRequest)
| Field | Type | Description |
| -------- | ---------------- | ----------------------------------------------- |
| type\_id | [ int32](#int32) | Identifier of the custom entity type to delete. |
### DeleteTypeResponse
(synq.entities.custom.v1.DeleteTypeResponse)
### ListTypesRequest
(synq.entities.custom.v1.ListTypesRequest)
### ListTypesResponse
(synq.entities.custom.v1.ListTypesResponse)
| Field | Type | Description |
| ----- | ---------------------- | ----------------- |
| types | [repeated Type](#type) | List of entities. |
### UpsertTypeRequest
(synq.entities.custom.v1.UpsertTypeRequest)
| Field | Type | Description |
| ----- | -------------- | --------------------------- |
| type | [ Type](#type) | Entity to create or update. |
### UpsertTypeResponse
(synq.entities.custom.v1.UpsertTypeResponse)
### CllDetails
(synq.entities.lineage.v1.CllDetails)
| Field | Type | Description |
| ------------- | -------------------------- | --------------------------------------------------------------- |
| columns | [repeated Column](#column) | Column details for CLL. |
| cll\_state | [ CllState](#cllstate) | State of the CLL parse. UNSPECIFIED if CLL was not requested. |
| cll\_messages | [repeated string](#string) | Messages related to CLL. e.g. Description of parse errors, etc. |
### Column
(synq.entities.lineage.v1.Column)
Column in a table-like asset (used in CLL mode).
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | -------------------------- | --------------------------------------------------------- |
| column\_id | [ string](#string) | ID string for the column. This is the parsed column name. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name.name | [optional string](#string) | Original column name as fetched from the table. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_native\_type.native\_type | [optional string](#string) | Column type as fetched from the table. |
### ColumnDependency
(synq.entities.lineage.v1.ColumnDependency)
Indicates data flow between columns.
Source columns are used to compute value of target columns.
| Field | Type | Description |
| ------------------------ | ------------------ | ----------------------------------------------- |
| source\_node\_idx | [ uint32](#uint32) | Index of source node in the lineage nodes list. |
| source\_node\_column\_id | [ string](#string) | none |
| target\_node\_idx | [ uint32](#uint32) | Index of target node in the lineage nodes list. |
| target\_node\_column\_id | [ string](#string) | none |
### Lineage
(synq.entities.lineage.v1.Lineage)
Lineage defines the lineage of table-like entities.
| Field | Type | Description |
| -------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| nodes | [repeated LineageNode](#lineagenode) | Nodes in the lineage with their identities and columns. |
| node\_dependencies | [repeated NodeDependency](#nodedependency) | All edges in the lineage between nodes. This can be parsed to create a graph of all the nodes. |
| is\_cll | [ bool](#bool) | Indicates whether the lineage was filtered for column level lineage (CLL). |
| column\_dependencies | [repeated ColumnDependency](#columndependency) | Dependencies between columns. Populated only for CLL. |
### LineageNode
(synq.entities.lineage.v1.LineageNode)
Node in a lineage graph representing one or more entities (e.g. database table).
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ids | [repeated Identifier](#identifier) | All entities which have the same identity as this node. Must be at least one item. These are sorted by closeness to the type of the start point entities. e.g. if requesting lineage of a DBT source, first entity should be from DBT, similarly when viewing table it will be other tables. |
| position | [ NodePosition](#nodeposition) | Position of the node in the lineage. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cll\_details.cll\_details | [optional CllDetails](#clldetails) | Populated only for Column Level Lineage (CLL). |
### NodeDependency
(synq.entities.lineage.v1.NodeDependency)
Indicates data flow between nodes.
Source nodes are used to compute value of target nodes.
| Field | Type | Description |
| ----------------- | ------------------ | ----------------------------------------------- |
| source\_node\_idx | [ uint32](#uint32) | Index of source node in the lineage nodes list. |
| target\_node\_idx | [ uint32](#uint32) | Index of target node in the lineage nodes list. |
### EntitiesStartPoint
(synq.entities.lineage.v1.EntitiesStartPoint)
| Field | Type | Description |
| -------- | ---------------------------------- | ----------- |
| entities | [repeated Identifier](#identifier) | none |
### EntityColumnsStartPoint
(synq.entities.lineage.v1.EntityColumnsStartPoint)
| Field | Type | Description |
| ------------- | -------------------------- | ----------- |
| id | [ Identifier](#identifier) | none |
| column\_names | [repeated string](#string) | none |
### GetLineageRequest
(synq.entities.lineage.v1.GetLineageRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------- |
| lineage\_direction | [ LineageDirection](#lineagedirection) | none |
| start\_point | [ GetLineageStartPoint](#getlineagestartpoint) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_max\_depth.max\_depth | [optional int32](#int32) | none |
### GetLineageResponse
(synq.entities.lineage.v1.GetLineageResponse)
| Field | Type | Description |
| ------- | -------------------- | ----------- |
| lineage | [ Lineage](#lineage) | none |
### GetLineageStartPoint
(synq.entities.lineage.v1.GetLineageStartPoint)
Possible starting points to get lineage from.
| Field | Type | Description |
| -------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | ----------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) from.entities | [ EntitiesStartPoint](#entitiesstartpoint) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) from.entity\_columns | [ EntityColumnsStartPoint](#entitycolumnsstartpoint) | none |
### BatchChangeRequest
(synq.entities.changes.v1.BatchChangeRequest)
BatchChangeRequest contains the parameters needed to retrieve multiple changes by their IDs.
| Field | Type | Description |
| ----------- | -------------------------- | -------------------------------------------------------------------------------------------- |
| change\_ids | [repeated string](#string) | List of change IDs to retrieve. Each ID uniquely identifies a specific change in the system. |
### BatchChangeResponse
(synq.entities.changes.v1.BatchChangeResponse)
BatchChangeResponse contains the requested changes mapped by their IDs.
| Field | Type | Description |
| ------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| changes | [map ChangesEntry](#changesentry) | Map of change ID to EntityChange. Only includes changes that were found and accessible. Missing changes are omitted from the response. |
### BatchChangeResponse.ChangesEntry
(synq.entities.changes.v1.BatchChangeResponse.ChangesEntry)
| Field | Type | Description |
| ----- | ------------------------------ | ----------- |
| key | [ string](#string) | none |
| value | [ EntityChange](#entitychange) | none |
### ListRequest
(synq.entities.changes.v1.ListRequest)
ListRequest contains the parameters needed to retrieve changes for a specific entity.
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get changes for. This can be a path identifier that uniquely identifies the entity in the system. |
| ids | [repeated Identifier](#identifier) | Identifiers of entities for which to get changes. Change is returned when it affects id. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_before.change\_before | [optional Timestamp](#timestamp) | Return changes older than or on `before`. Defaults to `now()`. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_after.change\_after | [optional Timestamp](#timestamp) | Return changes newer than until. Defaults to before - 7days, |
| limit\_to\_change\_types | [repeated EntityChangeType](#entitychangetype) | Return only changes of specific types. |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination parameters for limiting and cursoring through results. |
### ListResponse
(synq.entities.changes.v1.ListResponse)
ListResponse contains the list of changes made to the requested entity.
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| changes | [repeated EntityChange](#entitychange) | List of recent changes to the state of entity. Changes are returned from newest to oldest. Each change includes: - The type of change (git commit, schema change, SQL definition change) - When the change occurred - Details specific to the type of change - Metadata about who made the change |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_page\_info.page\_info | [optional PageInfo](#pageinfo) | Pagination information for navigating through results. |
### BatchSqlDetailsRequest
(synq.entities.sql\_insights.v1.BatchSqlDetailsRequest)
BatchSqlDetailsRequest requests SQL details for a set of entities.
| Field | Type | Description |
| ----- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| paths | [repeated string](#string) | The synq paths of the entities to fetch SQL details for. A synq path uniquely identifies an entity and can be obtained from the `synq_paths` field of other entity responses. |
### BatchSqlDetailsResponse
(synq.entities.sql\_insights.v1.BatchSqlDetailsResponse)
BatchSqlDetailsResponse maps each requested synq path to its SQL details.
| Field | Type | Description |
| ------------ | --------------------------------------- | ---------------------------------------------------------------------- |
| sql\_details | [map SqlDetailsEntry](#sqldetailsentry) | SQL details keyed by synq path. Paths with no SQL details are omitted. |
### BatchSqlDetailsResponse.SqlDetailsEntry
(synq.entities.sql\_insights.v1.BatchSqlDetailsResponse.SqlDetailsEntry)
| Field | Type | Description |
| ----- | -------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ SqlDetails](#sqldetails) | none |
### ListSqlConstructsRequest
(synq.entities.sql\_insights.v1.ListSqlConstructsRequest)
ListSqlConstructsRequest has no fields: the result is scoped to the workspace
of the authenticated request.
### ListSqlConstructsResponse
(synq.entities.sql\_insights.v1.ListSqlConstructsResponse)
ListSqlConstructsResponse carries the per-construct occurrence counts for the
workspace.
| Field | Type | Description |
| --------------- | ------------------------------------------------ | -------------------------------------------------------------------- |
| sql\_constructs | [repeated SqlConstructCount](#sqlconstructcount) | One entry per construct that appears at least once in the workspace. |
### ListSqlConstructsResponse.SqlConstructCount
(synq.entities.sql\_insights.v1.ListSqlConstructsResponse.SqlConstructCount)
SqlConstructCount pairs a SQL construct with the number of entities in the
workspace whose SQL uses it.
| Field | Type | Description |
| -------------- | ------------------------------ | ------------------------------------------------------ |
| sql\_construct | [ SqlConstruct](#sqlconstruct) | The SQL construct being counted. |
| count | [ int32](#int32) | How many entities in the workspace use this construct. |
### SqlDetails
(synq.entities.sql\_insights.v1.SqlDetails)
SqlDetails describes the SQL used by a single entity.
| Field | Type | Description |
| --------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| path | [ string](#string) | The synq path of the entity these details belong to. |
| sql\_constructs | [repeated SqlConstruct](#sqlconstruct) | The set of SQL constructs detected in the entity's SQL. Multiple constructs can be present on a single entity (e.g. a query with both a CTE and an INNER JOIN reports HAS\_CTE, HAS\_ANY\_JOIN and INNER\_JOIN). |
### AnnotationCount
(synq.entities.annotations.v1.AnnotationCount)
AnnotationCount represents the count of entities that have a specific annotation name-value pair.
This is used for aggregating and reporting annotation statistics across entities.
| Field | Type | Description |
| ----- | ------------------ | -------------------------------------------------------------------------------------------- |
| name | [ string](#string) | The annotation name (key). |
| value | [ string](#string) | The annotation value. If empty, represents the count for all values of this annotation name. |
| count | [ int32](#int32) | The number of entities that have this annotation name-value pair. |
### ListAnnotationsRequest
(synq.entities.annotations.v1.ListAnnotationsRequest)
ListAnnotationsRequest is the request message for the ListAnnotations method.
### ListAnnotationsResponse
(synq.entities.annotations.v1.ListAnnotationsResponse)
ListAnnotationsResponse is the response message for the ListAnnotations method.
| Field | Type | Description |
| ------------------ | -------------------------------------------- | ------------------------------------------------ |
| annotation\_counts | [repeated AnnotationCount](#annotationcount) | The annotation counts grouped by name and value. |
### EntityIncident
(synq.entities.status.v1.EntityIncident)
| Field | Type | Description |
| ------------ | ------------------------ | --------------------------------------------------------- |
| id | [ string](#string) | Unique identifier of the incident. |
| url | [ string](#string) | URL of the incident. |
| name | [ string](#string) | Name of the incident give by the user. |
| created\_by | [ string](#string) | Information about author of the incident. |
| created\_at | [ Timestamp](#timestamp) | Time when the incident was created. |
| updated\_by | [ string](#string) | Information about the user who last updated the incident. |
| updated\_at | [ Timestamp](#timestamp) | Time when the incident was last updated. |
| is\_resolved | [ bool](#bool) | Indicates if all issues inside the incident are resolved. |
### BatchGetIncidentsRequest
(synq.entities.status.v1.BatchGetIncidentsRequest)
BatchGetIncidentsRequest is the request message for the BatchGetIssues method.
| Field | Type | Description |
| -------- | ---------------------------------------------------- | ----------- |
| requests | [repeated GetIncidentsRequest](#getincidentsrequest) | none |
### BatchGetIncidentsResponse
(synq.entities.status.v1.BatchGetIncidentsResponse)
BatchGetIncidentsResponse is the response message for the BatchGetIssues method.
| Field | Type | Description |
| --------- | ------------------------------------------------------ | ----------- |
| responses | [repeated GetIncidentsResponse](#getincidentsresponse) | none |
### GetIncidentsRequest
(synq.entities.status.v1.GetIncidentsRequest)
GetIncidentsRequest is the request message for the GetEntity method.
| Field | Type | Description |
| -------------------------- | -------------------------- | ---------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get incidents for. |
| fetch\_upstream\_incidents | [ bool](#bool) | Retrieve incidents of upstream entities. |
### GetIncidentsResponse
(synq.entities.status.v1.GetIncidentsResponse)
GetIncidentsResponse is the response message for the GetEntity method.
| Field | Type | Description |
| ------------------------- | ------------------------------------------ | ------------------------------------------------------------------ |
| id | [ Identifier](#identifier) | Identifier of the entity. |
| entity\_open\_incidents | [repeated EntityIncident](#entityincident) | Open incident associated with the entity requested. |
| upstream\_open\_incidents | [repeated EntityIncident](#entityincident) | Open incidents associated with the upstream entities if requested. |
### BatchGetIssuesStatusRequest
(synq.entities.status.v1.BatchGetIssuesStatusRequest)
BatchGetIssuesStatusRequest is the request message for the BatchGetIssues method.
| Field | Type | Description |
| -------- | ---------------------------------------------------------- | ----------- |
| requests | [repeated GetIssuesStatusRequest](#getissuesstatusrequest) | none |
### BatchGetIssuesStatusResponse
(synq.entities.status.v1.BatchGetIssuesStatusResponse)
BatchGetIssuesStatusResponse is the response message for the BatchGetIssues method.
| Field | Type | Description |
| --------- | ------------------------------------------------------------ | ----------- |
| responses | [repeated GetIssuesStatusResponse](#getissuesstatusresponse) | none |
### GetIssuesStatusRequest
(synq.entities.status.v1.GetIssuesStatusRequest)
GetIssuesStatusRequest is the request message for the GetEntity method.
| Field | Type | Description |
| ----------------------- | -------------------------- | ------------------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get status for. |
| fetch\_upstream\_status | [ bool](#bool) | Retrieve status of upstream entities. |
### GetIssuesStatusResponse
(synq.entities.status.v1.GetIssuesStatusResponse)
GetIssuesStatusResponse is the response message for the GetEntity method.
| Field | Type | Description |
| ------------------------- | -------------------------------- | ------------------------------------------------ |
| id | [ Identifier](#identifier) | Identifier of the entity. |
| entity\_issues\_status | [ IssueStatus](#issuestatus) | Status of the entity requested. |
| entity\_issues\_summary | [ IssuesSummary](#issuessummary) | none |
| upstream\_issues\_status | [ IssueStatus](#issuestatus) | Optionally, the status of all upstream entities. |
| upstream\_issues\_summary | [ IssuesSummary](#issuessummary) | none |
### GetIssuesStatusResponse.IssuesSummary
(synq.entities.status.v1.GetIssuesStatusResponse.IssuesSummary)
| Field | Type | Description |
| --------------- | ---------------- | ------------------------------------------------------- |
| total\_count | [ int32](#int32) | Number of issues for the entity. |
| warn\_count | [ int32](#int32) | Number of issues for the entity with status 'warn'. |
| error\_count | [ int32](#int32) | Number of issues for the entity with status 'error'. |
| critical\_count | [ int32](#int32) | Number of issues for the entity with status 'critical'. |
### BrowseRequest
(synq.entities.folders.v1.BrowseRequest)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) parent.parent\_folder\_entity\_id | [ string](#string) | Opaque id of the parent folder to browse into (from `Folder.folder_entity_id`). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) parent.parent\_ref | [ FolderRef](#folderref) | Structured address of the parent folder to browse into. |
| filter | [ Query](#query) | Optional filter. When set, the returned `member_entity_ids` are limited to entities matching this query. |
### BrowseResponse
(synq.entities.folders.v1.BrowseResponse)
| Field | Type | Description |
| ------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| folders | [repeated Folder](#folder) | Direct sub-folders of the browsed location (or the roots, when no `parent` was given). |
| member\_entity\_ids | [repeated string](#string) | Opaque entity ids of the direct, non-folder members of the browsed folder. Empty when browsing the roots. Shallow by default — members of sub-folders are not included unless `depth` expanded them. |
### GetFolderOfRequest
(synq.entities.folders.v1.GetFolderOfRequest)
| Field | Type | Description |
| ----------- | -------------------------- | ------------------------------------------------------------------------------------------------------------- |
| entity\_ids | [repeated string](#string) | Opaque entity ids to look up. Ids that do not exist, or that live in no folder, are absent from the response. |
### GetFolderOfResponse
(synq.entities.folders.v1.GetFolderOfResponse)
| Field | Type | Description |
| --------------------------- | ------------------------------------------------------------- | ---------------------------------------------------- |
| breadcrumbs\_by\_entity\_id | [map BreadcrumbsByEntityIdEntry](#breadcrumbsbyentityidentry) | Requested entity id -> its containing breadcrumb(s). |
### GetFolderOfResponse.Breadcrumb
(synq.entities.folders.v1.GetFolderOfResponse.Breadcrumb)
One containing breadcrumb: the folders from a root down to (and including)
the entity's immediate parent, ordered root first.
| Field | Type | Description |
| ------- | -------------------------- | ----------- |
| folders | [repeated Folder](#folder) | none |
### GetFolderOfResponse.Breadcrumbs
(synq.entities.folders.v1.GetFolderOfResponse.Breadcrumbs)
All breadcrumbs for one entity. Most entities have a single breadcrumb; an
entity placed in several hierarchies has one per hierarchy.
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| breadcrumbs | [repeated Breadcrumb](#breadcrumb) | none |
### GetFolderOfResponse.BreadcrumbsByEntityIdEntry
(synq.entities.folders.v1.GetFolderOfResponse.BreadcrumbsByEntityIdEntry)
| Field | Type | Description |
| ----- | ---------------------------- | ----------- |
| key | [ string](#string) | none |
| value | [ Breadcrumbs](#breadcrumbs) | none |
### ListMembersRequest
(synq.entities.folders.v1.ListMembersRequest)
| Field | Type | Description |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) folder.folder\_entity\_id | [ string](#string) | Opaque id of the folder (from `Folder.folder_entity_id`). |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) folder.folder\_ref | [ FolderRef](#folderref) | Structured address of the folder. |
| deep | [ bool](#bool) | When true, include entities in all nested sub-folders. When false (default), return only the entities placed directly in this folder. |
| types | [repeated EntityType](#entitytype) | Optional entity-type filter. Empty returns all types. |
| filter | [ Query](#query) | Optional query filter. When set, only members matching this query are returned. |
| pagination | [ Pagination](#pagination) | Pagination. |
### ListMembersResponse
(synq.entities.folders.v1.ListMembersResponse)
| Field | Type | Description |
| ----------- | -------------------------- | ------------------------------------------ |
| entity\_ids | [repeated string](#string) | Opaque entity ids of the folder's members. |
| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. |
### Folder
(synq.entities.folders.v1.Folder)
Folder is one node in the folder / containment hierarchy: an integration root,
a container (database, schema, project), or a nested folder. Members that are
not themselves folders (tables, models, …) are returned as entity ids, not as
`Folder`s.
| Field | Type | Description |
| -------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| folder\_entity\_id | [ string](#string) | Opaque, authoritative id of this folder. Round-trip it verbatim as the `parent` of `Browse` or the `folder` of `ListMembers`; do not parse it. It is the canonical handle for a folder — always prefer it over rebuilding a location from `ref` when calling back in. |
| ref | [ FolderRef](#folderref) | Structured, human-friendly address of this folder. Populated when it can be derived from the surrounding hierarchy (always for `GetFolderOf`, and for `Browse` when the parent location is known). When it cannot be derived, `folder_entity_id` remains the authoritative handle. |
| name | [ string](#string) | Display name of this folder (its own leaf name, e.g. "sales"). |
| full\_name | [repeated string](#string) | Full display path from the root down to this folder (root first, leaf last), e.g. \["clickhouse-prod", "default", "sales"]. Suitable for rendering a breadcrumb. |
| type | [ EntityType](#entitytype) | Entity type of this node. Folders synthesized purely for grouping report an unspecified type; container entities that also act as folders (databases, schemas, projects) report their real type. |
| platform | [ DataPlatformType](#dataplatformtype) | Platform this folder belongs to, when known. |
| child\_folder\_count | [ uint32](#uint32) | Number of direct sub-folders. Best-effort: it may be reported as a collapsed count for lazily-loaded folders and can be 0 when the count was not loaded. |
| member\_count | [ uint32](#uint32) | Number of direct, non-folder members (entities that sit directly in this folder). Best-effort and may be 0 when not loaded. |
| role | [ FolderRole](#folderrole) | How this folder participates in browsing. |
### BatchGetEntitiesRequest
(synq.entities.entities.v1.BatchGetEntitiesRequest)
BatchGetEntitiesRequest is the request message for the BatchGetEntities method.
| Field | Type | Description |
| ----- | ---------------------------------- | ----------------------------------- |
| ids | [repeated Identifier](#identifier) | Identifiers of the entities to get. |
### BatchGetEntitiesResponse
(synq.entities.entities.v1.BatchGetEntitiesResponse)
BatchGetEntitiesResponse is the response message for the BatchGetEntities method.
| Field | Type | Description |
| -------- | -------------------------- | --------------------------------- |
| entities | [repeated Entity](#entity) | The entities that were retrieved. |
### GetEntityRequest
(synq.entities.entities.v1.GetEntityRequest)
GetEntityRequest is the request message for the GetEntity method.
| Field | Type | Description |
| ----- | -------------------------- | -------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get. |
### GetEntityResponse
(synq.entities.entities.v1.GetEntityResponse)
GetEntityResponse is the response message for the GetEntity method.
| Field | Type | Description |
| ------ | ------------------ | ------------------------------ |
| entity | [ Entity](#entity) | The entity that was retrieved. |
### ListEntitiesRequest
(synq.entities.entities.v1.ListEntitiesRequest)
| Field | Type | Description |
| ---------- | -------------------------- | ----------- |
| query | [ Query](#query) | none |
| pagination | [ Pagination](#pagination) | none |
### ListEntitiesResponse
(synq.entities.entities.v1.ListEntitiesResponse)
| Field | Type | Description |
| ----------- | ---------------------------------- | ----------- |
| page\_info | [ PageInfo](#pageinfo) | none |
| entity\_ids | [repeated Identifier](#identifier) | none |
### SearchEntitiesRequest
(synq.entities.entities.v1.SearchEntitiesRequest)
| Field | Type | Description |
| ----------------------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------- |
| query | [ string](#string) | Full text search query, it will search in name but also in description and columns of the entities |
| limit\_to\_types | [repeated EntityType](#entitytype) | Limit results to specific entity types, leave empty to use only the query |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_page.page | [optional uint32](#uint32) | none |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_limit\_per\_page.limit\_per\_page | [optional uint32](#uint32) | none |
### SearchEntitiesResponse
(synq.entities.entities.v1.SearchEntitiesResponse)
| Field | Type | Description |
| ----------------------- | -------------------------------------------------------- | ----------------------------------------------------- |
| hits | [repeated SearchHit](#searchhit) | The entities that were retrieved. |
| estimated\_total\_hits | [ uint64](#uint64) | Estimated number of all search results |
| entity\_type\_estimates | [repeated EntityTypeSearchFacet](#entitytypesearchfacet) | Estimated number of all search results by entity type |
### EntityTypeSearchFacet
(synq.entities.entities.v1.EntityTypeSearchFacet)
| Field | Type | Description |
| ------------ | -------------------------- | ----------- |
| entity\_type | [ EntityType](#entitytype) | none |
| count | [ uint32](#uint32) | none |
### SearchHit
(synq.entities.entities.v1.SearchHit)
| Field | Type | Description |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------- | ------------------------------------------------------- |
| name | [ string](#string) | Name of the found entity with optional folder like path |
| description | [ string](#string) | Description is used for display and search |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entity\_id.entity\_id | [optional Identifier](#identifier) | Identifier of the entity |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_synq\_path.synq\_path | [optional string](#string) | Coalesce Quality path, as used in frontend |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_entity\_type.entity\_type | [optional EntityType](#entitytype) | Information about entity type |
| ranking\_score | [ float](#float) | Ranking score, higher is better |
### BatchSchemaMismatchesRequest
(synq.entities.schemas.v1.BatchSchemaMismatchesRequest)
BatchGetSchemaMismatchesRequest is the request message for the BatchGetSchemaMismatches method.
| Field | Type | Description |
| ----- | ---------------------------------- | --------------------------------------------------------- |
| ids | [repeated Identifier](#identifier) | Identifiers of the entities to get schema mismatches for. |
### BatchSchemaMismatchesResponse
(synq.entities.schemas.v1.BatchSchemaMismatchesResponse)
BatchGetSchemaMismatchesResponse is the response message for the BatchGetSchemaMismatches method.
| Field | Type | Description |
| ------------------ | ------------------------------------------ | --------------------------------------------------- |
| schema\_mismatches | [repeated SchemaMismatch](#schemamismatch) | Schema mismatches found for the requested entities. |
### SchemaMismatch
(synq.entities.schemas.v1.SchemaMismatch)
SchemaMismatch represents a schema drift between a definer entity (e.g., dbt model)
and an origin entity (e.g., BigQuery table) where columns are defined but missing in origin.
| Field | Type | Description |
| ------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------- |
| definer\_id | [ Identifier](#identifier) | Identifier of the entity that defines the columns (e.g., dbt model). |
| origin\_id | [ Identifier](#identifier) | Identifier of the entity where the columns are expected but missing (e.g., BigQuery table). |
| missing\_origin\_column\_names | [repeated string](#string) | Names of the columns that are defined but missing in the origin. |
| missing\_origin\_column\_human\_names | [repeated string](#string) | Human-readable names of the columns that are defined but missing in the origin. |
### GetSchemaRequest
(synq.entities.schemas.v1.GetSchemaRequest)
GetEntityRequest is the request message for the GetEntity method.
| Field | Type | Description |
| ----- | -------------------------- | -------------------------------- |
| id | [ Identifier](#identifier) | Identifier of the entity to get. |
### GetSchemaResponse
(synq.entities.schemas.v1.GetSchemaResponse)
GetEntityResponse is the response message for the GetEntity method.
| Field | Type | Description |
| --------------------------------------------------------------------------------------------- | -------------------------- | ------------------------------------ |
| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_schema.schema | [optional Schema](#schema) | Schema of the entity, might be empty |
# Enums
### ListIncidentsRequest.Field
(synq.incidents.v1.ListIncidentsRequest.Field)
| Name | Number | Description |
| ------------------ | ------ | ----------- |
| FIELD\_UNSPECIFIED | 0 | none |
| FIELD\_CREATED\_AT | 1 | none |
| FIELD\_UPDATED\_AT | 2 | none |
### ListIncidentsRequest.Sort.Order
(synq.incidents.v1.ListIncidentsRequest.Sort.Order)
| Name | Number | Description |
| ------------------ | ------ | ----------- |
| ORDER\_UNSPECIFIED | 0 | none |
| ORDER\_ASC | 1 | none |
| ORDER\_DESC | 2 | none |
### Incident.State
(synq.incidents.v1.Incident.State)
| Name | Number | Description |
| ------------------ | ------ | ----------- |
| STATE\_UNSPECIFIED | 0 | none |
| STATE\_OPEN | 1 | none |
| STATE\_CLOSED | 2 | none |
| STATE\_CANCELLED | 3 | none |
### Config.Agent.LogLevel
(synq.agent.dwh.v1.Config.Agent.LogLevel)
| Name | Number | Description |
| ----------------------- | ------ | ---------------- |
| LOG\_LEVEL\_UNSPECIFIED | 0 | Defaults to info |
| LOG\_LEVEL\_TRACE | 1 | none |
| LOG\_LEVEL\_DEBUG | 2 | none |
| LOG\_LEVEL\_INFO | 3 | none |
| LOG\_LEVEL\_WARN | 4 | none |
| LOG\_LEVEL\_ERROR | 5 | none |
### LogLevel
(synq.agent.dwh.v1.LogLevel)
| Name | Number | Description |
| ----------------------- | ------ | ----------- |
| LOG\_LEVEL\_UNSPECIFIED | 0 | none |
| LOG\_LEVEL\_INFO | 1 | none |
| LOG\_LEVEL\_WARN | 2 | none |
| LOG\_LEVEL\_ERROR | 3 | none |
### ReconciliationRunFailureCategory
(synq.agent.recon.v1.ReconciliationRunFailureCategory)
ReconciliationRunFailureCategory classifies why a run ended in FAILED.
Clients use this to render appropriate user-facing messages.
| Name | Number | Description |
| -------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------- |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_UNSPECIFIED | 0 | none |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_CONNECTIVITY | 1 | Could not connect to source/target warehouse or other upstream. |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_CONFIG\_INVALID | 2 | Suite config or environment was rejected at execution time. |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_EXECUTION\_ERROR | 3 | Reconciliation execution itself returned an error. |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_INTERNAL | 4 | Unexpected internal error. |
| RECONCILIATION\_RUN\_FAILURE\_CATEGORY\_TIMEOUT | 5 | Run exceeded its configured wall-clock execution timeout and was cancelled before completing. |
### ReconciliationRunStatus
(synq.agent.recon.v1.ReconciliationRunStatus)
ReconciliationRunStatus is the lifecycle state of a single reconciliation run.
| Name | Number | Description |
| ----------------------------------------- | ------ | --------------------------------------------------------------------------------------------- |
| RECONCILIATION\_RUN\_STATUS\_UNSPECIFIED | 0 | none |
| RECONCILIATION\_RUN\_STATUS\_SCHEDULED | 1 | Run has been queued but not yet picked up by the worker. |
| RECONCILIATION\_RUN\_STATUS\_IN\_PROGRESS | 2 | Worker has started executing the run. |
| RECONCILIATION\_RUN\_STATUS\_SUCCEEDED | 3 | Run completed successfully. |
| RECONCILIATION\_RUN\_STATUS\_FAILED | 4 | Run completed with a failure. |
| RECONCILIATION\_RUN\_STATUS\_CANCELLED | 5 | Run was skipped or cancelled before/during execution (e.g. suite deleted, deployment paused). |
### ReconciliationRunTrigger
(synq.agent.recon.v1.ReconciliationRunTrigger)
ReconciliationRunTrigger describes why a run was created.
| Name | Number | Description |
| ----------------------------------------- | ------ | --------------------------------------------------------------------------------- |
| RECONCILIATION\_RUN\_TRIGGER\_UNSPECIFIED | 0 | none |
| RECONCILIATION\_RUN\_TRIGGER\_ADHOC | 1 | User submitted an ad-hoc suite via SubmitAdhocSuite. |
| RECONCILIATION\_RUN\_TRIGGER\_SCHEDULED | 2 | Scheduler enqueued the run from a deployment / managed-suite cron. |
| RECONCILIATION\_RUN\_TRIGGER\_API | 3 | External API call triggered the run (e.g. CI hook, future TriggerDeployment RPC). |
### HashAlgorithm
(synq.agent.recon.v1.HashAlgorithm)
HashAlgorithm specifies the hash function used for row checksums
in ROW\_CHECKSUM mode. Different databases natively support different
hash functions; choosing one supported by both sides avoids emulation overhead.
| Name | Number | Description |
| ---------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| HASH\_ALGORITHM\_UNSPECIFIED | 0 | Auto-negotiates the best common algorithm between source and target. Prefers the fastest algorithm supported natively by both databases. |
| HASH\_ALGORITHM\_MD5 | 1 | MD5 — widely supported across all databases. Slowest but most compatible. |
| HASH\_ALGORITHM\_FARM\_FINGERPRINT | 2 | FarmHash Fingerprint64 — native to BigQuery. Fast for BigQuery-to-BigQuery. |
| HASH\_ALGORITHM\_XXHASH64 | 3 | xxHash64 — native to Databricks and Snowflake. Fast for those dialects. |
### MismatchDetailLevel
(synq.agent.recon.v1.MismatchDetailLevel)
MismatchDetailLevel controls how much detail is included in results for mismatched rows.
Levels are ordered by increasing data exposure.
| Name | Number | Description |
| ------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| MISMATCH\_DETAIL\_LEVEL\_UNSPECIFIED | 0 | Default: COUNT\_ONLY. |
| MISMATCH\_DETAIL\_LEVEL\_COUNT\_ONLY | 1 | Only report mismatch counts per segment. No row-level information is exposed. Privacy-safe. |
| MISMATCH\_DETAIL\_LEVEL\_WITH\_KEYS | 2 | Include primary key values of mismatched rows. Reveals which rows differ, but not the actual data values. |
| MISMATCH\_DETAIL\_LEVEL\_DETAILED | 3 | Include full column values for mismatched rows. Requires consent\_acknowledged = true. Warning: may expose sensitive data in the audit log. |
### ReconciliationFailureImpact
(synq.agent.recon.v1.ReconciliationFailureImpact)
ReconciliationFailureImpact controls whether a reconciliation case's referenced
tables (resolved from the source/target SQL at deploy time) inherit the
case's failure status, or are only attached to the run for visibility.
This is a deployment-time policy, not part of the suite YAML — it is
set on PromoteSuite / UpdateDeploymentCaseImpacts and stored on the
promoted deployment, not on the authored config. Letting operators
flip impact without editing the suite keeps configuration declarative
and lets the FE offer "apply to all" without round-tripping YAML.
| Name | Number | Description |
| --------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| RECONCILIATION\_FAILURE\_IMPACT\_UNSPECIFIED | 0 | Defaults to RAISE\_ISSUE\_ON\_TABLES. |
| RECONCILIATION\_FAILURE\_IMPACT\_RAISE\_ISSUE\_ON\_TABLES | 1 | The referenced tables are treated as outcomes of the run: a failed case opens issues on each table, and the table's overall health reflects the reconciliation result. Use this when the reconciliation authoritatively validates the tables it references. |
| RECONCILIATION\_FAILURE\_IMPACT\_SHOW\_ON\_TABLES | 2 | The referenced tables appear on the run for visibility only. The run is listed in each table's run history but never raises an issue on them. Use this for advisory checks that should not impact the table's published health. |
### ReconciliationMode
(synq.agent.recon.v1.ReconciliationMode)
ReconciliationMode defines the comparison strategy for a reconciliation.
Modes are ordered by depth of comparison: ROW\_COUNT \< ROW\_CHECKSUM \< AGGREGATE.
| Name | Number | Description |
| ----------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| RECONCILIATION\_MODE\_UNSPECIFIED | 0 | none |
| RECONCILIATION\_MODE\_ROW\_COUNT | 1 | Compare row counts only — no data access, just verifies both sides have the same number of rows. Fastest mode, useful as a smoke test. |
| RECONCILIATION\_MODE\_ROW\_CHECKSUM | 2 | Row-level checksum comparison with hierarchical bisection drill-down to locate individual mismatched rows. The default and most thorough mode for exact row-by-row comparison. |
| RECONCILIATION\_MODE\_AGGREGATE | 3 | Aggregate comparison — GROUP BY with configurable measures (SUM, AVG, etc.) and tolerance thresholds. Best for large datasets where exact row matching is impractical, or when business-level metrics matter more than individual rows. |
### SegmentationStrategy
(synq.agent.recon.v1.SegmentationStrategy)
SegmentationStrategy defines how key ranges are split during bisection.
The strategy affects both performance and privacy characteristics.
| Name | Number | Description |
| ----------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SEGMENTATION\_STRATEGY\_UNSPECIFIED | 0 | Auto: defaults to quantile. |
| SEGMENTATION\_STRATEGY\_QUANTILE | 1 | NTILE-based key-range splitting. Uses the key column's actual values to create equal-count segments. Note: exposes key values in segment boundaries in the audit log. |
| SEGMENTATION\_STRATEGY\_HASH | 2 | Hash-based bucketing followed by range drill-down. Uses a hash of the key column for segmentation. Privacy-safe: does not expose raw key values in the audit log. |
| SEGMENTATION\_STRATEGY\_TIME | 3 | Time-based partitioning followed by range drill-down. Splits by time buckets using the configured time\_column and time\_granularity. Requires time\_column to be set. Best for time-series data with a natural temporal ordering (e.g., event logs, daily snapshots). |
### TimeGranularity
(synq.agent.recon.v1.TimeGranularity)
TimeGranularity defines the granularity for time-based segmentation.
| Name | Number | Description |
| ------------------------------ | ------ | ------------- |
| TIME\_GRANULARITY\_UNSPECIFIED | 0 | Default: DAY. |
| TIME\_GRANULARITY\_HOUR | 1 | none |
| TIME\_GRANULARITY\_DAY | 2 | none |
| TIME\_GRANULARITY\_WEEK | 3 | none |
| TIME\_GRANULARITY\_MONTH | 4 | none |
| TIME\_GRANULARITY\_QUARTER | 5 | none |
| TIME\_GRANULARITY\_YEAR | 6 | none |
### WindowStrategy
(synq.agent.recon.v1.WindowStrategy)
WindowStrategy defines how the time window boundaries are computed.
| Name | Number | Description |
| ----------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------ |
| WINDOW\_STRATEGY\_UNSPECIFIED | 0 | Default: SLIDING. |
| WINDOW\_STRATEGY\_SLIDING | 1 | Sliding window: window\_start = now - lookback. Each run covers a different absolute time range. |
| WINDOW\_STRATEGY\_FIXED | 2 | Fixed window: boundaries are aligned to calendar periods. Each run within the same period covers the same absolute time range. |
### AggregateDivergenceType
(synq.agent.recon.v1.AggregateDivergenceType)
AggregateDivergenceType categorizes how an aggregate group diverges.
| Name | Number | Description |
| ------------------------------------------------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AGGREGATE\_DIVERGENCE\_TYPE\_UNSPECIFIED | 0 | none |
| AGGREGATE\_DIVERGENCE\_TYPE\_SUBGROUP\_MISMATCH | 1 | The group is present on both sides and its measures diverge, at a level that still has a grouping level beneath it. Where drill\_down is populated the divergence is accounted for by the descendants, so this node is a path to the mismatches rather than a mismatch in its own right. Only when drill\_down is absent does it stand as the mismatch itself. |
| AGGREGATE\_DIVERGENCE\_TYPE\_MISSING\_IN\_SOURCE | 2 | Group exists in target but not in source. |
| AGGREGATE\_DIVERGENCE\_TYPE\_MISSING\_IN\_TARGET | 3 | Group exists in source but not in target. |
| AGGREGATE\_DIVERGENCE\_TYPE\_MEASURE\_MISMATCH | 4 | The group is present on both sides and its measures diverge at the deepest grouping level, so it is a mismatch in its own right and carries the investigation queries. Not a synonym for MISMATCH: the two differ by whether anything is grouped below, and only this one is counted directly in the divergent-group totals. |
### AuditOutcome
(synq.agent.recon.v1.AuditOutcome)
AuditOutcome describes the overall outcome of a reconciliation run.
Values are ordered by severity: passed \< within\_threshold \< mismatched \< failed.
| Name | Number | Description |
| --------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| AUDIT\_OUTCOME\_UNSPECIFIED | 0 | none |
| AUDIT\_OUTCOME\_PASSED | 1 | All reconciliations completed and matched exactly. |
| AUDIT\_OUTCOME\_MISMATCHED\_WITHIN\_THRESHOLD | 2 | Differences were found but all were within configured thresholds. No reconciliation had hard mismatches or infrastructure errors. This is a warning-level outcome. |
| AUDIT\_OUTCOME\_MISMATCHED | 3 | At least one reconciliation found data differences exceeding configured thresholds (or no thresholds were configured). |
| AUDIT\_OUTCOME\_FAILED | 4 | At least one reconciliation encountered an infrastructure error (connection failure, query error, setup failure, etc.). |
### DrillStopReason
(synq.agent.recon.v1.DrillStopReason)
DrillStopReason explains why bisection stopped at a particular node.
| Name | Number | Description |
| ---------------------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DRILL\_STOP\_REASON\_UNSPECIFIED | 0 | none |
| DRILL\_STOP\_REASON\_THRESHOLD\_REACHED | 1 | The segment narrowed to at most the configured number of rows, so it is reported as-is. Drilling further would still narrow it, which is why this and MAX\_DEPTH\_REACHED are the two reasons a later run can resume from. |
| DRILL\_STOP\_REASON\_MAX\_DEPTH\_REACHED | 2 | The configured depth limit was hit before the segment got small enough. Resumable: raising the limit and drilling again narrows it further. |
| DRILL\_STOP\_REASON\_EMPTY\_SEGMENT | 3 | Neither side had any rows in the segment, so there was nothing to compare. |
| DRILL\_STOP\_REASON\_CANNOT\_SPLIT | 4 | The key range cannot be subdivided any further — every remaining row shares one key value. Unlike the two resumable reasons above, drilling again will not narrow this segment. |
| DRILL\_STOP\_REASON\_MATCHED | 5 | Source and target agreed, so the segment needed no further drilling. |
| DRILL\_STOP\_REASON\_ERROR | 6 | A query failed while comparing the segment; its result is unknown rather than matched or mismatched. The failure is on the run's query records. |
### MeasureVerdictReason
(synq.agent.recon.v1.MeasureVerdictReason)
MeasureVerdictReason explains the threshold evaluation outcome.
MeasureVerdictReason explains why a measure was or was not treated as
diverging. Thresholds are tried in order — absolute first, then percentage —
and the first one the difference falls inside decides the verdict.
| Name | Number | Description |
| ------------------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| MEASURE\_VERDICT\_REASON\_UNSPECIFIED | 0 | none |
| MEASURE\_VERDICT\_REASON\_EXACT\_MATCH | 1 | Source and target agreed exactly, so no threshold was consulted. |
| MEASURE\_VERDICT\_REASON\_WITHIN\_ABSOLUTE\_THRESHOLD | 2 | The values differ, but by no more than the configured absolute threshold. Not treated as divergent. |
| MEASURE\_VERDICT\_REASON\_WITHIN\_PERCENTAGE\_THRESHOLD | 3 | The values differ by more than the absolute threshold allowed (or none was set), but fall inside the configured percentage threshold. Not treated as divergent. The percentage is computed against whichever side the PercentageBasis selects. |
| MEASURE\_VERDICT\_REASON\_EXCEEDED\_ALL\_THRESHOLDS | 4 | The values differ by more than every configured threshold. Divergent. |
| MEASURE\_VERDICT\_REASON\_NO\_THRESHOLDS\_CONFIGURED | 5 | The values differ and no threshold was configured to tolerate it, so any difference counts. Divergent — distinct from EXCEEDED\_ALL\_THRESHOLDS, where thresholds existed and were exceeded. |
### QueryRole
(synq.agent.recon.v1.QueryRole)
QueryRole identifies whether a query targets the source or target database.
| Name | Number | Description |
| ------------------------ | ------ | ----------- |
| QUERY\_ROLE\_UNSPECIFIED | 0 | none |
| QUERY\_ROLE\_SOURCE | 1 | none |
| QUERY\_ROLE\_TARGET | 2 | none |
### ReconciliationOutcome
(synq.agent.recon.v1.ReconciliationOutcome)
ReconciliationOutcome describes the outcome of a single reconciliation.
Distinguishes infrastructure errors from data comparison results.
Values are ordered by severity: passed \< within\_threshold \< mismatched \< failed.
| Name | Number | Description |
| ------------------------------------------------------ | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| RECONCILIATION\_OUTCOME\_UNSPECIFIED | 0 | none |
| RECONCILIATION\_OUTCOME\_PASSED | 1 | Reconciliation completed and data matched exactly — no differences found. |
| RECONCILIATION\_OUTCOME\_MISMATCHED\_WITHIN\_THRESHOLD | 2 | Reconciliation found data differences but all differences were within configured thresholds. This is a warning-level outcome — data differs but within acceptable tolerance. |
| RECONCILIATION\_OUTCOME\_MISMATCHED | 3 | Reconciliation completed but found data differences that exceed configured thresholds (or no thresholds were configured). |
| RECONCILIATION\_OUTCOME\_FAILED | 4 | Reconciliation encountered an infrastructure error (connection failure, query error, setup failure, etc.) and could not complete the comparison. |
### RowMismatchType
(synq.agent.recon.v1.RowMismatchType)
RowMismatchType categorizes a single row-level mismatch.
The source/target sense of these values matches SegmentMismatchType and
AggregateDivergenceType: source is numbered before target everywhere.
| Name | Number | Description |
| ---------------------------------------- | ------ | ------------------------------------------------------------ |
| ROW\_MISMATCH\_TYPE\_UNSPECIFIED | 0 | none |
| ROW\_MISMATCH\_TYPE\_MISSING\_IN\_SOURCE | 1 | The row is present in the target but absent from the source. |
| ROW\_MISMATCH\_TYPE\_MISSING\_IN\_TARGET | 2 | The row is present in the source but absent from the target. |
| ROW\_MISMATCH\_TYPE\_MODIFIED | 3 | The row exists on both sides but its contents differ. |
### SegmentMismatchType
(synq.agent.recon.v1.SegmentMismatchType)
SegmentMismatchType categorizes how rows differ between source and target.
A mismatch leaf carries every type that applies, so a segment whose two
sides differ in both row count and content reports COUNT\_MISMATCH and
DATA\_MISMATCH together.
| Name | Number | Description |
| -------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| SEGMENT\_MISMATCH\_TYPE\_UNSPECIFIED | 0 | none |
| SEGMENT\_MISMATCH\_TYPE\_MISSING\_IN\_SOURCE | 1 | The segment holds rows on the target side but none on the source side. |
| SEGMENT\_MISMATCH\_TYPE\_MISSING\_IN\_TARGET | 2 | The segment holds rows on the source side but none on the target side. |
| SEGMENT\_MISMATCH\_TYPE\_COUNT\_MISMATCH | 3 | Both sides hold rows, but not the same number of them. |
| SEGMENT\_MISMATCH\_TYPE\_DATA\_MISMATCH | 4 | Both sides hold rows and their checksums disagree, so at least one row differs in content. Reported independently of the row counts. |
| SEGMENT\_MISMATCH\_TYPE\_UNKNOWN | 5 | The segment was reported as mismatched but none of the categories above applied. Distinct from UNSPECIFIED, which means the field was never set. |
### StageType
(synq.agent.recon.v1.StageType)
StageType identifies the type of reconciliation stage.
| Name | Number | Description |
| ----------------------------- | ------ | ----------------------------------------------------------- |
| STAGE\_TYPE\_UNSPECIFIED | 0 | none |
| STAGE\_TYPE\_QUICK\_CHECK | 1 | Single-query count + checksum comparison. |
| STAGE\_TYPE\_BISECTION\_DRILL | 2 | Recursive bisection drill-down to locate mismatches. |
| STAGE\_TYPE\_AGGREGATE\_CHECK | 3 | Aggregate GROUP BY comparison with measures and thresholds. |
### ResumeMode
(synq.agent.recon.v1.ResumeMode)
ResumeMode selects which replay a ResumeFromRun performs.
| Name | Number | Description |
| --------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| RESUME\_MODE\_UNSPECIFIED | 0 | none |
| RESUME\_MODE\_RECHECK | 1 | Re-run the parent's queries and report what changed: fixed, still mismatched, regressed or unchanged. |
| RESUME\_MODE\_DRILL\_DEEPER | 2 | Continue the parent's drill from where it stopped — the mismatch segments a bisection left open, or the divergent groups an aggregate found — instead of re-drilling the whole dataset from the top. |
### DeploymentAction
(synq.agent.recon.v1.DeploymentAction)
| Name | Number | Description |
| --------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| DEPLOYMENT\_ACTION\_UNSPECIFIED | 0 | none |
| DEPLOYMENT\_ACTION\_PROMOTED | 1 | The suite reached production for the first time, under a new deployment id. Only PROMOTED and REPROMOTED replace the frozen suite snapshot; every other action carries the previous snapshot forward unchanged. |
| DEPLOYMENT\_ACTION\_REPROMOTED | 2 | A suite already in production was published again, keeping its deployment id and replacing the frozen snapshot with the current configuration. |
| DEPLOYMENT\_ACTION\_SCHEDULE\_CHANGED | 3 | The run schedule changed. The suite configuration itself is untouched. |
| DEPLOYMENT\_ACTION\_MAPPINGS\_CHANGED | 4 | The bindings from the suite's connection names to workspace integrations changed. |
| DEPLOYMENT\_ACTION\_PAUSED | 5 | Scheduled runs were suspended. The deployment stays in production. |
| DEPLOYMENT\_ACTION\_RESUMED | 6 | Scheduled runs were re-enabled after a pause. |
| DEPLOYMENT\_ACTION\_UNPROMOTED | 7 | The suite was withdrawn from production. Distinct from PAUSED: this retires the deployment rather than suspending its schedule. |
| DEPLOYMENT\_ACTION\_ANNOTATIONS\_CHANGED | 8 | The annotations attached to the deployment changed. |
| DEPLOYMENT\_ACTION\_FAILURE\_IMPACTS\_CHANGED | 9 | The per-reconciliation failure impact settings changed — which tables a failing reconciliation raises an issue on. |
### UnresolvedConnectionReason
(synq.agent.recon.v1.UnresolvedConnectionReason)
Reason why a single connection could not be resolved.
| Name | Number | Description |
| -------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UNRESOLVED\_CONNECTION\_REASON\_UNSPECIFIED | 0 | none |
| UNRESOLVED\_CONNECTION\_REASON\_NOT\_PROVIDED | 1 | No mapping was supplied and no workspace integration matches the connection name. |
| UNRESOLVED\_CONNECTION\_REASON\_INTEGRATION\_NOT\_FOUND | 2 | Mapping references an integration that does not exist or the caller cannot see it. |
| UNRESOLVED\_CONNECTION\_REASON\_CREDENTIAL\_NOT\_ALLOWED | 3 | Mapping uses a credential plane the caller is not allowed to use (e.g. user\_integration\_id without a user identity, or workspace integration\_id without SCOPE\_INTEGRATION\_EDIT). |
| UNRESOLVED\_CONNECTION\_REASON\_CAPABILITY\_DISABLED | 4 | Integration exists but the allow\_reconciliation\_adhoc / allow\_reconciliation\_deploy capability gate is disabled for it. |
### AggregateFunction
(synq.agent.recon.v1.AggregateFunction)
AggregateFunction defines the supported SQL aggregate functions
for measure comparisons in aggregate reconciliation mode.
| Name | Number | Description |
| -------------------------------- | ------ | --------------------------------------------------- |
| AGGREGATE\_FUNCTION\_UNSPECIFIED | 0 | none |
| AGGREGATE\_FUNCTION\_SUM | 1 | SQL SUM() — total of all values in the group. |
| AGGREGATE\_FUNCTION\_COUNT | 2 | SQL COUNT() — number of rows in the group. |
| AGGREGATE\_FUNCTION\_AVG | 3 | SQL AVG() — arithmetic mean of values in the group. |
| AGGREGATE\_FUNCTION\_MIN | 4 | SQL MIN() — smallest value in the group. |
| AGGREGATE\_FUNCTION\_MAX | 5 | SQL MAX() — largest value in the group. |
### PercentageBasis
(synq.agent.recon.v1.PercentageBasis)
PercentageBasis controls which percentage formula is used for threshold comparison.
The choice affects how "big" a difference appears when source and target values
differ in magnitude.
| Name | Number | Description | | | | | | |
| ------------------------------ | ------ | ---------------- | ---- | --- | ------ | --------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------ |
| PERCENTAGE\_BASIS\_UNSPECIFIED | 0 | Default: source. | | | | | | |
| PERCENTAGE\_BASIS\_SOURCE | 1 | | diff | / | source | — "target is X% off from source." Best when source is the authoritative baseline. | | |
| PERCENTAGE\_BASIS\_TARGET | 2 | | diff | / | target | — "source is X% off from target." Best when target is the authoritative baseline. | | |
| PERCENTAGE\_BASIS\_SYMMETRIC | 3 | 2 \* | diff | / ( | source | + | target | ) — symmetric, neither side is privileged. Best when both sides are equally authoritative. |
### CutoffAggregateFunction
(synq.agent.recon.v1.CutoffAggregateFunction)
CutoffAggregateFunction defines the aggregate function for watermark derivation.
| Name | Number | Description |
| ---------------------------------------- | ------ | ------------- |
| CUTOFF\_AGGREGATE\_FUNCTION\_UNSPECIFIED | 0 | Default: MAX. |
| CUTOFF\_AGGREGATE\_FUNCTION\_MAX | 1 | none |
| CUTOFF\_AGGREGATE\_FUNCTION\_MIN | 2 | none |
### CutoffCombineStrategy
(synq.agent.recon.v1.CutoffCombineStrategy)
CutoffCombineStrategy defines how to combine watermarks from source and target.
| Name | Number | Description |
| -------------------------------------- | ------ | --------------------------------------------------------------- |
| CUTOFF\_COMBINE\_STRATEGY\_UNSPECIFIED | 0 | Default: MIN. |
| CUTOFF\_COMBINE\_STRATEGY\_MIN | 1 | Use the smaller of source and target watermarks (safe default). |
| CUTOFF\_COMBINE\_STRATEGY\_MAX | 2 | Use the larger of source and target watermarks. |
| CUTOFF\_COMBINE\_STRATEGY\_SOURCE | 3 | Use only the source watermark (target must not be configured). |
| CUTOFF\_COMBINE\_STRATEGY\_TARGET | 4 | Use only the target watermark (source must not be configured). |
### CutoffTruncateUnit
(synq.agent.recon.v1.CutoffTruncateUnit)
CutoffTruncateUnit defines time truncation for the cutoff value.
| Name | Number | Description |
| ----------------------------------- | ------ | ------------------------ |
| CUTOFF\_TRUNCATE\_UNIT\_UNSPECIFIED | 0 | No truncation (default). |
| CUTOFF\_TRUNCATE\_UNIT\_HOUR | 1 | none |
| CUTOFF\_TRUNCATE\_UNIT\_DAY | 2 | none |
| CUTOFF\_TRUNCATE\_UNIT\_WEEK | 3 | none |
| CUTOFF\_TRUNCATE\_UNIT\_MONTH | 4 | none |
| CUTOFF\_TRUNCATE\_UNIT\_QUARTER | 5 | none |
| CUTOFF\_TRUNCATE\_UNIT\_YEAR | 6 | none |
### PromptField
(synq.agent.sre.v1.PromptField)
PromptField identifies which SRE agent system-prompt a suggestion targets.
Mirrors the four `*_system_prompt` fields returned by `GetConfig`.
| Name | Number | Description |
| ------------------------------ | ------ | ----------- |
| PROMPT\_FIELD\_UNSPECIFIED | 0 | none |
| PROMPT\_FIELD\_TRIAGE | 1 | none |
| PROMPT\_FIELD\_TESTER | 2 | none |
| PROMPT\_FIELD\_WORKSPACE | 3 | none |
| PROMPT\_FIELD\_ISSUE\_GROUPING | 4 | none |
### PromptSuggestionStatus
(synq.agent.sre.v1.PromptSuggestionStatus)
PromptSuggestionStatus is the review lifecycle of a single prompt suggestion.
`SUPERSEDED` indicates a newer pending suggestion for the same field replaced
this one before it was reviewed.
| Name | Number | Description |
| --------------------------------------- | ------ | ----------- |
| PROMPT\_SUGGESTION\_STATUS\_UNSPECIFIED | 0 | none |
| PROMPT\_SUGGESTION\_STATUS\_PENDING | 1 | none |
| PROMPT\_SUGGESTION\_STATUS\_ACCEPTED | 2 | none |
| PROMPT\_SUGGESTION\_STATUS\_DISMISSED | 3 | none |
| PROMPT\_SUGGESTION\_STATUS\_SUPERSEDED | 4 | none |
### IssueTriageStatus
(synq.agent.sre.v1.IssueTriageStatus)
IssueTriageStatus represents the current stage of an issue in the SRE agent's investigation workflow.
The status progresses as the agent collects evidence and reaches conclusions about the issue.
| Name | Number | Description |
| ----------------------------------- | ------ | ---------------------------------------------------------------------------------------------- |
| ISSUE\_TRIAGE\_STATUS\_UNSPECIFIED | 0 | Default value, should not be used |
| ISSUE\_TRIAGE\_STATUS\_SCHEDULED | 1 | Issue has been queued for investigation but the SRE agent has not started processing it yet |
| ISSUE\_TRIAGE\_STATUS\_IN\_PROGRESS | 2 | SRE agent is actively investigating the issue, collecting evidence and analyzing the situation |
| ISSUE\_TRIAGE\_STATUS\_CANCELLED | 7 | Issue has been scheduled but later cancelled |
| ISSUE\_TRIAGE\_STATUS\_FAILED | 8 | Issue wasn't triaged as such process failed. Scheduling again is possible. |
| ISSUE\_TRIAGE\_STATUS\_TRIAGED | 3 | SRE agent has generated conclusion for the issue |
| ISSUE\_TRIAGE\_STATUS\_ACCEPTED | 4 | User accepted the issue conclusion SRE agent has determined |
| ISSUE\_TRIAGE\_STATUS\_IGNORED | 5 | User Discarded the issue conclusion SRE agent has determined |
| ISSUE\_TRIAGE\_STATUS\_CLOSED | 6 | Issue was closed by the system |
### TriageFailureCategory
(synq.agent.sre.v1.TriageFailureCategory)
TriageFailureCategory classifies why a triage attempt failed.
The frontend can use this to render appropriate user-facing messages and actions.
| Name | Number | Description |
| ------------------------------------------------- | ------ | ---------------------------------------------------------------------------- |
| TRIAGE\_FAILURE\_CATEGORY\_UNSPECIFIED | 0 | Default value, should not be used |
| TRIAGE\_FAILURE\_CATEGORY\_BUDGET\_EXCEEDED | 1 | Daily AI budget limit reached, triage will resume automatically the next day |
| TRIAGE\_FAILURE\_CATEGORY\_CONTEXT\_TOO\_LARGE | 2 | Issue context is too large for the AI agent to process |
| TRIAGE\_FAILURE\_CATEGORY\_MAX\_ITERATIONS | 3 | AI agent couldn't reach a conclusion within the allowed number of steps |
| TRIAGE\_FAILURE\_CATEGORY\_INVALID\_AGENT\_OUTPUT | 4 | AI agent produced an invalid or unparseable response |
| TRIAGE\_FAILURE\_CATEGORY\_CONNECTIVITY | 5 | Temporary connectivity issue to upstream services |
| TRIAGE\_FAILURE\_CATEGORY\_RESOURCE\_NOT\_FOUND | 6 | Referenced resource (e.g. monitor) no longer exists |
| TRIAGE\_FAILURE\_CATEGORY\_INTERNAL | 7 | An unexpected internal error occurred |
### MessageRole
(synq.agent.sre.v1.MessageRole)
Role of the message in the conversation.
| Name | Number | Description |
| -------------------------- | ------ | ------------------------------- |
| MESSAGE\_ROLE\_UNSPECIFIED | 0 | none |
| MESSAGE\_ROLE\_USER | 1 | Message from the user/human. |
| MESSAGE\_ROLE\_ASSISTANT | 2 | Message from the assistant/LLM. |
### ModelType
(synq.agent.sre.v1.ModelType)
Type of model to use for the evaluation.
| Name | Number | Description |
| ------------------------ | ------ | ------------------------------------------------------------------------------------------------------ |
| MODEL\_TYPE\_UNSPECIFIED | 0 | none |
| MODEL\_TYPE\_SUMMARY | 1 | Summary model - faster and cheaper, suitable for simple tasks. This is the default when not specified. |
| MODEL\_TYPE\_THINKING | 2 | Thinking model - more capable, suitable for complex reasoning tasks. |
### TestSuggestionStatus
(synq.agent.sre.v1.TestSuggestionStatus)
| Name | Number | Description |
| ------------------------------------- | ------ | ----------- |
| TEST\_SUGGESTION\_STATUS\_UNSPECIFIED | 0 | none |
| TEST\_SUGGESTION\_STATUS\_SCHEDULED | 1 | none |
| TEST\_SUGGESTION\_STATUS\_RUNNING | 2 | none |
| TEST\_SUGGESTION\_STATUS\_COMPLETED | 3 | none |
| TEST\_SUGGESTION\_STATUS\_FAILED | 4 | none |
| TEST\_SUGGESTION\_STATUS\_CANCELLED | 5 | none |
### QueryOperand
(synq.queries.v1.QueryOperand)
QueryOperand defines how multiple QueryParts within a Query are combined.
| Name | Number | Description |
| --------------------------- | ------ | -------------------------------------------------------------------------------------------------------------- |
| QUERY\_OPERAND\_UNSPECIFIED | 0 | Defaults to AND behaviour. |
| QUERY\_OPERAND\_AND | 1 | Intersection: returns only entities present in ALL parts. |
| QUERY\_OPERAND\_OR | 2 | Union: returns entities present in ANY part. |
| QUERY\_OPERAND\_EXCEPT | 3 | Set difference: requires exactly 2 parts. Returns entities from parts\[0] that are NOT in parts\[1]. |
| QUERY\_OPERAND\_UPSTREAM | 4 | Lineage traversal: returns all upstream dependencies of the entities matched by the parts (combined with AND). |
| QUERY\_OPERAND\_DOWNSTREAM | 5 | Lineage traversal: returns all downstream dependents of the entities matched by the parts (combined with AND). |
### Domain.Source
(synq.domains.v1.Domain.Source)
| Name | Number | Description |
| ------------- | ------ | ----------------------------------------- |
| SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_ATLAN | 1 | none |
### Domain.Source
(synq.domains.v2.Domain.Source)
Where this domain is managed. Domains from an external source are read-only
in the app.
| Name | Number | Description |
| ------------- | ------ | ----------------------------------------- |
| SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_ATLAN | 1 | none |
### DataPlatformType
(synq.platforms.v1.DataPlatformType)
| Name | Number | Description |
| --------------------------------------- | ------ | ----------- |
| DATA\_PLATFORM\_TYPE\_UNSPECIFIED | 0 | none |
| DATA\_PLATFORM\_TYPE\_BIGQUERY | 10 | none |
| DATA\_PLATFORM\_TYPE\_LOOKER | 20 | none |
| DATA\_PLATFORM\_TYPE\_DBT | 30 | none |
| DATA\_PLATFORM\_TYPE\_DBT\_CLOUD | 31 | none |
| DATA\_PLATFORM\_TYPE\_DBT\_SELF\_HOSTED | 32 | none |
| DATA\_PLATFORM\_TYPE\_SNOWFLAKE | 50 | none |
| DATA\_PLATFORM\_TYPE\_GCP | 60 | none |
| DATA\_PLATFORM\_TYPE\_GIT | 70 | none |
| DATA\_PLATFORM\_TYPE\_GITHUB | 71 | none |
| DATA\_PLATFORM\_TYPE\_REDSHIFT | 80 | none |
| DATA\_PLATFORM\_TYPE\_TABLEAU | 110 | none |
| DATA\_PLATFORM\_TYPE\_AIRFLOW | 120 | none |
| DATA\_PLATFORM\_TYPE\_CLICKHOUSE | 130 | none |
| DATA\_PLATFORM\_TYPE\_POSTGRES | 160 | none |
| DATA\_PLATFORM\_TYPE\_MYSQL | 170 | none |
| DATA\_PLATFORM\_TYPE\_DATABRICKS | 180 | none |
| DATA\_PLATFORM\_TYPE\_SQLMESH | 190 | none |
| DATA\_PLATFORM\_TYPE\_DUCKDB | 200 | none |
| DATA\_PLATFORM\_TYPE\_TRINO | 210 | none |
| DATA\_PLATFORM\_TYPE\_ATLAN | 220 | none |
| DATA\_PLATFORM\_TYPE\_COALESCE | 230 | none |
| DATA\_PLATFORM\_TYPE\_CASTORDOC | 240 | none |
| DATA\_PLATFORM\_TYPE\_POWERBI | 300 | none |
| DATA\_PLATFORM\_TYPE\_THOUGHTSPOT | 310 | none |
| DATA\_PLATFORM\_TYPE\_SIGMA | 320 | none |
| DATA\_PLATFORM\_TYPE\_DOMO | 330 | none |
| DATA\_PLATFORM\_TYPE\_MSSQL | 340 | none |
| DATA\_PLATFORM\_TYPE\_ORACLE | 350 | none |
| DATA\_PLATFORM\_TYPE\_ATHENA | 360 | none |
| DATA\_PLATFORM\_TYPE\_FABRIC | 370 | none |
| DATA\_PLATFORM\_TYPE\_SYNQ | 1000 | none |
### Event.EventType
(synq.webhooks.v1.Event.EventType)
| Name | Number | Description |
| ----------------------------------- | ------ | ----------- |
| EVENT\_TYPE\_UNSPECIFIED | 0 | none |
| EVENT\_TYPE\_PING | 10 | none |
| EVENT\_TYPE\_ISSUE\_CREATED | 11 | none |
| EVENT\_TYPE\_ISSUE\_UPDATED | 12 | none |
| EVENT\_TYPE\_ISSUE\_STATUS\_UPDATED | 13 | none |
| EVENT\_TYPE\_ISSUE\_CLOSED | 14 | none |
| EVENT\_TYPE\_INCIDENT\_OPEN | 20 | none |
| EVENT\_TYPE\_INCIDENT\_CLOSED | 21 | none |
| EVENT\_TYPE\_INCIDENT\_CANCELLED | 22 | none |
### IssueSummary.IssueStatus
(synq.webhooks.v1.IssueSummary.IssueStatus)
| Name | Number | Description |
| --------------------------------- | ------ | ----------- |
| ISSUE\_STATUS\_UNSPECIFIED | 0 | none |
| ISSUE\_STATUS\_INVESTIGATING | 1 | none |
| ISSUE\_STATUS\_EXPECTED | 2 | none |
| ISSUE\_STATUS\_FIXED | 3 | none |
| ISSUE\_STATUS\_NO\_ACTION\_NEEDED | 4 | none |
### Dataproduct.Priority
(synq.dataproducts.v1.Dataproduct.Priority)
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| PRIORITY\_UNSPECIFIED | 0 | none |
| PRIORITY\_P3 | 3 | none |
| PRIORITY\_P2 | 4 | none |
| PRIORITY\_P1 | 5 | none |
### Dataproduct.Source
(synq.dataproducts.v1.Dataproduct.Source)
| Name | Number | Description |
| ------------- | ------ | ----------------------------------------- |
| SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_ATLAN | 1 | none |
### Dataproduct.Priority
(synq.dataproducts.v2.Dataproduct.Priority)
Priority. P1 is the highest.
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| PRIORITY\_UNSPECIFIED | 0 | none |
| PRIORITY\_P3 | 3 | none |
| PRIORITY\_P2 | 4 | none |
| PRIORITY\_P1 | 5 | none |
### Dataproduct.Source
(synq.dataproducts.v2.Dataproduct.Source)
Where this data product is managed. Products from an external source
(e.g. Atlan) are read-only in the app.
| Name | Number | Description |
| ------------- | ------ | ----------------------------------------- |
| SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_ATLAN | 1 | none |
### Severity
(synq.v1.Severity)
| Name | Number | Description |
| --------------------- | ------ | ---------------------------- |
| SEVERITY\_UNSPECIFIED | 0 | Invalid/unspecified severity |
| SEVERITY\_WARN | 1 | Warning level failures |
| SEVERITY\_ERROR | 2 | Error level failures |
| SEVERITY\_FATAL | 3 | Fatal/critical failures |
### Scope
(synq.v1.Scope)
| Name | Number | Description |
| ---------------------------------------- | ------ | ----------- |
| SCOPE\_UNSPECIFIED | 0 | none |
| SCOPE\_ISSUES\_EDIT | 10 | none |
| SCOPE\_ISSUES\_READ | 11 | none |
| SCOPE\_INCIDENTS\_EDIT | 13 | none |
| SCOPE\_INCIDENTS\_READ | 14 | none |
| SCOPE\_ENTITY\_EDIT | 30 | none |
| SCOPE\_ENTITY\_READ | 31 | none |
| SCOPE\_ENTITY\_TYPE\_EDIT | 32 | none |
| SCOPE\_ENTITY\_TYPE\_READ | 33 | none |
| SCOPE\_LINEAGE\_EDIT | 34 | none |
| SCOPE\_LINEAGE\_READ | 35 | none |
| SCOPE\_CODE\_READ | 37 | none |
| SCOPE\_STATUS\_READ | 40 | none |
| SCOPE\_INGEST\_DBT | 41 | none |
| SCOPE\_INGEST\_SQLMESH | 42 | none |
| SCOPE\_INGEST\_DWH | 43 | none |
| SCOPE\_INGEST\_SRE | 44 | none |
| SCOPE\_INGEST\_AIRFLOW | 45 | none |
| SCOPE\_INGEST\_CLOUDWATCH | 46 | none |
| SCOPE\_INGEST\_OPENLINEAGE | 47 | none |
| SCOPE\_DATACHECKS\_SQLTESTS\_EDIT | 50 | none |
| SCOPE\_DATACHECKS\_SQLTESTS\_READ | 51 | none |
| SCOPE\_DATACHECKS\_SQLTESTS\_AUDIT\_READ | 52 | none |
| SCOPE\_DATACHECKS\_TESTSUGGESTIONS\_EDIT | 53 | none |
| SCOPE\_DATACHECKS\_TESTSUGGESTIONS\_READ | 54 | none |
| SCOPE\_DATACHECKS\_TRIGGER | 55 | none |
| SCOPE\_EXECUTION\_EDIT | 60 | none |
| SCOPE\_EXECUTION\_LOG\_EDIT | 61 | none |
| SCOPE\_EXECUTION\_READ | 62 | none |
| SCOPE\_HOOK | 70 | none |
| SCOPE\_SRE\_AGENT | 71 | none |
| SCOPE\_SRE\_LLM | 72 | none |
| SCOPE\_INTEGRATION\_EDIT | 80 | none |
| SCOPE\_INTEGRATION\_READ | 81 | none |
| SCOPE\_USER\_EDIT | 90 | none |
| SCOPE\_USER\_READ | 91 | none |
| SCOPE\_USER\_ASSIGN | 92 | none |
| SCOPE\_MONITORS\_READ | 111 | none |
| SCOPE\_MONITORS\_AUTOMATIC\_EDIT | 112 | none |
| SCOPE\_MONITORS\_CUSTOM\_EDIT | 113 | none |
| SCOPE\_MONITORS\_CUSTOM\_SQL\_EDIT | 116 | none |
| SCOPE\_ALERTS\_EDIT | 130 | none |
| SCOPE\_ALERTS\_READ | 131 | none |
| SCOPE\_OWNERS\_EDIT | 140 | none |
| SCOPE\_OWNERS\_READ | 141 | none |
| SCOPE\_OWNERSHIP\_EDIT | 144 | none |
| SCOPE\_OWNERSHIP\_READ | 145 | none |
| SCOPE\_DATAPRODUCT\_EDIT | 150 | none |
| SCOPE\_DATAPRODUCT\_READ | 151 | none |
| SCOPE\_DOMAIN\_EDIT | 160 | none |
| SCOPE\_DOMAIN\_READ | 161 | none |
| SCOPE\_EXTENSIONS\_MANAGE | 180 | none |
| SCOPE\_USAGE\_GET | 192 | none |
| SCOPE\_MCP\_READ | 200 | none |
| SCOPE\_MCP\_WRITE | 201 | none |
| SCOPE\_RECON\_READ | 210 | none |
| SCOPE\_RECON\_EDIT | 211 | none |
| SCOPE\_INGEST\_RECON | 212 | none |
| SCOPE\_RECON\_PROMOTE | 213 | none |
| SCOPE\_POLICIES\_EDIT | 220 | none |
| SCOPE\_POLICIES\_READ | 221 | none |
| SCOPE\_SAVED\_VIEW\_READ | 230 | none |
| SCOPE\_SAVED\_VIEW\_EDIT | 231 | none |
| SCOPE\_SAVED\_VIEW\_ADMIN | 232 | none |
| SCOPE\_FOLDERS\_READ | 240 | none |
| SCOPE\_FOLDERS\_EDIT | 241 | none |
### Source
(synq.v1.Source)
| Name | Number | Description |
| ----------- | ------ | ----------------------------------------- |
| SOURCE\_APP | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_API | 1 | none |
### Owner.Source
(synq.owners.v1.Owner.Source)
Where the owner is managed. Owners from an external source (e.g. Atlan) are
read-only.
| Name | Number | Description |
| ------------- | ------ | ----------------------------------------- |
| SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_ATLAN | 1 | none |
### Status
(synq.extensions.atlan.workflows.v1.Status)
| Name | Number | Description |
| ------------------- | ------ | ----------- |
| STATUS\_UNSPECIFIED | 0 | none |
| STATUS\_OK | 1 | none |
| STATUS\_FAILED | 2 | none |
### SqlObfuscationMode
(synq.ingest.dwh.v1.SqlObfuscationMode)
SqlObfuscationMode represents the level of SQL obfuscation applied to query logs.
This is critical for on-premise deployments where customers want to prevent
sensitive data in SQL queries from being sent to Coalesce Quality backend.
| Name | Number | Description |
| ---------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------ |
| SQL\_OBFUSCATION\_MODE\_NONE | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX No obfuscation was applied |
| SQL\_OBFUSCATION\_MODE\_REDACT\_LITERALS | 1 | String and numeric literals were replaced with placeholders while preserving query structure for SQL parsing |
### LineageObjectDomain
(synq.ingest.dwh.v1.LineageObjectDomain)
LineageObjectDomain classifies what KIND of warehouse object sits at one end
of a lineage edge. It lets the platform tell real table-to-table lineage
apart from edges that touch warehouse-internal or non-tabular objects (load
stages, streams, semantic views, ...), which are rendered differently (or
hidden) in the lineage graph. The values mirror the object domains a
warehouse's native lineage feature reports (for example the domains returned
by Snowflake's GET\_LINEAGE) plus the common equivalents on other warehouses.
Set UNSPECIFIED when the producer cannot determine the domain — the edge is
still stored, just without the table-vs-builtin distinction.
| Name | Number | Description |
| ------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------- |
| LINEAGE\_OBJECT\_DOMAIN\_UNSPECIFIED | 0 | none |
| LINEAGE\_OBJECT\_DOMAIN\_TABLE | 1 | An ordinary table. |
| LINEAGE\_OBJECT\_DOMAIN\_VIEW | 2 | A non-materialized view. |
| LINEAGE\_OBJECT\_DOMAIN\_MATERIALIZED\_VIEW | 3 | A materialized view. |
| LINEAGE\_OBJECT\_DOMAIN\_EXTERNAL\_TABLE | 4 | A table backed by external storage (external/iceberg table, etc.). |
| LINEAGE\_OBJECT\_DOMAIN\_DYNAMIC\_TABLE | 5 | A table refreshed by the warehouse from a query (Snowflake dynamic table, BigQuery materialized view with auto-refresh, ...). |
| LINEAGE\_OBJECT\_DOMAIN\_STREAM | 6 | A change-data-capture object over a table (Snowflake stream, ...). |
| LINEAGE\_OBJECT\_DOMAIN\_STAGE | 7 | A load/unload staging area — warehouse-internal, not a customer table. |
| LINEAGE\_OBJECT\_DOMAIN\_SEMANTIC\_VIEW | 8 | A semantic/metrics layer object (Snowflake semantic view, ...). |
| LINEAGE\_OBJECT\_DOMAIN\_DATASET | 9 | A dataset/grouping object exposed by the warehouse's lineage feature. |
| LINEAGE\_OBJECT\_DOMAIN\_MODULE | 10 | A module/package object exposed by the warehouse's lineage feature. |
| LINEAGE\_OBJECT\_DOMAIN\_OTHER | 99 | A recognised object that does not fit any category above. |
### LineageSource
(synq.ingest.dwh.v1.LineageSource)
LineageSource records HOW the lineage was derived. The platform uses it both
to set the precedence of the resulting edges and to keep lineage of different
origins from silently overwriting one another: declared lineage is additive
to observed lineage, it never replaces it. Pick the single value that best
describes the whole batch.
| Name | Number | Description |
| --------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| LINEAGE\_SOURCE\_UNSPECIFIED | 0 | none |
| LINEAGE\_SOURCE\_DWH\_NATIVE | 1 | Read from the warehouse's own lineage feature (for example Snowflake SNOWFLAKE.CORE.GET\_LINEAGE). Authoritative, highest fidelity. |
| LINEAGE\_SOURCE\_QUERY\_HISTORY | 2 | Derived by parsing query history / access history. |
| LINEAGE\_SOURCE\_DECLARED | 3 | Declared by the customer or a modelling tool (dbt refs, hand-authored edges, BI relationships) rather than observed in the warehouse. |
| LINEAGE\_SOURCE\_VIEW\_DEFINITION | 4 | Derived from a view or materialization definition. |
### LineageReplaceMode
(synq.ingest.dwh.v1.LineageReplaceMode)
LineageReplaceMode controls how an ingested batch interacts with lineage that
was ingested earlier, and therefore when previously-ingested edges become
outdated and stop contributing to dependencies.
| Name | Number | Description |
| -------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| LINEAGE\_REPLACE\_MODE\_UNSPECIFIED | 0 | Treated as MERGE so a producer that forgets to set the mode can only add or refresh edges, never silently expire them. |
| LINEAGE\_REPLACE\_MODE\_MERGE | 1 | MERGE: upsert the lineage of every downstream object present in this batch and leave every other object untouched. Use for incremental refreshes — a single query's lineage, one schema the customer just rebuilt, etc. Nothing is expired; an edge disappears only when the same downstream object is re-ingested without it. |
| LINEAGE\_REPLACE\_MODE\_REPLACE\_SCOPE | 2 | REPLACE\_SCOPE: treat this batch as the authoritative, complete snapshot of all lineage whose downstream object falls inside `scope`. Any previously- ingested edge whose downstream object is inside the scope but absent from this batch becomes outdated and is excluded from dependencies. Use for full periodic refreshes. `scope` MUST be set. |
### SnapDirection
(synq.schedule.v1.SnapDirection)
SnapDirection constrains which way an occurrence may move to reach the grid.
| Name | Number | Description |
| ---------------------------- | ------ | ---------------------------------------------------------------------- |
| SNAP\_DIRECTION\_UNSPECIFIED | 0 | Move to whichever grid point is closest. Same as NEAREST. |
| SNAP\_DIRECTION\_NEAREST | 1 | Move to whichever grid point is closest. |
| SNAP\_DIRECTION\_FORWARD | 2 | Only delay an occurrence to a later grid point, never move it earlier. |
| SNAP\_DIRECTION\_BACKWARD | 3 | Only move an occurrence earlier to a prior grid point, never delay it. |
### GrantRole
(synq.savedviews.v1.GrantRole)
The access level a grant confers on its grantee.
| Name | Number | Description |
| ------------------------ | ------ | ----------------------------------------------------------------- |
| GRANT\_ROLE\_UNSPECIFIED | 0 | Unspecified is treated as VIEW. |
| GRANT\_ROLE\_VIEW | 1 | The grantee can see the view. |
| GRANT\_ROLE\_MANAGE | 2 | The grantee can also edit the view and change its sharing/grants. |
### SavedViewConfig.Layout
(synq.savedviews.v1.SavedViewConfig.Layout)
Layout used to render the view's results.
| Name | Number | Description |
| ------------------- | ------ | ----------- |
| LAYOUT\_UNSPECIFIED | 0 | none |
| LAYOUT\_LIST | 1 | none |
| LAYOUT\_CARDS | 2 | none |
| LAYOUT\_TABLE | 3 | none |
### SavedViewContext
(synq.savedviews.v1.SavedViewContext)
The surface a saved view applies to. A view saved on the catalog/assets screen
is not shown on the checks or issues screens, so listing is normally filtered
by the context the caller is rendering.
| Name | Number | Description |
| --------------------------------- | ------ | --------------------------------------- |
| SAVED\_VIEW\_CONTEXT\_UNSPECIFIED | 0 | Catalog / assets — the default surface. |
| SAVED\_VIEW\_CONTEXT\_CHECKS | 1 | Checks / monitors screen. |
| SAVED\_VIEW\_CONTEXT\_ISSUES | 2 | Issues / incidents screen. |
### SavedViewRelationship
(synq.savedviews.v1.SavedViewRelationship)
How a returned saved view relates to the calling user. Output-only: computed
per request from the view's owner, visibility and grants against the caller's
identity. Clients group their "views" UI by this value.
| Name | Number | Description |
| ------------------------------------------------ | ------ | --------------------------------------------------------------------------------------------- |
| SAVED\_VIEW\_RELATIONSHIP\_UNSPECIFIED | 0 | none |
| SAVED\_VIEW\_RELATIONSHIP\_MINE | 1 | The caller owns the view. |
| SAVED\_VIEW\_RELATIONSHIP\_WORKSPACE | 2 | Owned by the workspace itself (e.g. created by a workspace-level token), visible to everyone. |
| SAVED\_VIEW\_RELATIONSHIP\_SHARED\_TO\_WORKSPACE | 3 | Another user's view that they shared with the whole workspace. |
| SAVED\_VIEW\_RELATIONSHIP\_SHARED\_TO\_ME | 4 | Another user's view that was explicitly granted to the caller. |
### SavedViewVisibility
(synq.savedviews.v1.SavedViewVisibility)
Who can see a saved view. This is the absolute sharing state stored on the
view; how it relates to the calling user is reported separately as a
SavedViewRelationship on each returned view.
| Name | Number | Description |
| ------------------------------------ | ------ | -------------------------------------------------------------------------- |
| SAVED\_VIEW\_VISIBILITY\_UNSPECIFIED | 0 | Private — only the owner can see it. |
| SAVED\_VIEW\_VISIBILITY\_SHARED | 1 | Shared with the whole workspace — everyone in the workspace can see it. |
| SAVED\_VIEW\_VISIBILITY\_GRANTED | 2 | Granted — the owner plus the users explicitly listed in the view's grants. |
### DatacheckStatus
(synq.datachecks.v1.DatacheckStatus)
Result of a datacheck execution
| Name | Number | Description |
| ------------------------------ | ------ | ------------------------------------------ |
| DATACHECK\_STATUS\_UNSPECIFIED | 0 | none |
| DATACHECK\_STATUS\_PASSED | 1 | Check passed successfully. |
| DATACHECK\_STATUS\_FAILED | 2 | Check failed due to violations. |
| DATACHECK\_STATUS\_ERROR | 3 | Check failed due to error in check itself. |
| DATACHECK\_STATUS\_SKIPPED | 4 | Check was skipped (e.g. not applicable) |
### Severity
(synq.datachecks.sqltests.v1.Severity)
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| SEVERITY\_UNSPECIFIED | 0 | none |
| SEVERITY\_WARNING | 1 | none |
| SEVERITY\_ERROR | 2 | none |
| SEVERITY\_INFO | 3 | none |
### HealthStatus
(synq.integrations.v1.HealthStatus)
Health status of an integration, derived from its most recent runs.
| Name | Number | Description |
| --------------------------- | ------ | -------------------------------------------------------------------------------- |
| HEALTH\_STATUS\_UNSPECIFIED | 0 | Unknown — no runs observed yet. |
| HEALTH\_STATUS\_OK | 1 | Last run succeeded. |
| HEALTH\_STATUS\_WARN | 2 | Last run completed with warnings. |
| HEALTH\_STATUS\_ERROR | 3 | Last run failed. |
| HEALTH\_STATUS\_CRITICAL | 4 | Last run failed critically (for example authentication or connectivity failure). |
### ListIssuesRequest.Field
(synq.issues.v2.ListIssuesRequest.Field)
| Name | Number | Description |
| ------------------ | ------ | ----------------------------------------- |
| FIELD\_UPDATED\_AT | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| FIELD\_STARTED\_AT | 1 | none |
### ListIssuesRequest.Sort.Order
(synq.issues.v2.ListIssuesRequest.Sort.Order)
| Name | Number | Description |
| ----------- | ------ | ----------------------------------------- |
| ORDER\_ASC | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| ORDER\_DESC | 1 | none |
### LifecycleState
(synq.issues.issues.v1.LifecycleState)
Issue LifecycleState represents the current state of the issue in its life-cycle.
The state is exclusively determined as per the priority which is in the order of the fields below.
| Name | Number | Description |
| ----------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------- |
| LIFECYCLE\_STATE\_UNSPECIFIED | 0 | none |
| LIFECYCLE\_STATE\_UNTRIAGED | 1 | Issue has not been triaged yet. A triaged issue is one that has been acted upon (status update or incident declaration) |
| LIFECYCLE\_STATE\_CLOSED | 2 | Issue is closed. This is a terminal state. |
| LIFECYCLE\_STATE\_ONGOING\_RESOLVED | 3 | Open issue that has been marked as resolved by the user. |
| LIFECYCLE\_STATE\_ONGOING\_DECLARED | 4 | Open issue that has been declared as an incident. |
| LIFECYCLE\_STATE\_ONGOING\_STATUS\_SET | 5 | Open issue that has status set. |
| LIFECYCLE\_STATE\_AUTOTRIAGE\_QUEUED | 11 | Open issue that has been queued for autotriage. |
| LIFECYCLE\_STATE\_AUTOTRIAGE\_ACTION\_SUGGESTED | 12 | Issue has been autotriaged and an action has been suggested. |
### Severity
(synq.issues.issues.v1.Severity)
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| SEVERITY\_UNSPECIFIED | 0 | none |
| SEVERITY\_INFO | 1 | none |
| SEVERITY\_WARN | 2 | none |
| SEVERITY\_ERROR | 3 | none |
| SEVERITY\_FATAL | 4 | none |
### State
(synq.issues.issues.v1.State)
Whether the issue is open / close.
| Name | Number | Description |
| ------------------ | ------ | ----------- |
| STATE\_UNSPECIFIED | 0 | none |
| STATE\_OPEN | 1 | none |
| STATE\_CLOSED | 2 | none |
### Status
(synq.issues.issues.v1.Status)
Progress status of the issue.
| Name | Number | Description |
| -------------------------- | ------ | ----------- |
| STATUS\_UNSPECIFIED | 0 | none |
| STATUS\_INVESTIGATING | 1 | none |
| STATUS\_EXPECTED | 2 | none |
| STATUS\_FIXED | 3 | none |
| STATUS\_NO\_ACTION\_NEEDED | 4 | none |
### Actor.Via
(synq.issues.actor.v1.Actor.Via)
| Name | Number | Description |
| ---------------- | ------ | --------------------- |
| VIA\_UNSPECIFIED | 0 | Unknown / not set |
| VIA\_API | 1 | Public API |
| VIA\_MCP | 2 | Official MCP server |
| VIA\_SLACK | 3 | Slack bot integration |
| VIA\_PAGERDUTY | 4 | PagerDuty webhook |
### MonitorDefinition.Source
(synq.monitors.custom\_monitors.v1.MonitorDefinition.Source)
| Name | Number | Description |
| ----------- | ------ | ----------------------------------------- |
| SOURCE\_APP | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX |
| SOURCE\_API | 1 | none |
### Sensitivity
(synq.monitors.custom\_monitors.v1.Sensitivity)
| Name | Number | Description |
| ------------------------ | ------ | ----------- |
| SENSITIVITY\_UNSPECIFIED | 0 | none |
| SENSITIVITY\_PRECISE | 1 | none |
| SENSITIVITY\_BALANCED | 2 | none |
| SENSITIVITY\_RELAXED | 3 | none |
### Severity
(synq.monitors.custom\_monitors.v1.Severity)
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| SEVERITY\_UNSPECIFIED | 0 | none |
| SEVERITY\_WARNING | 1 | none |
| SEVERITY\_ERROR | 2 | none |
| SEVERITY\_INFO | 3 | none |
### DeploymentRuleType
(synq.monitors.automated\_monitors.v1.DeploymentRuleType)
DeploymentRuleType identifies which kind of selection a deployment rule uses.
The value corresponds to the populated `config` oneof arm on
MonitorsDeploymentRule / MonitorsDeploymentRuleView. Use it with
ListDeploymentRulesRequest.rule\_types to return only rules of selected kinds.
| Name | Number | Description |
| ----------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| DEPLOYMENT\_RULE\_TYPE\_UNSPECIFIED | 0 | No filter — when used in a request, rules of any type are returned. |
| DEPLOYMENT\_RULE\_TYPE\_QUERY | 1 | Rule with `query_config`: selects entities by a ResolverQL query and deploys monitors on the matches. |
| DEPLOYMENT\_RULE\_TYPE\_EXCLUSIVE\_QUERY | 2 | Rule with `exclusive_query_config`: a ResolverQL query whose matches are exclusively owned (monitors outside the match set are removed). |
| DEPLOYMENT\_RULE\_TYPE\_STATIC\_PATH | 3 | Rule with `static_config`: targets a single fixed entity path. |
| DEPLOYMENT\_RULE\_TYPE\_EXCLUSIVE\_STATIC\_PATH | 4 | Rule with `exclusive_static_config`: a single fixed path, exclusively owned. |
| DEPLOYMENT\_RULE\_TYPE\_PRODUCT | 5 | Rule with `product_config`: deploys monitors across a data product's entities per its upstream/self selection strategy. |
### MetricId
(synq.monitors.automated\_monitors.v1.MetricId)
| Name | Number | Description |
| --------------------------------- | ------ | ----------- |
| METRIC\_ID\_UNSPECIFIED | 0 | none |
| METRIC\_ID\_ROW\_COUNT | 1 | none |
| METRIC\_ID\_DELAY | 2 | none |
| METRIC\_ID\_VOLUME\_CHANGE\_DELAY | 3 | none |
### Sensitivity
(synq.monitors.automated\_monitors.v1.Sensitivity)
| Name | Number | Description |
| ------------------------ | ------ | ----------- |
| SENSITIVITY\_UNSPECIFIED | 0 | none |
| SENSITIVITY\_PRECISE | 1 | none |
| SENSITIVITY\_BALANCED | 2 | none |
| SENSITIVITY\_RELAXED | 3 | none |
### Severity
(synq.monitors.automated\_monitors.v1.Severity)
| Name | Number | Description |
| --------------------- | ------ | ----------- |
| SEVERITY\_UNSPECIFIED | 0 | none |
| SEVERITY\_WARNING | 1 | none |
| SEVERITY\_ERROR | 2 | none |
| SEVERITY\_INFO | 3 | none |
### PropagationFilter
(synq.entities.checks.v1.PropagationFilter)
PropagationFilter controls which types of checks are included in the coverage response.
| Name | Number | Description |
| ------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| PROPAGATION\_FILTER\_UNSPECIFIED | 0 | PROPAGATION\_FILTER\_UNSPECIFIED - Default behavior: returns both direct and propagated checks |
| PROPAGATION\_FILTER\_DIRECT\_ONLY | 1 | PROPAGATION\_FILTER\_DIRECT\_ONLY - Returns only direct checks, skips lineage resolution and propagation |
| PROPAGATION\_FILTER\_PROPAGATED\_ONLY | 2 | PROPAGATION\_FILTER\_PROPAGATED\_ONLY - Returns only propagated checks from upstream entities, direct checks arrays will be empty but still present |
### SqlConstruct
(synq.entities.v1.SqlConstruct)
SqlConstruct enumerates the SQL features detected in an entity's query.
Multiple values can be set on a single statement (e.g. a query with both a
CTE and an INNER JOIN carries HAS\_CTE, HAS\_ANY\_JOIN and INNER\_JOIN).
| Name | Number | Description |
| ---------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SQL\_CONSTRUCT\_UNSPECIFIED | 0 | none |
| SQL\_CONSTRUCT\_HAS\_ANY\_JOIN | 1 | Aggregate flag: the query contains at least one join of any kind. Always emitted alongside the specific JOIN variant for that join. |
| SQL\_CONSTRUCT\_HAS\_ANY\_SET\_OPERATION | 2 | Aggregate flag: the query contains at least one UNION / INTERSECT / EXCEPT at any nesting level. Always emitted alongside the specific SET variant. |
| SQL\_CONSTRUCT\_HAS\_GROUP\_BY | 3 | The query has a GROUP BY (including GROUP BY ALL). |
| SQL\_CONSTRUCT\_HAS\_CTE | 4 | The query has a WITH clause (CTEs, recursive or not). |
| SQL\_CONSTRUCT\_SET\_UNION | 10 | UNION / UNION ALL set operation. Emitted alongside HAS\_ANY\_SET\_OPERATION. |
| SQL\_CONSTRUCT\_SET\_INTERSECT | 11 | INTERSECT set operation. Emitted alongside HAS\_ANY\_SET\_OPERATION. |
| SQL\_CONSTRUCT\_SET\_EXCEPT | 12 | EXCEPT / MINUS set operation. Emitted alongside HAS\_ANY\_SET\_OPERATION. |
| SQL\_CONSTRUCT\_INNER\_JOIN | 20 | INNER JOIN. Also emitted for an unqualified `JOIN`, which defaults to INNER. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_CROSS\_APPLY\_JOIN | 21 | T-SQL `CROSS APPLY`. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_OUTER\_APPLY\_JOIN | 22 | T-SQL `OUTER APPLY`. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_ARRAY\_JOIN | 23 | ClickHouse `ARRAY JOIN` / `LEFT ARRAY JOIN`. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_CROSS\_JOIN | 24 | Explicit CROSS JOIN (cartesian product). Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_LEFT\_SEMI\_JOIN | 25 | LEFT SEMI JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_RIGHT\_SEMI\_JOIN | 26 | RIGHT SEMI JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_LEFT\_ANTI\_JOIN | 27 | LEFT ANTI JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_RIGHT\_ANTI\_JOIN | 28 | RIGHT ANTI JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_LEFT\_OUTER\_JOIN | 29 | LEFT \[OUTER] JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_RIGHT\_OUTER\_JOIN | 30 | RIGHT \[OUTER] JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_FULL\_OUTER\_JOIN | 31 | FULL \[OUTER] JOIN. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_ASOF\_JOIN | 32 | Snowflake / Databricks `ASOF JOIN`. Emitted alongside HAS\_ANY\_JOIN. |
| SQL\_CONSTRUCT\_READS\_SEMANTIC\_VIEW | 33 | Query reads a Snowflake semantic view via the `SEMANTIC_VIEW(...)` table-valued function. One occurrence is recorded per semantic-view reference. The companion CREATE SEMANTIC VIEW DDL is classified separately, not via this construct. |
| SQL\_CONSTRUCT\_HAS\_AGGREGATE\_FUNCTION | 34 | The query invokes at least one aggregate function (SUM, COUNT, AVG, ...) used as a grouping aggregate. A windowed aggregate (`SUM(x) OVER (...)`) does NOT set this flag — it sets HAS\_WINDOW\_FUNCTION instead, because it produces one row per input row rather than collapsing groups. Aggregate names are recognised per-dialect, including user-defined aggregates. |
| SQL\_CONSTRUCT\_HAS\_WINDOW\_FUNCTION | 35 | The query invokes at least one window function — any function call carrying an `OVER (...)` clause, whether the base is an aggregate (`SUM(x) OVER (...)`) or a dedicated window function (`ROW_NUMBER() OVER (...)`). The window-ness is the `OVER` clause, not the base name. |
| SQL\_CONSTRUCT\_UNSUPPORTED\_SQL\_SYNTAX | 100 | Set when the SQL could not be parsed. Lets unparseable entities be filtered without inspecting the underlying parse error. |
### ExecutionType
(synq.entities.v1.ExecutionType)
| Name | Number | Description |
| ------------------------------------------------------------------------------------- | ------ | ----------- |
| EXECUTION\_TYPE\_UNSPECIFIED | 0 | none |
| EXECUTION\_TYPE\_DELETION | 1 | none |
| EXECUTION\_TYPE\_SCHEMA\_CHANGE | 2 | none |
| EXECUTION\_TYPE\_SQL\_DEFINITION\_CHANGE | 3 | none |
| EXECUTION\_TYPE\_BQ\_QUERY\_JOB | 101 | none |
| EXECUTION\_TYPE\_BQ\_LOAD\_JOB | 102 | none |
| EXECUTION\_TYPE\_BQ\_COPY\_JOB | 103 | none |
| EXECUTION\_TYPE\_BQ\_EXTRACT\_JOB | 104 | none |
| EXECUTION\_TYPE\_BQ\_QUERY\_LOG | 105 | none |
| EXECUTION\_TYPE\_LOOKER\_USAGE\_REPORT | 201 | none |
| EXECUTION\_TYPE\_DBT\_INVOCATION | 301 | none |
| EXECUTION\_TYPE\_DBT\_NODE\_INVOCATION | 302 | none |
| EXECUTION\_TYPE\_DBT\_NODE\_FRESHNESS | 303 | none |
| EXECUTION\_TYPE\_DBT\_CATALOG\_REFRESH | 304 | none |
| EXECUTION\_TYPE\_DBT\_CLOUD\_JOB\_RUN | 351 | none |
| EXECUTION\_TYPE\_DBT\_CLOUD\_JOB\_RUN\_STEP | 352 | none |
| EXECUTION\_TYPE\_DATABOX\_FRESHNESS | 401 | none |
| EXECUTION\_TYPE\_GIT\_COMMIT | 501 | none |
| EXECUTION\_TYPE\_CLICKHOUSE\_QUERY\_LOG | 601 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG | 701 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_SELECT | 702 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DROP | 703 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE | 704 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_TABLE | 705 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_INSERT | 706 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_MERGE | 707 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_UPDATE | 708 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_TABLE\_AS\_SELECT | 709 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DELETE | 710 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_SHOW | 711 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_VIEW | 712 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_MULTI\_STATEMENT | 713 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ROLLBACK | 714 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_TRUNCATE\_TABLE | 715 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_COMMIT | 716 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_BEGIN\_TRANSACTION | 717 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_UNKNOWN | 718 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_SET | 719 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_RENAME\_TABLE | 720 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_GRANT | 721 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER\_TABLE\_ADD\_COLUMN | 722 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_USE | 723 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_COPY | 724 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CALL | 725 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER\_TABLE\_DROP\_COLUMN | 726 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER\_TABLE\_MODIFY\_COLUMN | 727 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_RENAME\_COLUMN | 728 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DROP\_ROLE | 729 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DESCRIBE\_QUERY | 730 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_CONSTRAINT | 731 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_EXPLAIN | 732 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_ROLE | 733 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER | 734 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DESCRIBE | 735 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_PUT\_FILES | 736 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_GET\_FILES | 737 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER\_SESSION | 738 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_LIST\_FILES | 739 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_EXTERNAL\_TABLE\_REFRESH | 740 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_REFRESH\_DYNAMIC\_TABLE\_AT\_REFRESH\_VERSION | 741 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_REMOVE\_FILES | 742 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_EXECUTE\_TASK | 743 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_ALTER\_TABLE | 744 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_EXECUTE\_STREAMLIT | 745 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_CREATE\_TASK | 746 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_UNLOAD | 747 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_QUERY\_LOG\_DROP\_TASK | 748 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_TASK\_EXECUTION | 790 | none |
| EXECUTION\_TYPE\_SNOWFLAKE\_TASK\_GROUP\_EXECUTION | 791 | none |
| EXECUTION\_TYPE\_REDSHIFT\_QUERY\_LOG | 801 | none |
| EXECUTION\_TYPE\_DATAHUB\_DATA\_PROCESS\_INSTANCE | 901 | none |
| EXECUTION\_TYPE\_DATAHUB\_USAGE\_REPORT | 902 | none |
| EXECUTION\_TYPE\_SYNQ\_CUSTOM\_ENTITY\_EXECUTION | 1001 | none |
| EXECUTION\_TYPE\_SYNQ\_CUSTOM\_ENTITY\_LOG | 1002 | none |
| EXECUTION\_TYPE\_SYNQ\_CUSTOM\_ENTITY\_MEASUREMENT | 1003 | none |
| EXECUTION\_TYPE\_TABLEAU\_USAGE\_REPORT | 1101 | none |
| EXECUTION\_TYPE\_TABLEAU\_EXTRACT | 1102 | none |
| EXECUTION\_TYPE\_AIRFLOW\_DAG | 1201 | none |
| EXECUTION\_TYPE\_AIRFLOW\_TASK | 1202 | none |
| EXECUTION\_TYPE\_ANOMALY\_INTEGRATION\_RUN | 1402 | none |
| EXECUTION\_TYPE\_ANOMALY\_MONITOR\_RUN | 1403 | none |
| EXECUTION\_TYPE\_ANOMALY\_MONITOR\_CORRECTION | 1404 | none |
| EXECUTION\_TYPE\_ANOMALY\_MONITOR\_SEGMENT\_RUN | 1405 | none |
| EXECUTION\_TYPE\_ANOMALY\_MONITOR\_SEGMENT\_CORRECTION | 1406 | none |
| EXECUTION\_TYPE\_ANOMALY\_MONITOR\_FETCH\_RUN | 1407 | none |
| EXECUTION\_TYPE\_SQL\_TEST\_RUN | 1421 | none |
| EXECUTION\_TYPE\_DATABRICKS\_QUERY\_LOG | 1501 | none |
| EXECUTION\_TYPE\_DATABRICKS\_JOB\_RUN | 1502 | none |
| EXECUTION\_TYPE\_DATABRICKS\_JOB\_TASK\_RUN | 1503 | none |
| EXECUTION\_TYPE\_SQLMESH\_PROJECT\_EXECUTION | 1601 | none |
| EXECUTION\_TYPE\_SQLMESH\_MODEL\_EVALUATION | 1602 | none |
| EXECUTION\_TYPE\_SQLMESH\_AUDIT\_CHECK | 1603 | none |
| EXECUTION\_TYPE\_TRINO\_QUERY\_LOG | 2101 | none |
| EXECUTION\_TYPE\_COALESCE\_ENVIRONMENT\_RUN | 2301 | none |
| EXECUTION\_TYPE\_COALESCE\_DEPLOY\_RUN | 2302 | none |
| EXECUTION\_TYPE\_COALESCE\_REFRESH\_RUN | 2303 | none |
| EXECUTION\_TYPE\_COALESCE\_NODE\_RUN | 2304 | none |
| EXECUTION\_TYPE\_COALESCE\_SQL\_TEST\_RUN | 2305 | none |
| EXECUTION\_TYPE\_MSSQL\_QUERY\_LOG | 2401 | none |
| EXECUTION\_TYPE\_ORACLE\_QUERY\_LOG | 2501 | none |
| EXECUTION\_TYPE\_RECON\_SUITE\_RUN | 2601 | none |
| EXECUTION\_TYPE\_RECON\_CASE\_RUN | 2602 | none |
| EXECUTION\_TYPE\_RECON\_DEPLOYMENT | 2603 | none |
| EXECUTION\_TYPE\_FABRIC\_QUERY\_LOG | 2701 | none |
### EntityChangeType
(synq.entities.v1.EntityChangeType)
| Name | Number | Description |
| --------------------------------------------- | ------ | ----------- |
| ENTITY\_CHANGE\_TYPE\_UNSPECIFIED | 0 | none |
| ENTITY\_CHANGE\_TYPE\_GIT\_COMMIT | 1 | none |
| ENTITY\_CHANGE\_TYPE\_SQL\_DEFINITION\_CHANGE | 2 | none |
| ENTITY\_CHANGE\_TYPE\_SCHEMA\_CHANGE | 3 | none |
### SqlDialect
(synq.entities.v1.SqlDialect)
| Name | Number | Description |
| ------------------------- | ------ | ----------- |
| SQL\_DIALECT\_UNSPECIFIED | 0 | none |
| SQL\_DIALECT\_BIGQUERY | 1 | none |
| SQL\_DIALECT\_CLICKHOUSE | 2 | none |
| SQL\_DIALECT\_DATABRICKS | 3 | none |
| SQL\_DIALECT\_MYSQL | 4 | none |
| SQL\_DIALECT\_POSTGRESQL | 5 | none |
| SQL\_DIALECT\_REDSHIFT | 6 | none |
| SQL\_DIALECT\_SNOWFLAKE | 7 | none |
| SQL\_DIALECT\_DUCKDB | 8 | none |
| SQL\_DIALECT\_TRINO | 9 | none |
| SQL\_DIALECT\_MSSQL | 10 | none |
| SQL\_DIALECT\_ORACLE | 11 | none |
| SQL\_DIALECT\_ATHENA | 12 | none |
| SQL\_DIALECT\_FABRIC | 13 | none |
### TableConstraintType
(synq.entities.v1.TableConstraintType)
TableConstraintType represents the type of a database table constraint or index.
| Name | Number | Description |
| ------------------------------------------ | ------ | -------------------------------------- |
| TABLE\_CONSTRAINT\_TYPE\_UNSPECIFIED | 0 | none |
| TABLE\_CONSTRAINT\_TYPE\_PRIMARY\_KEY | 1 | none |
| TABLE\_CONSTRAINT\_TYPE\_FOREIGN\_KEY | 2 | none |
| TABLE\_CONSTRAINT\_TYPE\_UNIQUE | 3 | none |
| TABLE\_CONSTRAINT\_TYPE\_CHECK | 4 | none |
| TABLE\_CONSTRAINT\_TYPE\_INDEX | 5 | none |
| TABLE\_CONSTRAINT\_TYPE\_SORTING\_KEY | 6 | DWH-specific constraint/ordering types |
| TABLE\_CONSTRAINT\_TYPE\_PARTITION\_BY | 7 | none |
| TABLE\_CONSTRAINT\_TYPE\_CLUSTER\_BY | 8 | none |
| TABLE\_CONSTRAINT\_TYPE\_DISTRIBUTION\_KEY | 9 | none |
| TABLE\_CONSTRAINT\_TYPE\_PROJECTION | 10 | none |
### CodeType
(synq.entities.v1.CodeType)
CodeType enum represents different types of code that can be processed in the Coalesce Quality platform
| Name | Number | Description |
| ----------------------- | ------ | ---------------------------------------------------------------------------------- |
| CODE\_TYPE\_UNSPECIFIED | 0 | none |
| CODE\_TYPE\_SQL | 1 | SQL code (e.g., SELECT, INSERT, UPDATE statements) |
| CODE\_TYPE\_PYTHON | 2 | Python code (e.g., scripts, functions, classes) |
| CODE\_TYPE\_JSON | 3 | JSON data or configuration files |
| CODE\_TYPE\_YAML | 4 | YAML configuration or data files |
| CODE\_TYPE\_DBT | 5 | dbt (data build tool) models and configurations |
| CODE\_TYPE\_SQLMESH | 6 | SQLMesh models and configurations. In most cases this will be similar to SQL code. |
| CODE\_TYPE\_LOOKML | 7 | LookML (Looker Modeling Language) files |
### EntityType
(synq.entities.v1.EntityType)
| Name | Number | Description |
| ----------------------------------------------- | ------ | ----------- |
| ENTITY\_TYPE\_UNSPECIFIED | 0 | none |
| ENTITY\_TYPE\_BQ\_TABLE | 103 | none |
| ENTITY\_TYPE\_BQ\_VIEW | 105 | none |
| ENTITY\_TYPE\_LOOKER\_LOOK | 201 | none |
| ENTITY\_TYPE\_LOOKER\_EXPLORE | 203 | none |
| ENTITY\_TYPE\_LOOKER\_VIEW | 207 | none |
| ENTITY\_TYPE\_LOOKER\_DASHBOARD | 208 | none |
| ENTITY\_TYPE\_DBT\_MODEL | 301 | none |
| ENTITY\_TYPE\_DBT\_TEST | 302 | none |
| ENTITY\_TYPE\_DBT\_SOURCE | 303 | none |
| ENTITY\_TYPE\_DBT\_PROJECT | 306 | none |
| ENTITY\_TYPE\_DBT\_METRIC | 307 | none |
| ENTITY\_TYPE\_DBT\_SNAPSHOT | 310 | none |
| ENTITY\_TYPE\_DBT\_SEED | 311 | none |
| ENTITY\_TYPE\_DBT\_ANALYSIS | 312 | none |
| ENTITY\_TYPE\_DBT\_EXPOSURE | 313 | none |
| ENTITY\_TYPE\_DBT\_GROUP | 314 | none |
| ENTITY\_TYPE\_DBT\_SEMANTIC\_MODEL | 315 | none |
| ENTITY\_TYPE\_DBT\_CLOUD\_PROJECT | 352 | none |
| ENTITY\_TYPE\_DBT\_CLOUD\_JOB | 353 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_TABLE | 503 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_VIEW | 508 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_STREAM | 509 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_DYNAMIC\_TABLE | 510 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_TASK | 511 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_EXTERNAL\_TABLE | 512 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_MATERIALIZED\_VIEW | 513 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_PROCEDURE | 514 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_FUNCTION | 515 | none |
| ENTITY\_TYPE\_SNOWFLAKE\_SEMANTIC\_VIEW | 516 | none |
| ENTITY\_TYPE\_REDSHIFT\_TABLE | 803 | none |
| ENTITY\_TYPE\_REDSHIFT\_VIEW | 805 | none |
| ENTITY\_TYPE\_REDSHIFT\_PROCEDURE | 806 | none |
| ENTITY\_TYPE\_REDSHIFT\_FUNCTION | 807 | none |
| ENTITY\_TYPE\_TABLEAU\_EMBEDDED | 1101 | none |
| ENTITY\_TYPE\_TABLEAU\_PUBLISHED | 1102 | none |
| ENTITY\_TYPE\_TABLEAU\_CUSTOM\_SQL | 1103 | none |
| ENTITY\_TYPE\_TABLEAU\_TABLE | 1104 | none |
| ENTITY\_TYPE\_TABLEAU\_SHEET | 1105 | none |
| ENTITY\_TYPE\_TABLEAU\_DASHBOARD | 1106 | none |
| ENTITY\_TYPE\_AIRFLOW\_DAG | 1201 | none |
| ENTITY\_TYPE\_AIRFLOW\_TASK | 1202 | none |
| ENTITY\_TYPE\_CLICKHOUSE\_TABLE | 1303 | none |
| ENTITY\_TYPE\_CLICKHOUSE\_VIEW | 1305 | none |
| ENTITY\_TYPE\_ANOMALY\_MONITOR | 1403 | none |
| ENTITY\_TYPE\_ANOMALY\_MONITOR\_SEGMENT | 1404 | none |
| ENTITY\_TYPE\_SQLTEST\_TEST | 1421 | none |
| ENTITY\_TYPE\_RECON\_SUITE | 1431 | none |
| ENTITY\_TYPE\_RECON\_CASE | 1432 | none |
| ENTITY\_TYPE\_POSTGRES\_TABLE | 1603 | none |
| ENTITY\_TYPE\_POSTGRES\_VIEW | 1605 | none |
| ENTITY\_TYPE\_MYSQL\_TABLE | 1703 | none |
| ENTITY\_TYPE\_MYSQL\_VIEW | 1705 | none |
| ENTITY\_TYPE\_DATABRICKS\_WAREHOUSE | 1801 | none |
| ENTITY\_TYPE\_DATABRICKS\_TABLE | 1804 | none |
| ENTITY\_TYPE\_DATABRICKS\_VIEW | 1805 | none |
| ENTITY\_TYPE\_DATABRICKS\_JOB | 1807 | none |
| ENTITY\_TYPE\_DATABRICKS\_JOB\_TASK | 1808 | none |
| ENTITY\_TYPE\_DATABRICKS\_NOTEBOOK | 1809 | none |
| ENTITY\_TYPE\_DATABRICKS\_QUERY | 1810 | none |
| ENTITY\_TYPE\_DATABRICKS\_DASHBOARD | 1811 | none |
| ENTITY\_TYPE\_SQLMESH\_PROJECT | 1901 | none |
| ENTITY\_TYPE\_SQLMESH\_SQL\_MODEL | 1902 | none |
| ENTITY\_TYPE\_SQLMESH\_PYTHON\_MODEL | 1903 | none |
| ENTITY\_TYPE\_SQLMESH\_EXTERNAL | 1904 | none |
| ENTITY\_TYPE\_SQLMESH\_SEED | 1905 | none |
| ENTITY\_TYPE\_SQLMESH\_AUDIT | 1906 | none |
| ENTITY\_TYPE\_SQLMESH\_UNIT\_TEST | 1907 | none |
| ENTITY\_TYPE\_SQLMESH\_ENVIRONMENT | 1908 | none |
| ENTITY\_TYPE\_SQLMESH\_SNAPSHOT | 1909 | none |
| ENTITY\_TYPE\_DUCKDB\_TABLE | 2003 | none |
| ENTITY\_TYPE\_DUCKDB\_VIEW | 2005 | none |
| ENTITY\_TYPE\_TRINO\_TABLE | 2104 | none |
| ENTITY\_TYPE\_TRINO\_VIEW | 2105 | none |
| ENTITY\_TYPE\_ATLAN\_ASSET | 2201 | none |
| ENTITY\_TYPE\_ATLAN\_INTEGRATION | 2202 | none |
| ENTITY\_TYPE\_COALESCE\_PROJECT | 2301 | none |
| ENTITY\_TYPE\_COALESCE\_ENVIRONMENT | 2302 | none |
| ENTITY\_TYPE\_COALESCE\_NODE | 2303 | none |
| ENTITY\_TYPE\_COALESCE\_NODE\_TEST | 2304 | none |
| ENTITY\_TYPE\_COALESCE\_JOB | 2305 | none |
| ENTITY\_TYPE\_CASTORDOC\_TABLE | 2404 | none |
| ENTITY\_TYPE\_CASTORDOC\_DASHBOARD | 2405 | none |
| ENTITY\_TYPE\_CASTORDOC\_VIEW | 2406 | none |
| ENTITY\_TYPE\_CASTORDOC\_TILE | 2407 | none |
| ENTITY\_TYPE\_CASTORDOC\_VIZ\_MODEL | 2408 | none |
| ENTITY\_TYPE\_POWERBI\_REPORT | 3001 | none |
| ENTITY\_TYPE\_POWERBI\_TILE | 3002 | none |
| ENTITY\_TYPE\_POWERBI\_DATASET | 3003 | none |
| ENTITY\_TYPE\_POWERBI\_DASHBOARD | 3004 | none |
| ENTITY\_TYPE\_POWERBI\_TENANT | 3005 | none |
| ENTITY\_TYPE\_THOUGHTSPOT\_LIVEBOARD | 3101 | none |
| ENTITY\_TYPE\_THOUGHTSPOT\_WORKSHEET | 3102 | none |
| ENTITY\_TYPE\_SIGMA\_WORKBOOK | 3201 | none |
| ENTITY\_TYPE\_SIGMA\_DATA\_MODEL | 3202 | none |
| ENTITY\_TYPE\_DOMO\_PAGE | 3301 | none |
| ENTITY\_TYPE\_DOMO\_DATASET | 3302 | none |
| ENTITY\_TYPE\_MSSQL\_TABLE | 3403 | none |
| ENTITY\_TYPE\_MSSQL\_VIEW | 3405 | none |
| ENTITY\_TYPE\_ORACLE\_TABLE | 3503 | none |
| ENTITY\_TYPE\_ORACLE\_VIEW | 3505 | none |
| ENTITY\_TYPE\_ATHENA\_TABLE | 3604 | none |
| ENTITY\_TYPE\_ATHENA\_VIEW | 3605 | none |
| ENTITY\_TYPE\_FABRIC\_TABLE | 3704 | none |
| ENTITY\_TYPE\_FABRIC\_VIEW | 3705 | none |
| ENTITY\_TYPE\_CUSTOM\_ENTITY\_GENERIC | 50000 | none |
| ENTITY\_TYPE\_CUSTOM\_ENTITY\_CUSTOM\_TYPE\_MIN | 50001 | none |
| ENTITY\_TYPE\_CUSTOM\_ENTITY\_CUSTOM\_TYPE\_MAX | 59999 | none |
### ExecutionStatus
(synq.entities.executions.v1.ExecutionStatus)
| Name | Number | Description |
| ------------------------------ | ------ | ----------- |
| EXECUTION\_STATUS\_UNSPECIFIED | 0 | none |
| EXECUTION\_STATUS\_OK | 1 | none |
| EXECUTION\_STATUS\_WARN | 2 | none |
| EXECUTION\_STATUS\_ERROR | 3 | none |
| EXECUTION\_STATUS\_CRITICAL | 4 | none |
### ExecutionStatus
(synq.entities.executions.v2.ExecutionStatus)
ExecutionStatus represents the outcome of an execution.
| Name | Number | Description |
| ------------------------------ | ------ | ----------- |
| EXECUTION\_STATUS\_UNSPECIFIED | 0 | none |
| EXECUTION\_STATUS\_OK | 1 | none |
| EXECUTION\_STATUS\_WARN | 2 | none |
| EXECUTION\_STATUS\_ERROR | 3 | none |
| EXECUTION\_STATUS\_CRITICAL | 4 | none |
### ExecutionStatus
(synq.entities.custom.v1.ExecutionStatus)
| Name | Number | Description |
| ------------------------------ | ------ | ----------- |
| EXECUTION\_STATUS\_UNSPECIFIED | 0 | none |
| EXECUTION\_STATUS\_OK | 1 | none |
| EXECUTION\_STATUS\_WARN | 2 | none |
| EXECUTION\_STATUS\_ERROR | 3 | none |
| EXECUTION\_STATUS\_CRITICAL | 4 | none |
### LineageDirection
(synq.entities.lineage.v1.LineageDirection)
Direction of the lineage to query.
| Name | Number | Description |
| ---------------------------------------- | ------ | ----------- |
| LINEAGE\_DIRECTION\_UNSPECIFIED | 0 | none |
| LINEAGE\_DIRECTION\_UPSTREAM | 1 | none |
| LINEAGE\_DIRECTION\_DOWNSTREAM | 2 | none |
| LINEAGE\_DIRECTION\_UPSTREAM\_DOWNSTREAM | 3 | none |
### CllState
(synq.entities.lineage.v1.CllState)
| Name | Number | Description |
| ------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------- |
| CLL\_STATE\_UNSPECIFIED | 0 | Unspecified state. |
| CLL\_STATE\_PARSE\_FAILED | 1 | Parsing of the asset SQL failed. No upstream dependencies can be found. |
| CLL\_STATE\_EXTRACTION\_FAILED | 2 | Extraction of the asset SQL failed. Some unsupported SQL features may be used. Some details might be missing. |
| CLL\_STATE\_RESOLUTION\_FAILED | 3 | Not all columns or tables were found upstream, lineage is not complete. |
| CLL\_STATE\_OK | 10 | No known issues present. |
### NodePosition
(synq.entities.lineage.v1.NodePosition)
| Name | Number | Description |
| --------------------------- | ------ | ------------------------------------------------ |
| NODE\_POSITION\_UNSPECIFIED | 0 | none |
| NODE\_POSITION\_START\_NODE | 1 | Node is one of the requested start point. |
| NODE\_POSITION\_UPSTREAM | 2 | Node is upstream of the requested start point. |
| NODE\_POSITION\_DOWNSTREAM | 3 | Node is downstream of the requested start point. |
### IssueStatus
(synq.entities.status.v1.IssueStatus)
| Name | Number | Description |
| -------------------------- | ------ | ----------- |
| ISSUE\_STATUS\_UNSPECIFIED | 0 | none |
| ISSUE\_STATUS\_OK | 10 | none |
| ISSUE\_STATUS\_WARN | 20 | none |
| ISSUE\_STATUS\_ERROR | 30 | none |
| ISSUE\_STATUS\_CRITICAL | 40 | none |
### FolderRole
(synq.entities.folders.v1.FolderRole)
FolderRole describes how a folder placement participates in browsing. It
mirrors the placement roles carried by the catalog.
| Name | Number | Description |
| ------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| FOLDER\_ROLE\_UNSPECIFIED | 0 | Unknown / not reported. Treat as VISIBLE. |
| FOLDER\_ROLE\_PRIMARY | 1 | Browsable and the default display location (breadcrumb) for its members. |
| FOLDER\_ROLE\_VISIBLE | 2 | Browsable, but not the default display location. |
| FOLDER\_ROLE\_HIDDEN | 3 | Match-only: folder filters still match entities through this placement, but it is not shown when browsing. Kept for legacy hierarchies. |
# Examples
Source: https://docs.synq.io/api-reference/examples
## Examples
You can find some language specific examples in the linked pages.
#### golang
* [1\_create\_types](examples/golang/1_create_types)
* [2\_create\_entities](examples/golang/2_create_entities)
* [3\_create\_features](examples/golang/3_create_features)
* [alerts\_management](examples/golang/alerts_management)
* [am\_deployment\_rules](examples/golang/am_deployment_rules)
* [atlan\_integration](examples/golang/atlan_integration)
* [create\_dataproduct](examples/golang/create_dataproduct)
* [datachecks](examples/golang/datachecks)
* [entity\_incidents](examples/golang/entity_incidents)
* [entity\_issues](examples/golang/entity_issues)
* [entity\_schema](examples/golang/entity_schema)
* [ingest\_dbt](examples/golang/ingest_dbt)
* [ingest\_sqlmesh](examples/golang/ingest_sqlmesh)
* [integrations\_management](examples/golang/integrations_management)
* [list\_sql\_tests](examples/golang/list_sql_tests)
* [manage\_sql\_tests](examples/golang/manage_sql_tests)
* [omni\_types](examples/golang/omni_types)
* [owners\_ownership](examples/golang/owners_ownership)
* [token\_auth](examples/golang/token_auth)
#### python
* [alerts\_management](examples/python/alerts_management)
* [ingest\_airflow\_logs](examples/python/ingest_airflow_logs)
* [integrations\_management](examples/python/integrations_management)
* [list\_sql\_tests](examples/python/list_sql_tests)
* [owners\_ownership](examples/python/owners_ownership)
# Getting Started
Source: https://docs.synq.io/api-reference/getting-started
Getting started with developer API at Coalesce Quality
# Overview
The Coalesce Quality API is available for developers to manage certain functionalities using custom workflows. Coalesce Quality exposes its API as [gRPC](https://grpc.io/) services. This means that the API are as easy to use as calling functions from your code.
To use the API, you need to do the following.
1. Clone protos from our github repository and generate the client code in the language of your choice.
2. Generate an access token and use it to connect to Coalesce Quality API.
3. Initialize clients and call functions in your code.
You can find language specific examples [here](https://github.com/getsynq/api/tree/main/examples).
# Client Code
The simplest way to use Coalesce Quality API is to use the SDKs from our [`buf` repository](https://buf.build/getsynq/api/sdks). Use select the language of your choice and follow the instructions to add the Coalesce Quality API to your project.
## Generating client code
If you prefer to, the client code can be generated from the protos available at our [github repository](https://github.com/getsynq/api).
```bash theme={null}
$ git clone git@github.com:getsynq/api.git
```
[gRPC](https://grpc.io/) supports a wide choice of languages and you can find the necessary guides on how to get started in a language of your choice [here](https://grpc.io/docs/languages/). You don't need to understand it all to get started with Coalesce Quality API. You just need to find the right tools to build the client code in your language of choice.
Additionally, you will need to install [protovalidate](https://github.com/bufbuild/protovalidate) in the language of your choice.
Following are some language references.
## Go
You will need the following plugins to generate golang code from the protos.
```bash theme={null}
$ go install google.golang.org/protobuf/cmd/protoc-gen-go
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
```
If you are starting off with gRPC and protos, it might be useful to follow the guide [here](https://grpc.io/docs/languages/go/quickstart/).
Run the following command from `` to generate the code in golang.
```bash theme={null}
$ protoc --proto_path=./protos --go_out=./gen2 --go-grpc_out=./gen protos/**/*.proto
```
The generated code is added to the `./gen` folder. You can change the location or find more options [here](https://protobuf.dev/reference/go/go-generated/) on how to use the `protoc` generator to suit your project's needs.
## Python
You will need the following tools to generate python code from the protos.
```bash theme={null}
$ python -m pip install grpcio
$ python -m pip install grpcio-tools
```
If you are starting off with gRPC and protos, it might be useful to follow the guide [here](https://grpc.io/docs/languages/python/quickstart/).
Run the following command from `` to generate the code in golang.
```bash theme={null}
$ python3 -m grpc_tools.protoc -Iprotos --python_out=./gen --pyi_out=./gen --grpc_python_out=./gen protos/**/*.proto
```
The generated code is added to the `./gen` folder. You can change the location to suit your project's needs.
# Fetching Access Token
You need a valid access token to communicate with the Coalesce Quality servers. To generate the access token, you need client credentials.
You can generate an client credentials (`CLIENT_ID` and `CLIENT_SECRET`) from the [Coalesce Quality application](https://app.synq.io/settings/api). The credentials are scoped so make sure to select the one best suited to execute the RPCs that you wish to.
You can now fetch the token source by making the following `POST` call to our OAuth2 server.
```bash theme={null}
curl -d "client_id=&client_secret=&grant_type=client_credentials" -X POST http://api.synq.io/oauth2/token
```
The response will have the following structure.
```json theme={null}
{
"access_token": ,
"expires_in": ,
...
}
```
The `` thus fetched is a valid JWT token which should be passed on to the calls made to Coalesce Quality API.
# Examples
The language specific examples to use Coalesce Quality APIs can be found [here](https://docs.synq.io/api-reference/examples).
# Troubleshooting
* If you experience a considerable slowness in connecting to the gRPC services, please flush your DNS cache. This is specially relevant if you are behind a VPN.
```
dscacheutil -flushcache
killall -HUP mDNSResponder
```
# API Scopes
Source: https://docs.synq.io/api-reference/scopes
Scopes that can be granted to Coalesce Quality API tokens and OAuth clients, and the public API methods each one unlocks
Every Coalesce Quality API token and OAuth client credential is granted a set of **scopes**. A scope authorises a group of related API methods; a call succeeds when the token carries **at least one** of the scopes required by that method (OR semantics).
Choose the narrowest set of scopes that covers the methods your integration calls. Scopes are selected when you create a token or client in [API settings](https://app.synq.io/settings/api), in the order listed below.
There are 53 scopes available to API tokens and OAuth clients. Internal scopes reserved for managed integrations are not listed here.
## Edit Issues
`SCOPE_ISSUES_EDIT`
Create and update data quality issues, including changing their status and assignees.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `MarkExpected` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-expected` | Mark issue as expected. |
| `MarkFixed` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-fixed` | Mark issue as fixed. |
| `MarkInvestigating` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-investigating` | Mark issue as being investigated. |
| `MarkNoActionNeeded` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-no-action-needed` | Mark issue as no action needed. |
| `PostComment` *synq.issues.issues.v1.IssuesService* `POST /api/issues/v1/{issue_id}/comment` | Post a comment on an issue. |
| `ClearStatus` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/clear-status` | Clear the triage status of an issue, returning it to an untriaged state. |
| `MarkExpected` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-expected` | Mark issue as expected. |
| `MarkFixed` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-fixed` | Mark issue as fixed. |
| `MarkInvestigating` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-investigating` | Mark issue as being investigated. |
| `MarkNoActionNeeded` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-no-action-needed` | Mark issue as no action needed. |
| `PostComment` *synq.issues.v2.IssuesService* `POST /api/issues/v2/{issue_id}/comment` | Post a comment on an issue. |
## Read Issues
`SCOPE_ISSUES_READ`
View data quality issues and their details.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `BatchGetIssues` *synq.issues.issues.v1.IssuesService* `POST /api/issues/v1/by-id` | |
| `ListIssues` *synq.issues.issues.v1.IssuesService* `GET /api/issues/v1` | |
| `BatchGetIssues` *synq.issues.v2.IssuesService* `POST /api/issues/v2/by-id` | |
| `ListIssues` *synq.issues.v2.IssuesService* `GET /api/issues/v2` | |
## Edit Incidents
`SCOPE_INCIDENTS_EDIT`
Declare, update, and resolve incidents raised for confirmed issues with business impact.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| `AddIssuesToIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/issues` | |
| `AssignIncidentOwner` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/assign-owner` | |
| `CancelIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/cancel` | Cancel an incident |
| `CloseIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/close` | Close an incident |
| `CreateIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1` | |
| `MergeIncidents` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/merge` | |
| `PostComment` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/comment` | Post a comment on an incident. |
| `RemoveIssuesFromIncident` *synq.incidents.v1.IncidentsService* `DELETE /api/incidents/v1/{incident_id}/issues` | |
| `RenameIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/rename` | |
| `SplitIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/split` | |
| `UpdateIncidentState` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/state` | |
## Read Incidents
`SCOPE_INCIDENTS_READ`
View incidents, including their status and the issues they track.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `BatchGetIncidents` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/by-id` | |
| `ListIncidents` *synq.incidents.v1.IncidentsService* `GET /api/incidents/v1` | |
## Edit Entities
`SCOPE_ENTITY_EDIT`
Create and update entities such as tables, dashboards, and jobs in the catalog.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `DeleteCheckRelationships` *synq.entities.custom.v1.ChecksRelationshipsService* `DELETE /api/entities/custom/v1/check-relationships` | Delete relationships between checks and the entities they validate. |
| `UpsertCheckRelationships` *synq.entities.custom.v1.ChecksRelationshipsService* `POST /api/entities/custom/v1/check-relationships` | Create or update relationships that attach a check (e.g. a SQL test) to the |
| `DeleteEntity` *synq.entities.custom.v1.EntitiesService* `DELETE /api/entities/custom/v1/entities` | Delete an entity by its identifier. If the entity does not exist, it will be a no-op. |
| `UpsertEntity` *synq.entities.custom.v1.EntitiesService* `POST /api/entities/custom/v1/entities` | Create or update an entity. If the entity does not exist, it will be created, otherwise it will be u... |
| `DeleteEntityFeature` *synq.entities.custom.v1.FeaturesService* `DELETE /api/entities/custom/v1/features` | Delete an entity by its identifier. If the entity does not exist, it will be a no-op. |
| `UpsertEntityFeature` *synq.entities.custom.v1.FeaturesService* `POST /api/entities/custom/v1/features` | Create or update an entity. If the entity does not exist, it will be created, otherwise it will be u... |
| `DeleteEntitiesGroup` *synq.entities.custom.v1.GroupsService* `DELETE /api/entities/custom/v1/groups` | DeleteEntitiesGroup deletes a group by its identifier. If the group does not exist, it will be a no-... |
| `UpsertEntitiesGroup` *synq.entities.custom.v1.GroupsService* `POST /api/entities/custom/v1/groups` | UpsertEntitiesGroup updates current definition of group to the server. As part of the upsert operati... |
## Read Entities
`SCOPE_ENTITY_READ`
View entities such as tables, dashboards, and jobs, along with their metadata.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `GenerateConnectionsYaml` *synq.agent.dwh.v1.ConnectionsService* | GenerateConnectionsYaml converts data warehouse connections to YAML configuration format. |
| `ListConnections` *synq.agent.dwh.v1.ConnectionsService* | ListConnections retrieves data warehouse connections for a workspace. |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `ListAnnotations` *synq.entities.annotations.v1.AnnotationsService* `GET /api/entities/annotations/v1` | List all available annotations with their usage counts across entities. |
| `BatchChange` *synq.entities.changes.v1.ChangesService* `POST /api/changes/v1/by-id` | BatchChange retrieves multiple entity changes by their IDs in a single request. |
| `List` *synq.entities.changes.v1.ChangesService* `GET /api/changes/v1` | Retrieves the complete change history for specified entities. |
| `GetCoverage` *synq.entities.checks.v1.ChecksCoverageService* | GetCoverage retrieves the coverage of checks for a specific entity. |
| `GetTableConstraints` *synq.entities.constraints.v1.TableConstraintsService* `GET /api/constraints/v1/table-constraints` | Get table constraints (primary keys, foreign keys, indexes, etc.) for a given entity. |
| `BatchDatabaseCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-id` | Get multiple DatabaseCoordinates for identifiers. |
| `BatchIdsByCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-fqn` | Given database FQN return possible entity ids. |
| `ListEntities` *synq.entities.custom.v1.EntitiesService* `GET /api/entities/custom/v1/entities` | List all entities. |
| `ListEntityFeatures` *synq.entities.custom.v1.FeaturesService* `POST /api/entities/custom/v1/features/list` | List all entities. |
| `ListEntityGroups` *synq.entities.custom.v1.GroupsService* `POST /api/entities/custom/v1/groups/list` | ListEntityGroups lists all groups. |
| `ListTypes` *synq.entities.custom.v1.TypesService* `POST /api/entities/custom/v1/types/list` | List all entities. |
| `BatchGetEntities` *synq.entities.entities.v1.EntitiesService* `POST /api/entities/v1/by-id` | Get multiple entities by their identifiers. |
| `GetEntity` *synq.entities.entities.v1.EntitiesService* | Get specific entity by its identifier. |
| `ListEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1` | List entities matching the given filter |
| `SearchEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1/search` | Search for entities. |
| `Browse` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/browse` `GET /api/entities/folders/v1/browse` | Browse the hierarchy one level at a time. With no `parent`, returns the |
| `GetFolderOf` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/folder-of` `GET /api/entities/folders/v1/folder-of` | Given entity ids, return the folder breadcrumb(s) each entity lives in — |
| `ListMembers` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/members` `GET /api/entities/folders/v1/members` | List the entity ids contained in a folder, paginated. Direct members only by |
| `GetImpact` *synq.entities.impact.v1.ImpactService* `POST /api/impact/v1` | |
| `BatchResolveIdentifiers` *synq.entities.resolve.v1.IdentifierResolveService* `POST /api/resolve/v1/by-id` | Resolve multiple identifiers, returning their Coalesce Quality paths and identity groups. |
| `BatchSchemaMismatches` *synq.entities.schemas.v1.SchemaMismatchesService* `POST /api/schema-mismatches/v1` | Get schema mismatches for a batch of entities by their identifiers. |
| `GetSchema` *synq.entities.schemas.v1.SchemasService* `GET /api/schema/v1` | Get schema of the entity its identifier. |
| `BatchSqlDetails` *synq.entities.sql\_insights.v1.SqlInsightsService* `POST /api/sql-insights/v1/details:batch` | BatchSqlDetails returns the SQL details (currently the set of detected SQL |
| `ListSqlConstructs` *synq.entities.sql\_insights.v1.SqlInsightsService* `GET /api/sql-insights/v1/constructs` | ListSqlConstructs returns the distribution of SQL constructs across all |
| `GetDiffByCommit` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/commit/{commit_sha}` | |
| `BatchGetLatestEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `POST /api/monitors/predictions/v1/entity-metrics:batchLatest` | Returns the most recent observed table-stats sample (row count, freshness) for each |
| `GetEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1/entity-metrics` | Returns raw metric timeseries for an entity. Identity-aware: resolves |
| `GenerateQuery` *synq.queries.v1.NLQueryService* `POST /api/queries/v1/generate` | GenerateQuery generates a Query from a natural language description. |
| `ResolveQuery` *synq.queries.v1.QueriesService* `POST /api/queries/v1/resolve` | Evaluate a selection and return the matched entity ids, paginated. Pass a |
| `TranslateResolverQl` *synq.queries.v1.QueriesService* `POST /api/queries/v1/translate-resolver-ql` | Compile a ResolverQL expression into a structured public `Query`. Unlike |
## Edit Entity Types
`SCOPE_ENTITY_TYPE_EDIT`
Define and update custom entity types.
| Method | Description |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `DeleteType` *synq.entities.custom.v1.TypesService* `DELETE /api/entities/custom/v1/types` | Delete an entity by its identifier. If the entity does not exist, it will be a no-op. |
| `UpsertType` *synq.entities.custom.v1.TypesService* `POST /api/entities/custom/v1/types` | Create or update an entity. If the entity does not exist, it will be created, otherwise it will be u... |
## Read Entity Types
`SCOPE_ENTITY_TYPE_READ`
View entity type definitions.
| Method | Description |
| ------------------------------------------------------------------------------------------------------ | ------------------ |
| `ListTypes` *synq.entities.custom.v1.TypesService* `POST /api/entities/custom/v1/types/list` | List all entities. |
## Edit Lineage
`SCOPE_LINEAGE_EDIT`
Create and update lineage relationships between entities.
| Method | Description |
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `DeleteRelationships` *synq.entities.custom.v1.RelationshipsService* `DELETE /api/entities/custom/v1/relationships` | Delete relationships between entities. If the relationship does not exist, it will be ignored. |
| `UpsertRelationships` *synq.entities.custom.v1.RelationshipsService* `POST /api/entities/custom/v1/relationships` | Create or update relationships between entities. If the relationship already exists, it will be upda... |
## Read Lineage
`SCOPE_LINEAGE_READ`
View upstream and downstream lineage between entities.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `ListRelationships` *synq.entities.custom.v1.RelationshipsService* `POST /api/entities/custom/v1/relationships/list` | Delete relationships between entities. If the relationship does not exist, it will be ignored. |
| `GetImpact` *synq.entities.impact.v1.ImpactService* `POST /api/impact/v1` | |
| `GetLineage` *synq.entities.lineage.v1.LineageService* `POST /api/lineage/v1` | |
| `BatchOrchestration` *synq.entities.orchestration.v1.OrchestrationService* `GET /api/orchestration/v1` | BatchOrchestration retrieves orchestration relationships for multiple entities. |
## Read Entity Code
`SCOPE_CODE_READ`
View the SQL or source code associated with an entity.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `ListCode` *synq.entities.code.v1.CodeService* `GET /api/code/v1` | ListCode retrieves all code artifacts associated with a specific entity. |
| `GetDiffByChangeId` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/change/{change_id}` | |
## Read Entity Status
`SCOPE_STATUS_READ`
View the health and status of entities, including status summaries and history.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `BatchGetIncidents` *synq.entities.status.v1.EntityIncidentsService* `POST /api/status/v1/incidents/by-id` | Get multiple entity statuses by their identifiers. |
| `GetIncidents` *synq.entities.status.v1.EntityIncidentsService* | Get specific entity status by its identifier. |
| `BatchGetIssuesStatus` *synq.entities.status.v1.EntityIssuesService* `POST /api/status/v1/issues/by-id` | Get multiple entity statuses by their identifiers. |
| `GetIssuesStatus` *synq.entities.status.v1.EntityIssuesService* | Get specific entity status by its identifier. |
## Edit SQL Tests
`SCOPE_DATACHECKS_SQLTESTS_EDIT`
Create, update, and delete SQL tests.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| `BatchDeleteSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `DELETE /api/datachecks/sqltests/v1` | Delete SqlTests by their IDs. |
| `BatchUpsertSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `POST /api/datachecks/sqltests/v1` | Upsert SqlTests based on a unique ID. |
## Read SQL Tests
`SCOPE_DATACHECKS_SQLTESTS_READ`
View SQL tests and their configuration.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `BatchGetSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `POST /api/datachecks/sqltests/v1/by-id` | Get SqlTests by their IDs. |
| `ListSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `GET /api/datachecks/sqltests/v1` | List SqlTests for given annotations. |
## Read SQL Tests Audit
`SCOPE_DATACHECKS_SQLTESTS_AUDIT_READ`
View the audit history of changes to SQL tests.
| Method | Description |
| -------------------------------------------------------------------- | --------------------------------------------------------- |
| `GetSqlTestAudit` *synq.datachecks.sqltests.v1.SqlTestsService* | Get SqlTest audit from a given execution ID in jwt token. |
## Edit Test Suggestions
`SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT`
Accept, dismiss, and manage suggested tests.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- |
| `MarkAsCancelled` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `MarkAsCompleted` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `MarkAsFailed` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `MarkAsRunning` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `SuggestFor` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `BatchAcceptTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `PATCH /api/datachecks/testsuggestions/v1/accepted` | |
| `BatchCreateTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `POST /api/datachecks/testsuggestions/v1` | |
| `BatchRejectTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `PATCH /api/datachecks/testsuggestions/v1/rejected` | |
## Read Test Suggestions
`SCOPE_DATACHECKS_TESTSUGGESTIONS_READ`
View suggested tests.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `BatchSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `GetActiveSuggestionStatesFor` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `ListSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `BatchGetTestSuggestionsForEntities` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `GET /api/datachecks/testsuggestions/v1` | |
## Trigger Data Checks
`SCOPE_DATACHECKS_TRIGGER`
Trigger data checks to run on demand.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `TriggerDatachecks` *synq.datachecks.v1.TriggerService* `POST /api/datachecks/scheduler/v1/trigger` | TriggerDatachecks executes datachecks for the specified entities. |
## Edit Executions
`SCOPE_EXECUTION_EDIT`
Report execution runs and their results.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `UpsertExecution` *synq.entities.custom.v1.EntityExecutionsService* `POST /api/entities/custom/executions/v1` | Execution affects status of the custom entity |
| `UpsertLogEntry` *synq.entities.custom.v1.EntityExecutionsService* `POST /api/entities/custom/executions/v1/log-entry` | LogEntry is a log message for the custom entity |
| `UpsertExecution` *synq.entities.executions.v1.EntityExecutionsService* `POST /api/executions/v1` | Execution affects status of the custom entity |
| `UpsertLogEntry` *synq.entities.executions.v1.EntityExecutionsService* `POST /api/executions/v1/log-entry` | LogEntry is a log message for the custom entity |
## Edit Execution Logs
`SCOPE_EXECUTION_LOG_EDIT`
Write logs for execution runs.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| `UpsertLogEntry` *synq.entities.custom.v1.EntityExecutionsService* `POST /api/entities/custom/executions/v1/log-entry` | LogEntry is a log message for the custom entity |
| `UpsertLogEntry` *synq.entities.executions.v1.EntityExecutionsService* `POST /api/executions/v1/log-entry` | LogEntry is a log message for the custom entity |
## Read Executions
`SCOPE_EXECUTION_READ`
View execution run history and results.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `BatchGetExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/by-id` | BatchGetExecutions retrieves multiple executions by their IDs. |
| `GetExecutionsSummary` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/summary` | GetExecutionsSummary provides aggregated statistics about executions for specified entities. |
| `GetLatestExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/latest` | GetLatestExecutions retrieves the most recent execution for each specified entity. |
| `ListExecutions` *synq.entities.executions.v2.EntityExecutionsService* `GET /api/executions/v2/list` | ListExecutions retrieves a paginated list of executions for one or more entities. |
## Edit Integration Settings
`SCOPE_INTEGRATION_EDIT`
Create, update, and delete integrations and their connection settings.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| `AcceptPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | AcceptPromptSuggestion applies a pending suggestion to the matching SRE agent |
| `DismissPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | DismissPromptSuggestion marks a pending suggestion as dismissed with an optional |
| `RecordPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | RecordPromptSuggestion is the producer-side endpoint used by the offline |
| `BatchGetIntegrations` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/by-id` | Fetch multiple integrations by id in one call. Ids not found (or not in the |
| `CreateIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1` | Create a new integration. The server assigns the id and returns the created |
| `DeleteIntegration` *synq.integrations.v1.IntegrationsService* `DELETE /api/integrations/v1/{integration_id}` | Delete an integration. The integration stops being scheduled and is removed |
| `DisableIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/disable` | Disable an integration without deleting it. The configuration is kept but |
| `EnableIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/enable` | Enable a previously disabled integration. No-op if already enabled. |
| `GetIntegration` *synq.integrations.v1.IntegrationsService* | Fetch a single integration by id. Secret config fields are masked. |
| `GetIntegrationHealth` *synq.integrations.v1.IntegrationsService* | Return current health plus a paginated history of recent runs for an |
| `ListIntegrations` *synq.integrations.v1.IntegrationsService* `GET /api/integrations/v1` | List all integrations in the workspace (optionally filtered by enabled |
| `RefreshIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/refresh` | Trigger an immediate, ad-hoc refresh of an integration. Available only for |
| `UpdateIntegration` *synq.integrations.v1.IntegrationsService* `PUT /api/integrations/v1/{integration_id}` | Update an integration. The `config` is replaced wholesale — send the |
| `SetPlatformAuthentication` *synq.platforms.v1.PlatformsService* `POST /api/platforms/v1` | |
## Read Integration Settings
`SCOPE_INTEGRATION_READ`
View integrations and their connection settings.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `GetConfig` *synq.agent.sre.v1.SreAgentService* | GetConfig returns the Scout configuration (system prompts + DWH connection |
| `ListPromptSuggestions` *synq.agent.sre.v1.SreAgentService* | ListPromptSuggestions returns prompt-improvement suggestions recorded for the |
| `Get` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `GET /api/extensions/atlan/integrations/v1` | |
| `BatchGetIntegrations` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/by-id` | Fetch multiple integrations by id in one call. Ids not found (or not in the |
| `GetIntegration` *synq.integrations.v1.IntegrationsService* | Fetch a single integration by id. Secret config fields are masked. |
| `GetIntegrationHealth` *synq.integrations.v1.IntegrationsService* | Return current health plus a paginated history of recent runs for an |
| `ListIntegrations` *synq.integrations.v1.IntegrationsService* `GET /api/integrations/v1` | List all integrations in the workspace (optionally filtered by enabled |
## Edit Users
`SCOPE_USER_EDIT`
Manage workspace members, including inviting users and updating their roles.
| Method | Description |
| ----------------------------------------------------- | ----------- |
| `DeleteUserAliases` *synq.users.v1.UsersService* | |
| `UpsertUserAliases` *synq.users.v1.UsersService* | |
## Read Users
`SCOPE_USER_READ`
View workspace members and their roles.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| `ListDomainMembers` *synq.domains.members.v1.DomainMembersService* `GET /api/domains/members/v1/{domain_id}/members` | List domain members. |
| `ListUserDomains` *synq.domains.members.v1.DomainMembersService* `GET /api/domains/members/v1/users/{user_id}/domains` | List domains for the given user. |
| `SetDefaultUserDomain` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/default-for-user` | Set default domain for user. |
| `BatchGetUsers` *synq.users.v1.UsersService* | |
| `GetByAlias` *synq.users.v1.UsersService* | |
| `GetByEmail` *synq.users.v1.UsersService* | |
| `GetUserAliases` *synq.users.v1.UsersService* | |
| `GetUserIdentities` *synq.users.v1.UsersService* | Returns all canonical identity strings for a user. |
| `ListUsers` *synq.users.v1.UsersService* | |
## Assign Users
`SCOPE_USER_ASSIGN`
Assign users as owners of entities, issues, and other resources.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
| `AddDomainMembers` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/members` | Add domain members. |
| `RemoveDomainMembers` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/members/remove` | Remove domain members. |
## Read Monitors
`SCOPE_MONITORS_READ`
View monitors and their configuration.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `ListConfigsMonitors` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `GET /api/monitors/custom-monitors/v1/by-config` | |
| `ListMonitors` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `GET /api/monitors/custom-monitors/v1` | |
| `History` *synq.monitors.history.v1.HistoryService* `GET /api/monitors/history/v1/{monitor_path}` | |
| `MonitorInfo` *synq.monitors.info.v1.MonitorInfoService* `GET /api/monitors/info/v1` | |
| `BatchGetLatestEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `POST /api/monitors/predictions/v1/entity-metrics:batchLatest` | Returns the most recent observed table-stats sample (row count, freshness) for each |
| `GetEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1/entity-metrics` | Returns raw metric timeseries for an entity. Identity-aware: resolves |
| `GetMonitorPredictions` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1` | Returns prediction timeseries for a monitor. The monitor must exist |
## Edit Automatic Monitors
`SCOPE_MONITORS_AUTOMATIC_EDIT`
Enable, disable, and configure automatic monitors.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `BatchDeleteDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `DELETE /api/monitors/automated/v1/deployment-rules/batch` | |
| `BatchDeployDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/batch/deployed` | |
| `BatchGetDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules/batch` | |
| `BatchUpdateDeploymentRuleTitle` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `PATCH /api/monitors/automated/v1/deployment-rules` | |
| `BatchUpsertDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/batch` | |
| `DeleteDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `DELETE /api/monitors/automated/v1/deployment-rule/{id}` | |
| `DeployDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/deployed` | |
| `GetDeployDeleteOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule/{id}/deleted` | |
| `GetDeployOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule` | |
| `ListDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules` | |
| `ListDeploymentRulesForAsset` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules/{asset_path}` | |
| `UpsertDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules` | |
## Edit Custom Monitors
`SCOPE_MONITORS_CUSTOM_EDIT`
Create, update, and delete custom monitors.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `BatchCreateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1` | |
| `BatchDeleteMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/delete` | |
| `BatchUpdateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `PUT /api/monitors/custom-monitors/v1` | |
| `BatchUpdateMonitorMode` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/mode` | |
| `BatchUpdateMonitorSeverity` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/severity` | |
| `ConfigChangesOverview` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/config-changes` | |
## Edit Custom SQL Monitors
`SCOPE_MONITORS_CUSTOM_SQL_EDIT`
Create and update custom monitors backed by a custom SQL query.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `BatchCreateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1` | |
| `BatchUpdateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `PUT /api/monitors/custom-monitors/v1` | |
## Edit Alerts
`SCOPE_ALERTS_EDIT`
Create, update, and delete alert rules and notification channels.
| Method | Description |
| ---------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `Create` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1` | Create a new alert configuration. |
| `Delete` *synq.alerts.services.v1.AlertsService* `DELETE /api/alerts/v1` | Delete an existing alert configuration. |
| `ToggleEnabled` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/toggle` | Enables or disables an existing alert configuration. |
| `Update` *synq.alerts.services.v1.AlertsService* `PUT /api/alerts/v1` | Update an existing alert configuration. |
## Read Alerts
`SCOPE_ALERTS_READ`
View alert rules and notification channels.
| Method | Description |
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `BatchGet` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/get` | Get multiple alert configurations by their identifiers. |
| `List` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/list` | Retrieves a list of alert configurations based on filters. |
## Edit Owners
`SCOPE_OWNERS_EDIT`
Create, update, and delete owners and their notification channels (Slack, email, Microsoft Teams, users).
| Method | Description |
| ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| `DeleteOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1/delete` | Delete an owner and all of its ownerships. Idempotent — deleting an |
| `UpsertOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1` | Create or update an owner. The id is supplied by the caller (a UUID); |
## Read Owners
`SCOPE_OWNERS_READ`
View owners and their notification channels.
| Method | Description |
| ----------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| `BatchGetOwners` *synq.owners.v1.OwnersService* `POST /api/owners/v1/batch-get` | Fetch multiple owners by id. Ids that do not exist (or, unless |
| `ListOwners` *synq.owners.v1.OwnersService* `GET /api/owners/v1` | List the owners in the workspace, paginated. |
## Edit Ownership
`SCOPE_OWNERSHIP_EDIT`
Create, update, and delete ownership assignments and the alerts they route to owners.
| Method | Description |
| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| `DeleteOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/delete` | Delete an ownership by id. Idempotent — deleting an already-deleted or |
| `UpsertOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/{owner_id}/ownerships` | Create or update an ownership under an owner. The ownership id is supplied |
## Read Ownership
`SCOPE_OWNERSHIP_READ`
View ownership assignments and their alert routing.
| Method | Description |
| -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `BatchGetOwnerships` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/batch-get` | Fetch multiple ownerships by id (across owners). Ids that do not exist (or, |
| `ListOwnerships` *synq.owners.v1.OwnersService* `GET /api/owners/v1/{owner_id}/ownerships` | List the ownerships of an owner, paginated. |
## Edit Data Products
`SCOPE_DATAPRODUCT_EDIT`
Create, update, and delete data products.
| Method | Description |
| ----------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `Delete` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/delete` | Delete a dataproduct by its identifier. |
| `RemoveDefinitionPart` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition/part/delete` | Remove definition part from the definition of an existing dataproduct. |
| `SetDefinition` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition` | Set the definition for an existing dataproduct. |
| `Upsert` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1` | Create or update a dataproduct. |
| `UpsertDefinitionPart` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition/part` | Upsert definition part to the definition of an existing dataproduct. |
| `Delete` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/delete` | Delete a data product. Idempotent — deleting an already-deleted or unknown |
| `RemoveDefinitionPart` *synq.dataproducts.v2.DataproductsService* `DELETE /api/dataproducts/v2/{id}/definition/parts/{part_id}` | Remove a single definition part by its part id. Idempotent. |
| `SetDefinition` *synq.dataproducts.v2.DataproductsService* `PUT /api/dataproducts/v2/{id}/definition` | Replace the entire membership definition of a data product. |
| `Upsert` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2` | Create or update a data product. The id is supplied by the caller (a UUID); |
| `UpsertDefinitionPart` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/{id}/definition/parts` | Add or replace a single definition part (matched by its part id). |
## Read Data Products
`SCOPE_DATAPRODUCT_READ`
View data products and their contents.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `Get` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/get` | Get multiple dataproducts by their identifiers. |
| `List` *synq.dataproducts.v1.DataproductsService* `GET /api/dataproducts/v1` | List all the dataproducts in the current scope. |
| `BatchGet` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/batch-get` | Fetch multiple data products by id. Ids that do not exist (or, unless |
| `List` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2` | List the data products in the workspace, paginated. Narrow with `folder` |
| `ListMembers` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2/{id}/members` | List the assets that currently belong to a data product, resolved from its |
## Edit Domains
`SCOPE_DOMAIN_EDIT`
Create, update, and delete domains.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `Delete` *synq.domains.v1.DomainsService* `POST /api/domains/v1/delete` | Delete a domain by its identifier. |
| `RemoveDefinitionPart` *synq.domains.v1.DomainsService* `DELETE /api/domains/v1/{domain_id}/definition/parts/{part_id}` | Remove definition part from the definition of an existing domain. |
| `SetDefinition` *synq.domains.v1.DomainsService* `PUT /api/domains/v1/{domain_id}/definition` | Set the definition for an existing domain. |
| `Upsert` *synq.domains.v1.DomainsService* `POST /api/domains/v1` | Create or update a domain. |
| `UpsertDefinitionPart` *synq.domains.v1.DomainsService* `POST /api/domains/v1/{domain_id}/definition/parts` | Upsert definition part to the definition of an existing domain. |
| `Delete` *synq.domains.v2.DomainsService* `POST /api/domains/v2/delete` | Delete a domain. Idempotent — deleting an already-deleted or unknown domain |
| `RemoveDefinitionPart` *synq.domains.v2.DomainsService* `DELETE /api/domains/v2/{id}/definition/parts/{part_id}` | Remove a single definition part by its part id. Idempotent. |
| `SetDefinition` *synq.domains.v2.DomainsService* `PUT /api/domains/v2/{id}/definition` | Replace the entire membership definition of a domain. |
| `Upsert` *synq.domains.v2.DomainsService* `POST /api/domains/v2` | Create or update a domain. The id is supplied by the caller (a UUID); |
| `UpsertDefinitionPart` *synq.domains.v2.DomainsService* `POST /api/domains/v2/{id}/definition/parts` | Add or replace a single definition part (matched by its part id). |
## Read Domains
`SCOPE_DOMAIN_READ`
View domains and their contents.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `BatchGet` *synq.domains.v1.DomainsService* `POST /api/domains/v1/batch-get` | Get multiple domains by their identifiers. |
| `FetchDomainWithSubDomains` *synq.domains.v1.DomainsService* `GET /api/domains/v1/{domain_id}/sub-domains` | Get a domain with its sub-domains |
| `List` *synq.domains.v1.DomainsService* `GET /api/domains/v1` | List all the domains in the current workspace. |
| `BatchGet` *synq.domains.v2.DomainsService* `POST /api/domains/v2/batch-get` | Fetch multiple domains by id. Ids that do not exist (or, unless |
| `FetchDomainWithSubDomains` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/sub-domains` | Fetch a domain together with its direct sub-domains, keyed by id. |
| `List` *synq.domains.v2.DomainsService* `GET /api/domains/v2` | List the domains in the workspace, paginated. Narrow to one level of the |
| `ListMembers` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/members` | List the assets that currently belong to a domain, resolved from its |
## Manage Extensions
`SCOPE_EXTENSIONS_MANAGE`
Manage platform extensions, including data warehouse agent and catalog connections.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `GenerateConnectionsYaml` *synq.agent.dwh.v1.ConnectionsService* | GenerateConnectionsYaml converts data warehouse connections to YAML configuration format. |
| `ListConnections` *synq.agent.dwh.v1.ConnectionsService* | ListConnections retrieves data warehouse connections for a workspace. |
| `Activate` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `PATCH /api/extensions/atlan/integrations/v1` | Activate or deactivate the integration. |
| `Ping` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `POST /api/extensions/atlan/integrations/v1/ping` | Pings Atlan with the given connection credentials. |
| `Remove` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `DELETE /api/extensions/atlan/integrations/v1` | |
| `Upsert` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `POST /api/extensions/atlan/integrations/v1` | Upserts an integration and validates it by checking if the provided API URL and token are valid. |
| `GetAtlanConnections` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/connections` | |
| `GetAtlanDataProducts` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/data-products` | |
| `GetAtlanDomains` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/domains` | |
| `FetchRuns` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/runs` | |
| `GetConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/connection-mappings` | |
| `GetDomainMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/domain-mappings` | |
| `GetMappingToggles` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/mappings/toggle` | |
| `GetProductMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/product-mappings` | |
| `RemoveConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `DELETE /api/extensions/atlan/workflows/v1/connection-mappings` | |
| `SetConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/connection-mappings` | |
| `SetMappingToggles` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/mappings/toggle` | |
| `Synchronize` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/synchronize` | Run a synchronization job for the integration. |
## MCP Read Access
`SCOPE_MCP_READ`
Use any read-only MCP (Model Context Protocol) tool, including tools added in the future.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `GenerateConnectionsYaml` *synq.agent.dwh.v1.ConnectionsService* | GenerateConnectionsYaml converts data warehouse connections to YAML configuration format. |
| `ListConnections` *synq.agent.dwh.v1.ConnectionsService* | ListConnections retrieves data warehouse connections for a workspace. |
| `GetAuditLog` *synq.agent.recon.v1.AuditLogService* | GetAuditLog returns a single audit log by invocation ID. |
| `ListAuditLogs` *synq.agent.recon.v1.AuditLogService* | ListAuditLogs returns audit logs ordered from newest to oldest, optionally filtered by suite and tim... |
| `BatchReconciliationRunState` *synq.agent.recon.v1.RunStateService* | BatchReconciliationRunState returns the latest concluded run and any ongoing |
| `ListReconciliationRunState` *synq.agent.recon.v1.RunStateService* | ListReconciliationRunState returns runs filtered by status and/or suite\_id. |
| `GetSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | Get the latest version of a suite config by suite\_id. |
| `GetSuiteConfigVersion` *synq.agent.recon.v1.SuiteConfigService* | Get a specific historical version of a suite config. |
| `ListSuiteConfigVersions` *synq.agent.recon.v1.SuiteConfigService* | Get version history for a suite config. |
| `ListSuiteConfigs` *synq.agent.recon.v1.SuiteConfigService* | List latest suite configs with filtering and pagination. |
| `GetSuiteDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | Fetch a deployment by suite\_id or deployment\_id. |
| `ListSuiteDeploymentHistory` *synq.agent.recon.v1.SuiteDeploymentService* | List the append-only history of a deployment (every promote, |
| `ListSuiteDeployments` *synq.agent.recon.v1.SuiteDeploymentService* | List deployments for the caller's workspace. Filters support answering |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | SubmitFeatureRequest submits a feature request to the Coalesce Quality product team. |
| `GetConfig` *synq.agent.sre.v1.SreAgentService* | GetConfig returns the Scout configuration (system prompts + DWH connection |
| `ListPromptSuggestions` *synq.agent.sre.v1.SreAgentService* | ListPromptSuggestions returns prompt-improvement suggestions recorded for the |
| `BatchSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `GetActiveSuggestionStatesFor` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `ListSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | |
| `BatchLatestConclusions` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/conclusions` | Retrieves the latest triage state for one or more issues. This method is used by the LLM agent |
| `BatchTriageState` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/states` | Retrieves the triage state for one or more issues. This method is used by the LLM agent |
| `ListTriageState` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/statuses` | Retrieves the triage state for one or more issues. This method is used by the LLM agent |
| `BatchGetSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `POST /api/datachecks/sqltests/v1/by-id` | Get SqlTests by their IDs. |
| `ListSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `GET /api/datachecks/sqltests/v1` | List SqlTests for given annotations. |
| `BatchGetTestSuggestionsForEntities` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `GET /api/datachecks/testsuggestions/v1` | |
| `Get` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/get` | Get multiple dataproducts by their identifiers. |
| `List` *synq.dataproducts.v1.DataproductsService* `GET /api/dataproducts/v1` | List all the dataproducts in the current scope. |
| `BatchGet` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/batch-get` | Fetch multiple data products by id. Ids that do not exist (or, unless |
| `List` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2` | List the data products in the workspace, paginated. Narrow with `folder` |
| `ListMembers` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2/{id}/members` | List the assets that currently belong to a data product, resolved from its |
| `BatchGet` *synq.domains.v2.DomainsService* `POST /api/domains/v2/batch-get` | Fetch multiple domains by id. Ids that do not exist (or, unless |
| `FetchDomainWithSubDomains` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/sub-domains` | Fetch a domain together with its direct sub-domains, keyed by id. |
| `List` *synq.domains.v2.DomainsService* `GET /api/domains/v2` | List the domains in the workspace, paginated. Narrow to one level of the |
| `ListMembers` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/members` | List the assets that currently belong to a domain, resolved from its |
| `ListAnnotations` *synq.entities.annotations.v1.AnnotationsService* `GET /api/entities/annotations/v1` | List all available annotations with their usage counts across entities. |
| `BatchChange` *synq.entities.changes.v1.ChangesService* `POST /api/changes/v1/by-id` | BatchChange retrieves multiple entity changes by their IDs in a single request. |
| `List` *synq.entities.changes.v1.ChangesService* `GET /api/changes/v1` | Retrieves the complete change history for specified entities. |
| `GetCoverage` *synq.entities.checks.v1.ChecksCoverageService* | GetCoverage retrieves the coverage of checks for a specific entity. |
| `ListCode` *synq.entities.code.v1.CodeService* `GET /api/code/v1` | ListCode retrieves all code artifacts associated with a specific entity. |
| `GetTableConstraints` *synq.entities.constraints.v1.TableConstraintsService* `GET /api/constraints/v1/table-constraints` | Get table constraints (primary keys, foreign keys, indexes, etc.) for a given entity. |
| `BatchDatabaseCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-id` | Get multiple DatabaseCoordinates for identifiers. |
| `BatchIdsByCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-fqn` | Given database FQN return possible entity ids. |
| `ListEntities` *synq.entities.custom.v1.EntitiesService* `GET /api/entities/custom/v1/entities` | List all entities. |
| `ListEntityFeatures` *synq.entities.custom.v1.FeaturesService* `POST /api/entities/custom/v1/features/list` | List all entities. |
| `ListEntityGroups` *synq.entities.custom.v1.GroupsService* `POST /api/entities/custom/v1/groups/list` | ListEntityGroups lists all groups. |
| `ListRelationships` *synq.entities.custom.v1.RelationshipsService* `POST /api/entities/custom/v1/relationships/list` | Delete relationships between entities. If the relationship does not exist, it will be ignored. |
| `BatchGetEntities` *synq.entities.entities.v1.EntitiesService* `POST /api/entities/v1/by-id` | Get multiple entities by their identifiers. |
| `GetEntity` *synq.entities.entities.v1.EntitiesService* | Get specific entity by its identifier. |
| `ListEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1` | List entities matching the given filter |
| `SearchEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1/search` | Search for entities. |
| `BatchGetExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/by-id` | BatchGetExecutions retrieves multiple executions by their IDs. |
| `GetExecutionsSummary` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/summary` | GetExecutionsSummary provides aggregated statistics about executions for specified entities. |
| `GetLatestExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/latest` | GetLatestExecutions retrieves the most recent execution for each specified entity. |
| `ListExecutions` *synq.entities.executions.v2.EntityExecutionsService* `GET /api/executions/v2/list` | ListExecutions retrieves a paginated list of executions for one or more entities. |
| `Browse` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/browse` `GET /api/entities/folders/v1/browse` | Browse the hierarchy one level at a time. With no `parent`, returns the |
| `GetFolderOf` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/folder-of` `GET /api/entities/folders/v1/folder-of` | Given entity ids, return the folder breadcrumb(s) each entity lives in — |
| `ListMembers` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/members` `GET /api/entities/folders/v1/members` | List the entity ids contained in a folder, paginated. Direct members only by |
| `GetImpact` *synq.entities.impact.v1.ImpactService* `POST /api/impact/v1` | |
| `GetLineage` *synq.entities.lineage.v1.LineageService* `POST /api/lineage/v1` | |
| `BatchOrchestration` *synq.entities.orchestration.v1.OrchestrationService* `GET /api/orchestration/v1` | BatchOrchestration retrieves orchestration relationships for multiple entities. |
| `BatchResolveIdentifiers` *synq.entities.resolve.v1.IdentifierResolveService* `POST /api/resolve/v1/by-id` | Resolve multiple identifiers, returning their Coalesce Quality paths and identity groups. |
| `BatchSchemaMismatches` *synq.entities.schemas.v1.SchemaMismatchesService* `POST /api/schema-mismatches/v1` | Get schema mismatches for a batch of entities by their identifiers. |
| `GetSchema` *synq.entities.schemas.v1.SchemasService* `GET /api/schema/v1` | Get schema of the entity its identifier. |
| `BatchSqlDetails` *synq.entities.sql\_insights.v1.SqlInsightsService* `POST /api/sql-insights/v1/details:batch` | BatchSqlDetails returns the SQL details (currently the set of detected SQL |
| `ListSqlConstructs` *synq.entities.sql\_insights.v1.SqlInsightsService* `GET /api/sql-insights/v1/constructs` | ListSqlConstructs returns the distribution of SQL constructs across all |
| `BatchGetIncidents` *synq.entities.status.v1.EntityIncidentsService* `POST /api/status/v1/incidents/by-id` | Get multiple entity statuses by their identifiers. |
| `GetIncidents` *synq.entities.status.v1.EntityIncidentsService* | Get specific entity status by its identifier. |
| `BatchGetIssuesStatus` *synq.entities.status.v1.EntityIssuesService* `POST /api/status/v1/issues/by-id` | Get multiple entity statuses by their identifiers. |
| `GetDiffByChangeId` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/change/{change_id}` | |
| `GetDiffByCommit` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/commit/{commit_sha}` | |
| `BatchGetIncidents` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/by-id` | |
| `ListIncidents` *synq.incidents.v1.IncidentsService* `GET /api/incidents/v1` | |
| `BatchGetIssues` *synq.issues.issues.v1.IssuesService* `POST /api/issues/v1/by-id` | |
| `ListIssues` *synq.issues.issues.v1.IssuesService* `GET /api/issues/v1` | |
| `BatchGetIssues` *synq.issues.v2.IssuesService* `POST /api/issues/v2/by-id` | |
| `ListIssues` *synq.issues.v2.IssuesService* `GET /api/issues/v2` | |
| `GetDeployDeleteOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule/{id}/deleted` | |
| `GetDeployOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule` | |
| `ListDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules` | |
| `History` *synq.monitors.history.v1.HistoryService* `GET /api/monitors/history/v1/{monitor_path}` | |
| `MonitorInfo` *synq.monitors.info.v1.MonitorInfoService* `GET /api/monitors/info/v1` | |
| `BatchGetLatestEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `POST /api/monitors/predictions/v1/entity-metrics:batchLatest` | Returns the most recent observed table-stats sample (row count, freshness) for each |
| `GetEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1/entity-metrics` | Returns raw metric timeseries for an entity. Identity-aware: resolves |
| `GetMonitorPredictions` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1` | Returns prediction timeseries for a monitor. The monitor must exist |
| `BatchGetOwners` *synq.owners.v1.OwnersService* `POST /api/owners/v1/batch-get` | Fetch multiple owners by id. Ids that do not exist (or, unless |
| `BatchGetOwnerships` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/batch-get` | Fetch multiple ownerships by id (across owners). Ids that do not exist (or, |
| `ListOwners` *synq.owners.v1.OwnersService* `GET /api/owners/v1` | List the owners in the workspace, paginated. |
| `ListOwnerships` *synq.owners.v1.OwnersService* `GET /api/owners/v1/{owner_id}/ownerships` | List the ownerships of an owner, paginated. |
| `ResolveQuery` *synq.queries.v1.QueriesService* `POST /api/queries/v1/resolve` | Evaluate a selection and return the matched entity ids, paginated. Pass a |
| `TranslateResolverQl` *synq.queries.v1.QueriesService* `POST /api/queries/v1/translate-resolver-ql` | Compile a ResolverQL expression into a structured public `Query`. Unlike |
| `BatchGet` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/batch-get` | Fetch multiple saved views by id. Ids the caller cannot see, or that do not |
| `List` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/list` | List the saved views the calling user can see. By default returns every |
| `SetPin` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/set-pin` | Pin or unpin a saved view to the calling user's main screen. Pinning is a |
| `GetByEmail` *synq.users.v1.UsersService* | |
| `GetUserIdentities` *synq.users.v1.UsersService* | Returns all canonical identity strings for a user. |
| `ListUsers` *synq.users.v1.UsersService* | |
## MCP Write Access
`SCOPE_MCP_WRITE`
Use any write MCP (Model Context Protocol) tool, including tools added in the future.
| Method | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `BatchCreateTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `POST /api/datachecks/testsuggestions/v1` | |
| `Delete` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/delete` | Delete a data product. Idempotent — deleting an already-deleted or unknown |
| `Upsert` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2` | Create or update a data product. The id is supplied by the caller (a UUID); |
| `Delete` *synq.domains.v2.DomainsService* `POST /api/domains/v2/delete` | Delete a domain. Idempotent — deleting an already-deleted or unknown domain |
| `Upsert` *synq.domains.v2.DomainsService* `POST /api/domains/v2` | Create or update a domain. The id is supplied by the caller (a UUID); |
| `CreateIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1` | |
| `PostComment` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/comment` | Post a comment on an incident. |
| `PostComment` *synq.issues.v2.IssuesService* `POST /api/issues/v2/{issue_id}/comment` | Post a comment on an issue. |
| `DeleteDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `DELETE /api/monitors/automated/v1/deployment-rule/{id}` | |
| `DeployDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/deployed` | |
| `DeleteOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1/delete` | Delete an owner and all of its ownerships. Idempotent — deleting an |
| `DeleteOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/delete` | Delete an ownership by id. Idempotent — deleting an already-deleted or |
| `UpsertOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1` | Create or update an owner. The id is supplied by the caller (a UUID); |
| `UpsertOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/{owner_id}/ownerships` | Create or update an ownership under an owner. The ownership id is supplied |
| `Delete` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/delete` | Delete a saved view. Idempotent — deleting an already-deleted or unknown |
| `Upsert` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1` | Create or update a saved view. |
## Read Reconciliation Audits and Settings
`SCOPE_RECON_READ`
View reconciliation suites, settings, and audit results.
| Method | Description |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `GetAuditLog` *synq.agent.recon.v1.AuditLogService* | GetAuditLog returns a single audit log by invocation ID. |
| `ListAuditLogs` *synq.agent.recon.v1.AuditLogService* | ListAuditLogs returns audit logs ordered from newest to oldest, optionally filtered by suite and tim... |
| `BatchReconciliationRunState` *synq.agent.recon.v1.RunStateService* | BatchReconciliationRunState returns the latest concluded run and any ongoing |
| `ListReconciliationRunState` *synq.agent.recon.v1.RunStateService* | ListReconciliationRunState returns runs filtered by status and/or suite\_id. |
| `GetSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | Get the latest version of a suite config by suite\_id. |
| `GetSuiteConfigVersion` *synq.agent.recon.v1.SuiteConfigService* | Get a specific historical version of a suite config. |
| `ListSuiteConfigVersions` *synq.agent.recon.v1.SuiteConfigService* | Get version history for a suite config. |
| `ListSuiteConfigs` *synq.agent.recon.v1.SuiteConfigService* | List latest suite configs with filtering and pagination. |
| `GetSuiteDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | Fetch a deployment by suite\_id or deployment\_id. |
| `ListSuiteDeploymentHistory` *synq.agent.recon.v1.SuiteDeploymentService* | List the append-only history of a deployment (every promote, |
| `ListSuiteDeployments` *synq.agent.recon.v1.SuiteDeploymentService* | List deployments for the caller's workspace. Filters support answering |
## Edit Reconciliation Settings
`SCOPE_RECON_EDIT`
Create and update reconciliation suites and their settings.
| Method | Description |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `IngestAuditLog` *synq.agent.recon.v1.AuditLogService* | IngestAuditLog stores a reconciliation run audit log. |
| `CancelReconciliationRun` *synq.agent.recon.v1.RunStateService* | CancelReconciliationRun marks a SCHEDULED or IN\_PROGRESS run as |
| `DeleteSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | Delete a managed suite config (soft delete — inserts a deleted version). |
| `SubmitAdhocSuite` *synq.agent.recon.v1.SuiteConfigService* | Submit an ad-hoc suite for one-off execution. |
| `UpsertSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | Upsert a managed suite config. Creates if new, updates with new version if exists. |
## Promote Reconciliation Suites to run on Schedule or API
`SCOPE_RECON_PROMOTE`
Promote reconciliation suites so they run on a schedule or via the API.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `PauseDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | Pause a deployment. Scheduled and API-triggered runs are suppressed until |
| `PromoteSuite` *synq.agent.recon.v1.SuiteDeploymentService* | Promote a suite config into production. Freezes a snapshot of the config |
| `ResumeDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | Resume a paused deployment. |
| `TriggerDeployment` *synq.agent.recon.v1.SuiteDeploymentService* `POST /api/recon/v1/deployments/trigger` | Trigger an on-demand execution of a promoted deployment. Enqueues a run |
| `UnpromoteSuite` *synq.agent.recon.v1.SuiteDeploymentService* | Unpromote a deployment. Marks it inactive; scheduler and API triggers |
| `UpdateDeploymentAnnotations` *synq.agent.recon.v1.SuiteDeploymentService* | Replace the deployment-level annotation overlay on an existing |
| `UpdateDeploymentCaseImpacts` *synq.agent.recon.v1.SuiteDeploymentService* | Patch the per-case ReconciliationFailureImpact map on an existing deployment |
| `UpdateDeploymentMappings` *synq.agent.recon.v1.SuiteDeploymentService* | Rewire connection → integration mappings on an existing deployment |
| `UpdateDeploymentSchedule` *synq.agent.recon.v1.SuiteDeploymentService* | Change schedule and/or triggerable\_by\_api on an existing deployment |
## Edit Check Categorisation Rules
`SCOPE_POLICIES_EDIT`
Create and update rules that categorise data quality checks.
| Method | Description |
| ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `DeleteCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `POST /api/entities/checks/v1/categories:delete` | DeleteCheckCategories clears the explicit category (both dimensions) |
| `ListCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `GET /api/entities/checks/v1/categories` | ListCheckCategories returns every explicit check category in the |
| `UpsertCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `POST /api/entities/checks/v1/categories:upsert` | UpsertCheckCategories sets (or replaces) the explicit category for |
## Read Check Categorisation Rules and Status
`SCOPE_POLICIES_READ`
View check categorisation rules and their status.
| Method | Description |
| -------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| `ListCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `GET /api/entities/checks/v1/categories` | ListCheckCategories returns every explicit check category in the |
## Read Saved Views
`SCOPE_SAVED_VIEW_READ`
View saved views the caller has access to.
| Method | Description |
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- |
| `BatchGet` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/batch-get` | Fetch multiple saved views by id. Ids the caller cannot see, or that do not |
| `List` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/list` | List the saved views the calling user can see. By default returns every |
| `SetPin` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/set-pin` | Pin or unpin a saved view to the calling user's main screen. Pinning is a |
## Create and Edit Saved Views
`SCOPE_SAVED_VIEW_EDIT`
Create, update, and delete the caller's own saved views.
| Method | Description |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `Delete` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/delete` | Delete a saved view. Idempotent — deleting an already-deleted or unknown |
| `Upsert` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1` | Create or update a saved view. |
## Manage All Saved Views in the Workspace
`SCOPE_SAVED_VIEW_ADMIN`
Manage all saved views in the workspace, including those owned by other users.
| Method | Description |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `Delete` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/delete` | Delete a saved view. Idempotent — deleting an already-deleted or unknown |
| `Upsert` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1` | Create or update a saved view. |
## Read Folders
`SCOPE_FOLDERS_READ`
Browse the folder hierarchy and list the entities it contains.
| Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `Browse` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/browse` `GET /api/entities/folders/v1/browse` | Browse the hierarchy one level at a time. With no `parent`, returns the |
| `GetFolderOf` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/folder-of` `GET /api/entities/folders/v1/folder-of` | Given entity ids, return the folder breadcrumb(s) each entity lives in — |
| `ListMembers` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/members` `GET /api/entities/folders/v1/members` | List the entity ids contained in a folder, paginated. Direct members only by |
## Edit Folders
`SCOPE_FOLDERS_EDIT`
Create, update, and delete folders and their placements.
*No public gRPC/REST methods require this scope directly (e.g. MCP tools or future methods).*
## Endpoint reference
Every public API method a customer token can call, and the scopes that satisfy it. A token needs any one of the listed scopes.
| Method | Scopes |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GenerateConnectionsYaml` *synq.agent.dwh.v1.ConnectionsService* | `SCOPE_MCP_READ` `SCOPE_EXTENSIONS_MANAGE` `SCOPE_ENTITY_READ` |
| `ListConnections` *synq.agent.dwh.v1.ConnectionsService* | `SCOPE_MCP_READ` `SCOPE_EXTENSIONS_MANAGE` `SCOPE_ENTITY_READ` |
| `GetAuditLog` *synq.agent.recon.v1.AuditLogService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `IngestAuditLog` *synq.agent.recon.v1.AuditLogService* | `SCOPE_RECON_EDIT` |
| `ListAuditLogs` *synq.agent.recon.v1.AuditLogService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `BatchReconciliationRunState` *synq.agent.recon.v1.RunStateService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `CancelReconciliationRun` *synq.agent.recon.v1.RunStateService* | `SCOPE_RECON_EDIT` |
| `ListReconciliationRunState` *synq.agent.recon.v1.RunStateService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `DeleteSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_EDIT` |
| `GetSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `GetSuiteConfigVersion` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `ListSuiteConfigVersions` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `ListSuiteConfigs` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `SubmitAdhocSuite` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_EDIT` |
| `UpsertSuiteConfig` *synq.agent.recon.v1.SuiteConfigService* | `SCOPE_RECON_EDIT` |
| `GetSuiteDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `ListSuiteDeploymentHistory` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `ListSuiteDeployments` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_READ` `SCOPE_MCP_READ` |
| `PauseDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `PromoteSuite` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `ResumeDeployment` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `TriggerDeployment` *synq.agent.recon.v1.SuiteDeploymentService* `POST /api/recon/v1/deployments/trigger` | `SCOPE_RECON_PROMOTE` |
| `UnpromoteSuite` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `UpdateDeploymentAnnotations` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `UpdateDeploymentCaseImpacts` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `UpdateDeploymentMappings` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `UpdateDeploymentSchedule` *synq.agent.recon.v1.SuiteDeploymentService* | `SCOPE_RECON_PROMOTE` |
| `ParseYaml` *synq.agent.recon.v1.YamlService* `POST /api/agent/recon/v1/yaml/parse` | — |
| `RenderYaml` *synq.agent.recon.v1.YamlService* `POST /api/agent/recon/v1/yaml/render` | — |
| `SubmitFeatureRequest` *synq.agent.sre.v1.FeatureRequestService* `POST /api/feature-request/v1/submit` | `SCOPE_MCP_READ` `SCOPE_ENTITY_READ` `SCOPE_ISSUES_READ` `SCOPE_INCIDENTS_READ` `SCOPE_LINEAGE_READ` `SCOPE_MONITORS_READ` `SCOPE_EXECUTION_READ` `SCOPE_CODE_READ` `SCOPE_DATACHECKS_SQLTESTS_READ` `SCOPE_DATACHECKS_TESTSUGGESTIONS_READ` |
| `AcceptPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | `SCOPE_INTEGRATION_EDIT` |
| `DismissPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | `SCOPE_INTEGRATION_EDIT` |
| `GetConfig` *synq.agent.sre.v1.SreAgentService* | `SCOPE_INTEGRATION_READ` `SCOPE_MCP_READ` |
| `ListPromptSuggestions` *synq.agent.sre.v1.SreAgentService* | `SCOPE_INTEGRATION_READ` `SCOPE_MCP_READ` |
| `RecordPromptSuggestion` *synq.agent.sre.v1.SreAgentService* | `SCOPE_INTEGRATION_EDIT` |
| `BatchSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_READ` `SCOPE_MCP_READ` |
| `GetActiveSuggestionStatesFor` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_READ` `SCOPE_MCP_READ` |
| `ListSuggestionStates` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_READ` `SCOPE_MCP_READ` |
| `MarkAsCancelled` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `MarkAsCompleted` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `MarkAsFailed` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `MarkAsRunning` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `SuggestFor` *synq.agent.sre.v1.TestsSuggestionStateService* | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `BatchLatestConclusions` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/conclusions` | `SCOPE_MCP_READ` |
| `BatchTriageState` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/states` | `SCOPE_MCP_READ` |
| `ListTriageState` *synq.agent.sre.v1.TriageService* `GET /api/triage/v1/statuses` | `SCOPE_MCP_READ` |
| `BatchGet` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/get` | `SCOPE_ALERTS_READ` |
| `Create` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1` | `SCOPE_ALERTS_EDIT` |
| `Delete` *synq.alerts.services.v1.AlertsService* `DELETE /api/alerts/v1` | `SCOPE_ALERTS_EDIT` |
| `List` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/list` | `SCOPE_ALERTS_READ` |
| `ToggleEnabled` *synq.alerts.services.v1.AlertsService* `POST /api/alerts/v1/toggle` | `SCOPE_ALERTS_EDIT` |
| `Update` *synq.alerts.services.v1.AlertsService* `PUT /api/alerts/v1` | `SCOPE_ALERTS_EDIT` |
| `Iam` *synq.auth.iam.v1.IamService* `GET /api/iam/v1` | — |
| `BatchDeleteSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `DELETE /api/datachecks/sqltests/v1` | `SCOPE_DATACHECKS_SQLTESTS_EDIT` |
| `BatchGetSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `POST /api/datachecks/sqltests/v1/by-id` | `SCOPE_DATACHECKS_SQLTESTS_READ` `SCOPE_MCP_READ` |
| `BatchUpsertSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `POST /api/datachecks/sqltests/v1` | `SCOPE_DATACHECKS_SQLTESTS_EDIT` |
| `GetSqlTestAudit` *synq.datachecks.sqltests.v1.SqlTestsService* | `SCOPE_DATACHECKS_SQLTESTS_AUDIT_READ` |
| `ListSqlTests` *synq.datachecks.sqltests.v1.SqlTestsService* `GET /api/datachecks/sqltests/v1` | `SCOPE_DATACHECKS_SQLTESTS_READ` `SCOPE_MCP_READ` |
| `BatchAcceptTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `PATCH /api/datachecks/testsuggestions/v1/accepted` | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `BatchCreateTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `POST /api/datachecks/testsuggestions/v1` | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` `SCOPE_MCP_WRITE` |
| `BatchGetTestSuggestionsForEntities` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `GET /api/datachecks/testsuggestions/v1` | `SCOPE_DATACHECKS_TESTSUGGESTIONS_READ` `SCOPE_MCP_READ` |
| `BatchRejectTestSuggestions` *synq.datachecks.testsuggestions.v1.TestSuggestionsService* `PATCH /api/datachecks/testsuggestions/v1/rejected` | `SCOPE_DATACHECKS_TESTSUGGESTIONS_EDIT` |
| `TriggerDatachecks` *synq.datachecks.v1.TriggerService* `POST /api/datachecks/scheduler/v1/trigger` | `SCOPE_DATACHECKS_TRIGGER` |
| `Delete` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/delete` | `SCOPE_DATAPRODUCT_EDIT` |
| `Get` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/get` | `SCOPE_DATAPRODUCT_READ` `SCOPE_MCP_READ` |
| `List` *synq.dataproducts.v1.DataproductsService* `GET /api/dataproducts/v1` | `SCOPE_DATAPRODUCT_READ` `SCOPE_MCP_READ` |
| `RemoveDefinitionPart` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition/part/delete` | `SCOPE_DATAPRODUCT_EDIT` |
| `SetDefinition` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition` | `SCOPE_DATAPRODUCT_EDIT` |
| `Upsert` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1` | `SCOPE_DATAPRODUCT_EDIT` |
| `UpsertDefinitionPart` *synq.dataproducts.v1.DataproductsService* `POST /api/dataproducts/v1/definition/part` | `SCOPE_DATAPRODUCT_EDIT` |
| `BatchGet` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/batch-get` | `SCOPE_DATAPRODUCT_READ` `SCOPE_MCP_READ` |
| `Delete` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/delete` | `SCOPE_DATAPRODUCT_EDIT` `SCOPE_MCP_WRITE` |
| `List` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2` | `SCOPE_DATAPRODUCT_READ` `SCOPE_MCP_READ` |
| `ListMembers` *synq.dataproducts.v2.DataproductsService* `GET /api/dataproducts/v2/{id}/members` | `SCOPE_DATAPRODUCT_READ` `SCOPE_MCP_READ` |
| `RemoveDefinitionPart` *synq.dataproducts.v2.DataproductsService* `DELETE /api/dataproducts/v2/{id}/definition/parts/{part_id}` | `SCOPE_DATAPRODUCT_EDIT` |
| `SetDefinition` *synq.dataproducts.v2.DataproductsService* `PUT /api/dataproducts/v2/{id}/definition` | `SCOPE_DATAPRODUCT_EDIT` |
| `Upsert` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2` | `SCOPE_DATAPRODUCT_EDIT` `SCOPE_MCP_WRITE` |
| `UpsertDefinitionPart` *synq.dataproducts.v2.DataproductsService* `POST /api/dataproducts/v2/{id}/definition/parts` | `SCOPE_DATAPRODUCT_EDIT` |
| `AddDomainMembers` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/members` | `SCOPE_USER_ASSIGN` |
| `ListDomainMembers` *synq.domains.members.v1.DomainMembersService* `GET /api/domains/members/v1/{domain_id}/members` | `SCOPE_USER_READ` |
| `ListUserDomains` *synq.domains.members.v1.DomainMembersService* `GET /api/domains/members/v1/users/{user_id}/domains` | `SCOPE_USER_READ` |
| `RemoveDomainMembers` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/members/remove` | `SCOPE_USER_ASSIGN` |
| `SetDefaultUserDomain` *synq.domains.members.v1.DomainMembersService* `POST /api/domains/members/v1/{domain_id}/default-for-user` | `SCOPE_USER_READ` |
| `BatchGet` *synq.domains.v1.DomainsService* `POST /api/domains/v1/batch-get` | `SCOPE_DOMAIN_READ` |
| `Delete` *synq.domains.v1.DomainsService* `POST /api/domains/v1/delete` | `SCOPE_DOMAIN_EDIT` |
| `FetchDomainWithSubDomains` *synq.domains.v1.DomainsService* `GET /api/domains/v1/{domain_id}/sub-domains` | `SCOPE_DOMAIN_READ` |
| `List` *synq.domains.v1.DomainsService* `GET /api/domains/v1` | `SCOPE_DOMAIN_READ` |
| `RemoveDefinitionPart` *synq.domains.v1.DomainsService* `DELETE /api/domains/v1/{domain_id}/definition/parts/{part_id}` | `SCOPE_DOMAIN_EDIT` |
| `SetDefinition` *synq.domains.v1.DomainsService* `PUT /api/domains/v1/{domain_id}/definition` | `SCOPE_DOMAIN_EDIT` |
| `Upsert` *synq.domains.v1.DomainsService* `POST /api/domains/v1` | `SCOPE_DOMAIN_EDIT` |
| `UpsertDefinitionPart` *synq.domains.v1.DomainsService* `POST /api/domains/v1/{domain_id}/definition/parts` | `SCOPE_DOMAIN_EDIT` |
| `BatchGet` *synq.domains.v2.DomainsService* `POST /api/domains/v2/batch-get` | `SCOPE_DOMAIN_READ` `SCOPE_MCP_READ` |
| `Delete` *synq.domains.v2.DomainsService* `POST /api/domains/v2/delete` | `SCOPE_DOMAIN_EDIT` `SCOPE_MCP_WRITE` |
| `FetchDomainWithSubDomains` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/sub-domains` | `SCOPE_DOMAIN_READ` `SCOPE_MCP_READ` |
| `List` *synq.domains.v2.DomainsService* `GET /api/domains/v2` | `SCOPE_DOMAIN_READ` `SCOPE_MCP_READ` |
| `ListMembers` *synq.domains.v2.DomainsService* `GET /api/domains/v2/{id}/members` | `SCOPE_DOMAIN_READ` `SCOPE_MCP_READ` |
| `RemoveDefinitionPart` *synq.domains.v2.DomainsService* `DELETE /api/domains/v2/{id}/definition/parts/{part_id}` | `SCOPE_DOMAIN_EDIT` |
| `SetDefinition` *synq.domains.v2.DomainsService* `PUT /api/domains/v2/{id}/definition` | `SCOPE_DOMAIN_EDIT` |
| `Upsert` *synq.domains.v2.DomainsService* `POST /api/domains/v2` | `SCOPE_DOMAIN_EDIT` `SCOPE_MCP_WRITE` |
| `UpsertDefinitionPart` *synq.domains.v2.DomainsService* `POST /api/domains/v2/{id}/definition/parts` | `SCOPE_DOMAIN_EDIT` |
| `ListAnnotations` *synq.entities.annotations.v1.AnnotationsService* `GET /api/entities/annotations/v1` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchChange` *synq.entities.changes.v1.ChangesService* `POST /api/changes/v1/by-id` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `List` *synq.entities.changes.v1.ChangesService* `GET /api/changes/v1` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `DeleteCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `POST /api/entities/checks/v1/categories:delete` | `SCOPE_POLICIES_EDIT` |
| `ListCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `GET /api/entities/checks/v1/categories` | `SCOPE_POLICIES_READ` `SCOPE_POLICIES_EDIT` |
| `UpsertCheckCategories` *synq.entities.checks.v1.ChecksCategoriesService* `POST /api/entities/checks/v1/categories:upsert` | `SCOPE_POLICIES_EDIT` |
| `GetCoverage` *synq.entities.checks.v1.ChecksCoverageService* | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `ListCode` *synq.entities.code.v1.CodeService* `GET /api/code/v1` | `SCOPE_CODE_READ` `SCOPE_MCP_READ` |
| `GetTableConstraints` *synq.entities.constraints.v1.TableConstraintsService* `GET /api/constraints/v1/table-constraints` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchDatabaseCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-id` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchIdsByCoordinates` *synq.entities.coordinates.v1.DatabaseCoordinatesService* `POST /api/coordinates/v1/database/by-fqn` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `DeleteCheckRelationships` *synq.entities.custom.v1.ChecksRelationshipsService* `DELETE /api/entities/custom/v1/check-relationships` | `SCOPE_ENTITY_EDIT` |
| `UpsertCheckRelationships` *synq.entities.custom.v1.ChecksRelationshipsService* `POST /api/entities/custom/v1/check-relationships` | `SCOPE_ENTITY_EDIT` |
| `DeleteEntity` *synq.entities.custom.v1.EntitiesService* `DELETE /api/entities/custom/v1/entities` | `SCOPE_ENTITY_EDIT` |
| `ListEntities` *synq.entities.custom.v1.EntitiesService* `GET /api/entities/custom/v1/entities` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `UpsertEntity` *synq.entities.custom.v1.EntitiesService* `POST /api/entities/custom/v1/entities` | `SCOPE_ENTITY_EDIT` |
| `UpsertExecution` *synq.entities.custom.v1.EntityExecutionsService* `POST /api/entities/custom/executions/v1` | `SCOPE_EXECUTION_EDIT` |
| `UpsertLogEntry` *synq.entities.custom.v1.EntityExecutionsService* `POST /api/entities/custom/executions/v1/log-entry` | `SCOPE_EXECUTION_EDIT` `SCOPE_EXECUTION_LOG_EDIT` |
| `DeleteEntityFeature` *synq.entities.custom.v1.FeaturesService* `DELETE /api/entities/custom/v1/features` | `SCOPE_ENTITY_EDIT` |
| `ListEntityFeatures` *synq.entities.custom.v1.FeaturesService* `POST /api/entities/custom/v1/features/list` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `UpsertEntityFeature` *synq.entities.custom.v1.FeaturesService* `POST /api/entities/custom/v1/features` | `SCOPE_ENTITY_EDIT` |
| `DeleteEntitiesGroup` *synq.entities.custom.v1.GroupsService* `DELETE /api/entities/custom/v1/groups` | `SCOPE_ENTITY_EDIT` |
| `ListEntityGroups` *synq.entities.custom.v1.GroupsService* `POST /api/entities/custom/v1/groups/list` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `UpsertEntitiesGroup` *synq.entities.custom.v1.GroupsService* `POST /api/entities/custom/v1/groups` | `SCOPE_ENTITY_EDIT` |
| `DeleteRelationships` *synq.entities.custom.v1.RelationshipsService* `DELETE /api/entities/custom/v1/relationships` | `SCOPE_LINEAGE_EDIT` |
| `ListRelationships` *synq.entities.custom.v1.RelationshipsService* `POST /api/entities/custom/v1/relationships/list` | `SCOPE_LINEAGE_READ` `SCOPE_MCP_READ` |
| `UpsertRelationships` *synq.entities.custom.v1.RelationshipsService* `POST /api/entities/custom/v1/relationships` | `SCOPE_LINEAGE_EDIT` |
| `DeleteType` *synq.entities.custom.v1.TypesService* `DELETE /api/entities/custom/v1/types` | `SCOPE_ENTITY_TYPE_EDIT` |
| `ListTypes` *synq.entities.custom.v1.TypesService* `POST /api/entities/custom/v1/types/list` | `SCOPE_ENTITY_READ` `SCOPE_ENTITY_TYPE_READ` |
| `UpsertType` *synq.entities.custom.v1.TypesService* `POST /api/entities/custom/v1/types` | `SCOPE_ENTITY_TYPE_EDIT` |
| `BatchGetEntities` *synq.entities.entities.v1.EntitiesService* `POST /api/entities/v1/by-id` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetEntity` *synq.entities.entities.v1.EntitiesService* | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `ListEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `SearchEntities` *synq.entities.entities.v1.EntitiesService* `GET /api/entities/v1/search` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `UpsertExecution` *synq.entities.executions.v1.EntityExecutionsService* `POST /api/executions/v1` | `SCOPE_EXECUTION_EDIT` |
| `UpsertLogEntry` *synq.entities.executions.v1.EntityExecutionsService* `POST /api/executions/v1/log-entry` | `SCOPE_EXECUTION_EDIT` `SCOPE_EXECUTION_LOG_EDIT` |
| `BatchGetExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/by-id` | `SCOPE_EXECUTION_READ` `SCOPE_MCP_READ` |
| `GetExecutionsSummary` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/summary` | `SCOPE_EXECUTION_READ` `SCOPE_MCP_READ` |
| `GetLatestExecutions` *synq.entities.executions.v2.EntityExecutionsService* `POST /api/executions/v2/latest` | `SCOPE_EXECUTION_READ` `SCOPE_MCP_READ` |
| `ListExecutions` *synq.entities.executions.v2.EntityExecutionsService* `GET /api/executions/v2/list` | `SCOPE_EXECUTION_READ` `SCOPE_MCP_READ` |
| `Browse` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/browse` `GET /api/entities/folders/v1/browse` | `SCOPE_FOLDERS_READ` `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetFolderOf` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/folder-of` `GET /api/entities/folders/v1/folder-of` | `SCOPE_FOLDERS_READ` `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `ListMembers` *synq.entities.folders.v1.FoldersService* `POST /api/entities/folders/v1/members` `GET /api/entities/folders/v1/members` | `SCOPE_FOLDERS_READ` `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetImpact` *synq.entities.impact.v1.ImpactService* `POST /api/impact/v1` | `SCOPE_ENTITY_READ` `SCOPE_LINEAGE_READ` `SCOPE_MCP_READ` |
| `GetLineage` *synq.entities.lineage.v1.LineageService* `POST /api/lineage/v1` | `SCOPE_LINEAGE_READ` `SCOPE_MCP_READ` |
| `BatchOrchestration` *synq.entities.orchestration.v1.OrchestrationService* `GET /api/orchestration/v1` | `SCOPE_LINEAGE_READ` `SCOPE_MCP_READ` |
| `BatchResolveIdentifiers` *synq.entities.resolve.v1.IdentifierResolveService* `POST /api/resolve/v1/by-id` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchSchemaMismatches` *synq.entities.schemas.v1.SchemaMismatchesService* `POST /api/schema-mismatches/v1` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetSchema` *synq.entities.schemas.v1.SchemasService* `GET /api/schema/v1` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchSqlDetails` *synq.entities.sql\_insights.v1.SqlInsightsService* `POST /api/sql-insights/v1/details:batch` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `ListSqlConstructs` *synq.entities.sql\_insights.v1.SqlInsightsService* `GET /api/sql-insights/v1/constructs` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchGetIncidents` *synq.entities.status.v1.EntityIncidentsService* `POST /api/status/v1/incidents/by-id` | `SCOPE_STATUS_READ` `SCOPE_MCP_READ` |
| `GetIncidents` *synq.entities.status.v1.EntityIncidentsService* | `SCOPE_STATUS_READ` `SCOPE_MCP_READ` |
| `BatchGetIssuesStatus` *synq.entities.status.v1.EntityIssuesService* `POST /api/status/v1/issues/by-id` | `SCOPE_STATUS_READ` `SCOPE_MCP_READ` |
| `GetIssuesStatus` *synq.entities.status.v1.EntityIssuesService* | `SCOPE_STATUS_READ` |
| `Activate` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `PATCH /api/extensions/atlan/integrations/v1` | `SCOPE_EXTENSIONS_MANAGE` |
| `Get` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `GET /api/extensions/atlan/integrations/v1` | `SCOPE_INTEGRATION_READ` |
| `Ping` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `POST /api/extensions/atlan/integrations/v1/ping` | `SCOPE_EXTENSIONS_MANAGE` |
| `Remove` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `DELETE /api/extensions/atlan/integrations/v1` | `SCOPE_EXTENSIONS_MANAGE` |
| `Upsert` *synq.extensions.atlan.integrations.v1.AtlanIntegrationService* `POST /api/extensions/atlan/integrations/v1` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetAtlanConnections` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/connections` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetAtlanDataProducts` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/data-products` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetAtlanDomains` *synq.extensions.atlan.provider.v1.AtlanProviderService* `GET /api/extensions/atlan/provider/v1/domains` | `SCOPE_EXTENSIONS_MANAGE` |
| `FetchRuns` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/runs` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/connection-mappings` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetDomainMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/domain-mappings` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetMappingToggles` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/mappings/toggle` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetProductMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `GET /api/extensions/atlan/workflows/v1/product-mappings` | `SCOPE_EXTENSIONS_MANAGE` |
| `RemoveConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `DELETE /api/extensions/atlan/workflows/v1/connection-mappings` | `SCOPE_EXTENSIONS_MANAGE` |
| `SetConnectionMappings` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/connection-mappings` | `SCOPE_EXTENSIONS_MANAGE` |
| `SetMappingToggles` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/mappings/toggle` | `SCOPE_EXTENSIONS_MANAGE` |
| `Synchronize` *synq.extensions.atlan.workflows.v1.AtlanWorkflowService* `POST /api/extensions/atlan/workflows/v1/synchronize` | `SCOPE_EXTENSIONS_MANAGE` |
| `GetDiffByChangeId` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/change/{change_id}` | `SCOPE_CODE_READ` `SCOPE_MCP_READ` |
| `GetDiffByCommit` *synq.git.commits.v1.CommitsService* `GET /api/git/v1/commit/{commit_sha}` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `AddIssuesToIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/issues` | `SCOPE_INCIDENTS_EDIT` |
| `AssignIncidentOwner` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/assign-owner` | `SCOPE_INCIDENTS_EDIT` |
| `BatchGetIncidents` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/by-id` | `SCOPE_INCIDENTS_READ` `SCOPE_MCP_READ` |
| `CancelIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/cancel` | `SCOPE_INCIDENTS_EDIT` |
| `CloseIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/close` | `SCOPE_INCIDENTS_EDIT` |
| `CreateIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1` | `SCOPE_INCIDENTS_EDIT` `SCOPE_MCP_WRITE` |
| `ListIncidents` *synq.incidents.v1.IncidentsService* `GET /api/incidents/v1` | `SCOPE_INCIDENTS_READ` `SCOPE_MCP_READ` |
| `MergeIncidents` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/merge` | `SCOPE_INCIDENTS_EDIT` |
| `PostComment` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/comment` | `SCOPE_INCIDENTS_EDIT` `SCOPE_MCP_WRITE` |
| `RemoveIssuesFromIncident` *synq.incidents.v1.IncidentsService* `DELETE /api/incidents/v1/{incident_id}/issues` | `SCOPE_INCIDENTS_EDIT` |
| `RenameIncident` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/rename` | `SCOPE_INCIDENTS_EDIT` |
| `SplitIncident` *synq.incidents.v1.IncidentsService* `POST /api/incidents/v1/{incident_id}/split` | `SCOPE_INCIDENTS_EDIT` |
| `UpdateIncidentState` *synq.incidents.v1.IncidentsService* `PATCH /api/incidents/v1/{incident_id}/state` | `SCOPE_INCIDENTS_EDIT` |
| `BatchGetIntegrations` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/by-id` | `SCOPE_INTEGRATION_READ` `SCOPE_INTEGRATION_EDIT` |
| `CreateIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1` | `SCOPE_INTEGRATION_EDIT` |
| `DeleteIntegration` *synq.integrations.v1.IntegrationsService* `DELETE /api/integrations/v1/{integration_id}` | `SCOPE_INTEGRATION_EDIT` |
| `DisableIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/disable` | `SCOPE_INTEGRATION_EDIT` |
| `EnableIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/enable` | `SCOPE_INTEGRATION_EDIT` |
| `GetIntegration` *synq.integrations.v1.IntegrationsService* | `SCOPE_INTEGRATION_READ` `SCOPE_INTEGRATION_EDIT` |
| `GetIntegrationHealth` *synq.integrations.v1.IntegrationsService* | `SCOPE_INTEGRATION_READ` `SCOPE_INTEGRATION_EDIT` |
| `ListIntegrations` *synq.integrations.v1.IntegrationsService* `GET /api/integrations/v1` | `SCOPE_INTEGRATION_READ` `SCOPE_INTEGRATION_EDIT` |
| `RefreshIntegration` *synq.integrations.v1.IntegrationsService* `POST /api/integrations/v1/{integration_id}/refresh` | `SCOPE_INTEGRATION_EDIT` |
| `UpdateIntegration` *synq.integrations.v1.IntegrationsService* `PUT /api/integrations/v1/{integration_id}` | `SCOPE_INTEGRATION_EDIT` |
| `BatchGetIssues` *synq.issues.issues.v1.IssuesService* `POST /api/issues/v1/by-id` | `SCOPE_ISSUES_READ` `SCOPE_MCP_READ` |
| `ListIssues` *synq.issues.issues.v1.IssuesService* `GET /api/issues/v1` | `SCOPE_ISSUES_READ` `SCOPE_MCP_READ` |
| `MarkExpected` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-expected` | `SCOPE_ISSUES_EDIT` |
| `MarkFixed` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-fixed` | `SCOPE_ISSUES_EDIT` |
| `MarkInvestigating` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-investigating` | `SCOPE_ISSUES_EDIT` |
| `MarkNoActionNeeded` *synq.issues.issues.v1.IssuesService* `PATCH /api/issues/v1/{issue_id}/mark-no-action-needed` | `SCOPE_ISSUES_EDIT` |
| `PostComment` *synq.issues.issues.v1.IssuesService* `POST /api/issues/v1/{issue_id}/comment` | `SCOPE_ISSUES_EDIT` |
| `BatchGetIssues` *synq.issues.v2.IssuesService* `POST /api/issues/v2/by-id` | `SCOPE_ISSUES_READ` `SCOPE_MCP_READ` |
| `ClearStatus` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/clear-status` | `SCOPE_ISSUES_EDIT` |
| `ListIssues` *synq.issues.v2.IssuesService* `GET /api/issues/v2` | `SCOPE_ISSUES_READ` `SCOPE_MCP_READ` |
| `MarkExpected` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-expected` | `SCOPE_ISSUES_EDIT` |
| `MarkFixed` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-fixed` | `SCOPE_ISSUES_EDIT` |
| `MarkInvestigating` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-investigating` | `SCOPE_ISSUES_EDIT` |
| `MarkNoActionNeeded` *synq.issues.v2.IssuesService* `PATCH /api/issues/v2/{issue_id}/mark-no-action-needed` | `SCOPE_ISSUES_EDIT` |
| `PostComment` *synq.issues.v2.IssuesService* `POST /api/issues/v2/{issue_id}/comment` | `SCOPE_ISSUES_EDIT` `SCOPE_MCP_WRITE` |
| `BatchDeleteDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `DELETE /api/monitors/automated/v1/deployment-rules/batch` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `BatchDeployDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/batch/deployed` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `BatchGetDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules/batch` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `BatchUpdateDeploymentRuleTitle` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `PATCH /api/monitors/automated/v1/deployment-rules` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `BatchUpsertDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/batch` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `DeleteDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `DELETE /api/monitors/automated/v1/deployment-rule/{id}` | `SCOPE_MONITORS_AUTOMATIC_EDIT` `SCOPE_MCP_WRITE` |
| `DeployDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules/deployed` | `SCOPE_MONITORS_AUTOMATIC_EDIT` `SCOPE_MCP_WRITE` |
| `GetDeployDeleteOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule/{id}/deleted` | `SCOPE_MONITORS_AUTOMATIC_EDIT` `SCOPE_MCP_READ` |
| `GetDeployOverview` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rule` | `SCOPE_MONITORS_AUTOMATIC_EDIT` `SCOPE_MCP_READ` |
| `ListDeploymentRules` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules` | `SCOPE_MONITORS_AUTOMATIC_EDIT` `SCOPE_MCP_READ` |
| `ListDeploymentRulesForAsset` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `GET /api/monitors/automated/v1/deployment-rules/{asset_path}` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `UpsertDeploymentRule` *synq.monitors.automated\_monitors.v1.DeploymentRulesService* `POST /api/monitors/automated/v1/deployment-rules` | `SCOPE_MONITORS_AUTOMATIC_EDIT` |
| `BatchCreateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1` | `SCOPE_MONITORS_CUSTOM_EDIT` `SCOPE_MONITORS_CUSTOM_SQL_EDIT` |
| `BatchDeleteMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/delete` | `SCOPE_MONITORS_CUSTOM_EDIT` |
| `BatchUpdateMonitor` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `PUT /api/monitors/custom-monitors/v1` | `SCOPE_MONITORS_CUSTOM_EDIT` `SCOPE_MONITORS_CUSTOM_SQL_EDIT` |
| `BatchUpdateMonitorMode` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/mode` | `SCOPE_MONITORS_CUSTOM_EDIT` |
| `BatchUpdateMonitorSeverity` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/severity` | `SCOPE_MONITORS_CUSTOM_EDIT` |
| `ConfigChangesOverview` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `POST /api/monitors/custom-monitors/v1/config-changes` | `SCOPE_MONITORS_CUSTOM_EDIT` |
| `ListConfigsMonitors` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `GET /api/monitors/custom-monitors/v1/by-config` | `SCOPE_MONITORS_READ` |
| `ListMonitors` *synq.monitors.custom\_monitors.v1.CustomMonitorsService* `GET /api/monitors/custom-monitors/v1` | `SCOPE_MONITORS_READ` |
| `History` *synq.monitors.history.v1.HistoryService* `GET /api/monitors/history/v1/{monitor_path}` | `SCOPE_MONITORS_READ` `SCOPE_MCP_READ` |
| `MonitorInfo` *synq.monitors.info.v1.MonitorInfoService* `GET /api/monitors/info/v1` | `SCOPE_MONITORS_READ` `SCOPE_MCP_READ` |
| `BatchGetLatestEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `POST /api/monitors/predictions/v1/entity-metrics:batchLatest` | `SCOPE_MONITORS_READ` `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetEntityMetrics` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1/entity-metrics` | `SCOPE_MONITORS_READ` `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `GetMonitorPredictions` *synq.monitors.predictions.v1.MonitorPredictionsService* `GET /api/monitors/predictions/v1` | `SCOPE_MONITORS_READ` `SCOPE_MCP_READ` |
| `BatchGetOwners` *synq.owners.v1.OwnersService* `POST /api/owners/v1/batch-get` | `SCOPE_OWNERS_READ` `SCOPE_MCP_READ` |
| `BatchGetOwnerships` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/batch-get` | `SCOPE_OWNERSHIP_READ` `SCOPE_MCP_READ` |
| `DeleteOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1/delete` | `SCOPE_OWNERS_EDIT` `SCOPE_MCP_WRITE` |
| `DeleteOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/ownerships/delete` | `SCOPE_OWNERSHIP_EDIT` `SCOPE_MCP_WRITE` |
| `ListOwners` *synq.owners.v1.OwnersService* `GET /api/owners/v1` | `SCOPE_OWNERS_READ` `SCOPE_MCP_READ` |
| `ListOwnerships` *synq.owners.v1.OwnersService* `GET /api/owners/v1/{owner_id}/ownerships` | `SCOPE_OWNERSHIP_READ` `SCOPE_MCP_READ` |
| `UpsertOwner` *synq.owners.v1.OwnersService* `POST /api/owners/v1` | `SCOPE_OWNERS_EDIT` `SCOPE_MCP_WRITE` |
| `UpsertOwnership` *synq.owners.v1.OwnersService* `POST /api/owners/v1/{owner_id}/ownerships` | `SCOPE_OWNERSHIP_EDIT` `SCOPE_MCP_WRITE` |
| `SetPlatformAuthentication` *synq.platforms.v1.PlatformsService* `POST /api/platforms/v1` | `SCOPE_INTEGRATION_EDIT` |
| `GenerateQuery` *synq.queries.v1.NLQueryService* `POST /api/queries/v1/generate` | `SCOPE_ENTITY_READ` |
| `ResolveQuery` *synq.queries.v1.QueriesService* `POST /api/queries/v1/resolve` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `TranslateResolverQl` *synq.queries.v1.QueriesService* `POST /api/queries/v1/translate-resolver-ql` | `SCOPE_ENTITY_READ` `SCOPE_MCP_READ` |
| `BatchGet` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/batch-get` | `SCOPE_SAVED_VIEW_READ` `SCOPE_MCP_READ` |
| `Delete` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/delete` | `SCOPE_SAVED_VIEW_EDIT` `SCOPE_SAVED_VIEW_ADMIN` `SCOPE_MCP_WRITE` |
| `List` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/list` | `SCOPE_SAVED_VIEW_READ` `SCOPE_MCP_READ` |
| `SetPin` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1/set-pin` | `SCOPE_SAVED_VIEW_READ` `SCOPE_MCP_READ` |
| `Upsert` *synq.savedviews.v1.SavedViewsService* `POST /api/saved-views/v1` | `SCOPE_SAVED_VIEW_EDIT` `SCOPE_SAVED_VIEW_ADMIN` `SCOPE_MCP_WRITE` |
| `PreviewSchedules` *synq.schedule.v1.ScheduleService* `POST /api/schedule/v1/preview` | — |
| `BatchGetUsers` *synq.users.v1.UsersService* | `SCOPE_USER_READ` |
| `DeleteUserAliases` *synq.users.v1.UsersService* | `SCOPE_USER_EDIT` |
| `GetByAlias` *synq.users.v1.UsersService* | `SCOPE_USER_READ` |
| `GetByEmail` *synq.users.v1.UsersService* | `SCOPE_USER_READ` `SCOPE_MCP_READ` |
| `GetUserAliases` *synq.users.v1.UsersService* | `SCOPE_USER_READ` |
| `GetUserIdentities` *synq.users.v1.UsersService* | `SCOPE_USER_READ` `SCOPE_MCP_READ` |
| `ListUsers` *synq.users.v1.UsersService* | `SCOPE_USER_READ` `SCOPE_MCP_READ` |
| `UpsertUserAliases` *synq.users.v1.UsersService* | `SCOPE_USER_EDIT` |
# TriggerDeployment
Source: https://docs.synq.io/api-reference/synqagentreconv1suitedeploymentservice/triggerdeployment
/api-reference/openapi.yaml post /api/recon/v1/deployments/trigger
Trigger an on-demand execution of a promoted deployment. Enqueues a run
using the frozen suite snapshot and connection mappings stored on the
deployment row — execution uses platform integration credentials, not the
caller's. Returns the freshly-allocated `run_id` so callers can poll
RunStateService for status.
Preconditions:
- Deployment must exist and be `active`.
- Deployment must have `triggerable_by_api = true` (FAILED_PRECONDITION
otherwise).
- Deployment must not be paused (FAILED_PRECONDITION when
`paused_until` is set and in the future).
# ParseYaml
Source: https://docs.synq.io/api-reference/synqagentreconv1yamlservice/parseyaml
/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/parse
ParseYaml parses a YAML config string into a ReconciliationSuite proto.
Only the suite configuration fields are extracted (connections are ignored).
# RenderYaml
Source: https://docs.synq.io/api-reference/synqagentreconv1yamlservice/renderyaml
/api-reference/openapi.yaml post /api/agent/recon/v1/yaml/render
RenderYaml renders a ReconciliationSuite proto as a YAML config string.
# SubmitFeatureRequest
Source: https://docs.synq.io/api-reference/synqagentsrev1featurerequestservice/submitfeaturerequest
/api-reference/openapi.yaml post /api/feature-request/v1/submit
SubmitFeatureRequest submits a feature request to the Coalesce Quality product team.
This method should only be called as a last resort when the user's request cannot be
fulfilled by any existing tool. It logs the request for product team review.
# Evaluate
Source: https://docs.synq.io/api-reference/synqagentsrev1llmservice/evaluate
/api-reference/openapi.yaml post /api/sre/llm/v1/evaluate
Evaluates an LLM request with a structured output schema and message history.
The main prompt should be constant as it will be cached for efficiency.
# BatchLatestConclusions
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/batchlatestconclusions
/api-reference/openapi.yaml get /api/triage/v1/conclusions
Retrieves the latest triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
# BatchTriageState
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/batchtriagestate
/api-reference/openapi.yaml get /api/triage/v1/states
Retrieves the triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
# Conclude
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/conclude
/api-reference/openapi.yaml post /api/triage/v1/{session_id}/conclusion
Concludes the triage investigation for one or more issues by providing a structured conclusion
and supporting evidence. This method is used by the LLM agent to finalize its investigation.
# ListTriageState
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/listtriagestate
/api-reference/openapi.yaml get /api/triage/v1/statuses
Retrieves the triage state for one or more issues. This method is used by the LLM agent
to retrieve the current state of the issues it is working on.
# MarkAsInProgress
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/markasinprogress
/api-reference/openapi.yaml patch /api/triage/v1/in-progress
Marks an issue as in progress. This method is used by the LLM agent to indicate that it has started working on an issue.
# MarkFailed
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/markfailed
/api-reference/openapi.yaml patch /api/triage/v1/failed
Marks an issue as failed triaging. This method is used by the LLM agent to indicate that it was unable to triage.
# RecordEvidence
Source: https://docs.synq.io/api-reference/synqagentsrev1triageservice/recordevidence
/api-reference/openapi.yaml post /api/triage/v1/{session_id}/evidence
Records evidence collected during the triage investigation. This method allows the LLM agent
to incrementally add evidence as it discovers information during the investigation process.
# BatchGet
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/batchget
/api-reference/openapi.yaml post /api/alerts/v1/get
Get multiple alert configurations by their identifiers.
# Create
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/create
/api-reference/openapi.yaml post /api/alerts/v1
Create a new alert configuration.
# Delete
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/delete
/api-reference/openapi.yaml delete /api/alerts/v1
Delete an existing alert configuration.
The config can be identified by either ID or FQN.
# List
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/list
/api-reference/openapi.yaml post /api/alerts/v1/list
Retrieves a list of alert configurations based on filters.
# ToggleEnabled
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/toggleenabled
/api-reference/openapi.yaml post /api/alerts/v1/toggle
Enables or disables an existing alert configuration.
The config can be identified by either ID or FQN.
# Update
Source: https://docs.synq.io/api-reference/synqalertsservicesv1alertsservice/update
/api-reference/openapi.yaml put /api/alerts/v1
Update an existing alert configuration.
The config can be identified by either ID or FQN.
# Iam
Source: https://docs.synq.io/api-reference/synqauthiamv1iamservice/iam
/api-reference/openapi.yaml get /api/iam/v1
Iam returns information about caller authentication
# BatchDeleteSqlTests
Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchdeletesqltests
/api-reference/openapi.yaml delete /api/datachecks/sqltests/v1
Delete SqlTests by their IDs.
# BatchGetSqlTests
Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchgetsqltests
/api-reference/openapi.yaml post /api/datachecks/sqltests/v1/by-id
Get SqlTests by their IDs.
# BatchUpsertSqlTests
Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsservice/batchupsertsqltests
/api-reference/openapi.yaml post /api/datachecks/sqltests/v1
Upsert SqlTests based on a unique ID.
# ListSqlTests
Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsservice/listsqltests
/api-reference/openapi.yaml get /api/datachecks/sqltests/v1
List SqlTests for given annotations.
# BatchAcceptTestSuggestions
Source: https://docs.synq.io/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchaccepttestsuggestions
/api-reference/openapi.yaml patch /api/datachecks/testsuggestions/v1/accepted
# BatchCreateTestSuggestions
Source: https://docs.synq.io/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchcreatetestsuggestions
/api-reference/openapi.yaml post /api/datachecks/testsuggestions/v1
# BatchGetTestSuggestionsForEntities
Source: https://docs.synq.io/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchgettestsuggestionsforentities
/api-reference/openapi.yaml get /api/datachecks/testsuggestions/v1
# BatchRejectTestSuggestions
Source: https://docs.synq.io/api-reference/synqdatacheckstestsuggestionsv1testsuggestionsservice/batchrejecttestsuggestions
/api-reference/openapi.yaml patch /api/datachecks/testsuggestions/v1/rejected
# TriggerDatachecks
Source: https://docs.synq.io/api-reference/synqdatachecksv1triggerservice/triggerdatachecks
/api-reference/openapi.yaml post /api/datachecks/scheduler/v1/trigger
TriggerDatachecks executes datachecks for the specified entities.
# Delete
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/delete
/api-reference/openapi.yaml post /api/dataproducts/v1/delete
Delete a dataproduct by its identifier.
Soft deletes by default. Optionally purge the dataproduct to release the identifier.
# Get
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/get
/api-reference/openapi.yaml post /api/dataproducts/v1/get
Get multiple dataproducts by their identifiers.
# List
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/list
/api-reference/openapi.yaml get /api/dataproducts/v1
List all the dataproducts in the current scope.
# RemoveDefinitionPart
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/removedefinitionpart
/api-reference/openapi.yaml post /api/dataproducts/v1/definition/part/delete
Remove definition part from the definition of an existing dataproduct.
# SetDefinition
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/setdefinition
/api-reference/openapi.yaml post /api/dataproducts/v1/definition
Set the definition for an existing dataproduct.
# Upsert
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/upsert
/api-reference/openapi.yaml post /api/dataproducts/v1
Create or update a dataproduct.
# UpsertDefinitionPart
Source: https://docs.synq.io/api-reference/synqdataproductsv1dataproductsservice/upsertdefinitionpart
/api-reference/openapi.yaml post /api/dataproducts/v1/definition/part
Upsert definition part to the definition of an existing dataproduct.
# BatchGet
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/batchget
/api-reference/openapi.yaml post /api/dataproducts/v2/batch-get
Fetch multiple data products by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
# Delete
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/delete
/api-reference/openapi.yaml post /api/dataproducts/v2/delete
Delete a data product. Idempotent — deleting an already-deleted or unknown
product succeeds. Soft-deletes by default; set `purge` to hard-delete and
release the id. Pass `etag` to guard against deleting a concurrently-edited
product.
# List
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/list
/api-reference/openapi.yaml get /api/dataproducts/v2
List the data products in the workspace, paginated. Narrow with `folder`
and `priorities`.
# ListMembers
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/listmembers
/api-reference/openapi.yaml get /api/dataproducts/v2/{id}/members
List the assets that currently belong to a data product, resolved from its
definition and returned as opaque entity ids. Paginated.
# RemoveDefinitionPart
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/removedefinitionpart
/api-reference/openapi.yaml delete /api/dataproducts/v2/{id}/definition/parts/{part_id}
Remove a single definition part by its part id. Idempotent.
# SetDefinition
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/setdefinition
/api-reference/openapi.yaml put /api/dataproducts/v2/{id}/definition
Replace the entire membership definition of a data product.
# Upsert
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/upsert
/api-reference/openapi.yaml post /api/dataproducts/v2
Create or update a data product. The id is supplied by the caller (a UUID);
repeating the same request converges to the same product. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
# UpsertDefinitionPart
Source: https://docs.synq.io/api-reference/synqdataproductsv2dataproductsservice/upsertdefinitionpart
/api-reference/openapi.yaml post /api/dataproducts/v2/{id}/definition/parts
Add or replace a single definition part (matched by its part id).
# AddDomainMembers
Source: https://docs.synq.io/api-reference/synqdomainsmembersv1domainmembersservice/adddomainmembers
/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/members
Add domain members.
# ListDomainMembers
Source: https://docs.synq.io/api-reference/synqdomainsmembersv1domainmembersservice/listdomainmembers
/api-reference/openapi.yaml get /api/domains/members/v1/{domain_id}/members
List domain members.
# ListUserDomains
Source: https://docs.synq.io/api-reference/synqdomainsmembersv1domainmembersservice/listuserdomains
/api-reference/openapi.yaml get /api/domains/members/v1/users/{user_id}/domains
List domains for the given user.
# RemoveDomainMembers
Source: https://docs.synq.io/api-reference/synqdomainsmembersv1domainmembersservice/removedomainmembers
/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/members/remove
Remove domain members.
# SetDefaultUserDomain
Source: https://docs.synq.io/api-reference/synqdomainsmembersv1domainmembersservice/setdefaultuserdomain
/api-reference/openapi.yaml post /api/domains/members/v1/{domain_id}/default-for-user
Set default domain for user.
# BatchGet
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/batchget
/api-reference/openapi.yaml post /api/domains/v1/batch-get
Get multiple domains by their identifiers.
# Delete
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/delete
/api-reference/openapi.yaml post /api/domains/v1/delete
Delete a domain by its identifier.
# FetchDomainWithSubDomains
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/fetchdomainwithsubdomains
/api-reference/openapi.yaml get /api/domains/v1/{domain_id}/sub-domains
Get a domain with its sub-domains
# GetUsage
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/getusage
/api-reference/openapi.yaml get /api/domains/v1/usage
# List
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/list
/api-reference/openapi.yaml get /api/domains/v1
List all the domains in the current workspace.
# RemoveDefinitionPart
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/removedefinitionpart
/api-reference/openapi.yaml delete /api/domains/v1/{domain_id}/definition/parts/{part_id}
Remove definition part from the definition of an existing domain.
# SetDefinition
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/setdefinition
/api-reference/openapi.yaml put /api/domains/v1/{domain_id}/definition
Set the definition for an existing domain.
# Upsert
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/upsert
/api-reference/openapi.yaml post /api/domains/v1
Create or update a domain.
# UpsertDefinitionPart
Source: https://docs.synq.io/api-reference/synqdomainsv1domainsservice/upsertdefinitionpart
/api-reference/openapi.yaml post /api/domains/v1/{domain_id}/definition/parts
Upsert definition part to the definition of an existing domain.
# BatchGet
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/batchget
/api-reference/openapi.yaml post /api/domains/v2/batch-get
Fetch multiple domains by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
# Delete
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/delete
/api-reference/openapi.yaml post /api/domains/v2/delete
Delete a domain. Idempotent — deleting an already-deleted or unknown domain
succeeds. Soft-deletes by default; set `purge` to hard-delete and release the
id, which is refused while the domain still has sub-domains. Pass `etag` to
guard against deleting a concurrently-edited domain.
# FetchDomainWithSubDomains
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/fetchdomainwithsubdomains
/api-reference/openapi.yaml get /api/domains/v2/{id}/sub-domains
Fetch a domain together with its direct sub-domains, keyed by id.
# GetUsage
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/getusage
/api-reference/openapi.yaml get /api/domains/v2/usage
Report how many domains the workspace uses, split into top-level domains and
sub-domains.
# List
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/list
/api-reference/openapi.yaml get /api/domains/v2
List the domains in the workspace, paginated. Narrow to one level of the
hierarchy with `parent_id`.
# ListMembers
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/listmembers
/api-reference/openapi.yaml get /api/domains/v2/{id}/members
List the assets that currently belong to a domain, resolved from its
definition — including everything contributed by the data products and
domains it references, and by its own sub-domains — and returned as opaque
entity ids. Paginated.
# RemoveDefinitionPart
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/removedefinitionpart
/api-reference/openapi.yaml delete /api/domains/v2/{id}/definition/parts/{part_id}
Remove a single definition part by its part id. Idempotent.
# SetDefinition
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/setdefinition
/api-reference/openapi.yaml put /api/domains/v2/{id}/definition
Replace the entire membership definition of a domain.
# Upsert
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/upsert
/api-reference/openapi.yaml post /api/domains/v2
Create or update a domain. The id is supplied by the caller (a UUID);
repeating the same request converges to the same domain. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
# UpsertDefinitionPart
Source: https://docs.synq.io/api-reference/synqdomainsv2domainsservice/upsertdefinitionpart
/api-reference/openapi.yaml post /api/domains/v2/{id}/definition/parts
Add or replace a single definition part (matched by its part id).
# ListAnnotations
Source: https://docs.synq.io/api-reference/synqentitiesannotationsv1annotationsservice/listannotations
/api-reference/openapi.yaml get /api/entities/annotations/v1
List all available annotations with their usage counts across entities.
# BatchChange
Source: https://docs.synq.io/api-reference/synqentitieschangesv1changesservice/batchchange
/api-reference/openapi.yaml post /api/changes/v1/by-id
BatchChange retrieves multiple entity changes by their IDs in a single request.
This is an optimized endpoint for fetching specific changes when you already know their IDs,
rather than listing changes for an entity.
# List
Source: https://docs.synq.io/api-reference/synqentitieschangesv1changesservice/list
/api-reference/openapi.yaml get /api/changes/v1
Retrieves the complete change history for specified entities.
Returns all change types (git commits, schema changes, SQL changes) in chronological order (newest first).
Changes include lineage context showing upstream_distance when changes affect dependencies.
# DeleteCheckCategories
Source: https://docs.synq.io/api-reference/synqentitieschecksv1checkscategoriesservice/deletecheckcategories
/api-reference/openapi.yaml post /api/entities/checks/v1/categories:delete
DeleteCheckCategories clears the explicit category (both dimensions)
for the given checks. Checks fall back to their rule-computed
categories afterwards.
# ListCheckCategories
Source: https://docs.synq.io/api-reference/synqentitieschecksv1checkscategoriesservice/listcheckcategories
/api-reference/openapi.yaml get /api/entities/checks/v1/categories
ListCheckCategories returns every explicit check category in the
caller's workspace.
# UpsertCheckCategories
Source: https://docs.synq.io/api-reference/synqentitieschecksv1checkscategoriesservice/upsertcheckcategories
/api-reference/openapi.yaml post /api/entities/checks/v1/categories:upsert
UpsertCheckCategories sets (or replaces) the explicit category for
one or more checks. Each entry is the complete state for its check —
both dimensions — so an empty `category` / `governance_category` means
"no explicit value for that dimension".
# ListCode
Source: https://docs.synq.io/api-reference/synqentitiescodev1codeservice/listcode
/api-reference/openapi.yaml get /api/code/v1
ListCode retrieves all code artifacts associated with a specific entity.
This includes SQL queries, Python scripts, dbt models, and other code configurations
that define or are part of the entity's functionality.
# GetTableConstraints
Source: https://docs.synq.io/api-reference/synqentitiesconstraintsv1tableconstraintsservice/gettableconstraints
/api-reference/openapi.yaml get /api/constraints/v1/table-constraints
Get table constraints (primary keys, foreign keys, indexes, etc.) for a given entity.
# BatchDatabaseCoordinates
Source: https://docs.synq.io/api-reference/synqentitiescoordinatesv1databasecoordinatesservice/batchdatabasecoordinates
/api-reference/openapi.yaml post /api/coordinates/v1/database/by-id
Get multiple DatabaseCoordinates for identifiers.
# BatchIdsByCoordinates
Source: https://docs.synq.io/api-reference/synqentitiescoordinatesv1databasecoordinatesservice/batchidsbycoordinates
/api-reference/openapi.yaml post /api/coordinates/v1/database/by-fqn
Given database FQN return possible entity ids.
# DeleteCheckRelationships
Source: https://docs.synq.io/api-reference/synqentitiescustomv1checksrelationshipsservice/deletecheckrelationships
/api-reference/openapi.yaml delete /api/entities/custom/v1/check-relationships
Delete relationships between checks and the entities they validate.
Relationships that do not exist are ignored.
# UpsertCheckRelationships
Source: https://docs.synq.io/api-reference/synqentitiescustomv1checksrelationshipsservice/upsertcheckrelationships
/api-reference/openapi.yaml post /api/entities/custom/v1/check-relationships
Create or update relationships that attach a check (e.g. a SQL test) to the
entities it validates. Idempotent per (check, checked) pair: an existing
relationship is updated, otherwise it is created.
# DeleteEntity
Source: https://docs.synq.io/api-reference/synqentitiescustomv1entitiesservice/deleteentity
/api-reference/openapi.yaml delete /api/entities/custom/v1/entities
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
# ListEntities
Source: https://docs.synq.io/api-reference/synqentitiescustomv1entitiesservice/listentities
/api-reference/openapi.yaml get /api/entities/custom/v1/entities
List all entities.
# UpsertEntity
Source: https://docs.synq.io/api-reference/synqentitiescustomv1entitiesservice/upsertentity
/api-reference/openapi.yaml post /api/entities/custom/v1/entities
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
# UpsertExecution
Source: https://docs.synq.io/api-reference/synqentitiescustomv1entityexecutionsservice/upsertexecution
/api-reference/openapi.yaml post /api/entities/custom/executions/v1
Execution affects status of the custom entity
# UpsertLogEntry
Source: https://docs.synq.io/api-reference/synqentitiescustomv1entityexecutionsservice/upsertlogentry
/api-reference/openapi.yaml post /api/entities/custom/executions/v1/log-entry
LogEntry is a log message for the custom entity
# DeleteEntityFeature
Source: https://docs.synq.io/api-reference/synqentitiescustomv1featuresservice/deleteentityfeature
/api-reference/openapi.yaml delete /api/entities/custom/v1/features
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
# ListEntityFeatures
Source: https://docs.synq.io/api-reference/synqentitiescustomv1featuresservice/listentityfeatures
/api-reference/openapi.yaml post /api/entities/custom/v1/features/list
List all entities.
# UpsertEntityFeature
Source: https://docs.synq.io/api-reference/synqentitiescustomv1featuresservice/upsertentityfeature
/api-reference/openapi.yaml post /api/entities/custom/v1/features
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
# DeleteEntitiesGroup
Source: https://docs.synq.io/api-reference/synqentitiescustomv1groupsservice/deleteentitiesgroup
/api-reference/openapi.yaml delete /api/entities/custom/v1/groups
DeleteEntitiesGroup deletes a group by its identifier. If the group does not exist, it will be a no-op.
# ListEntityGroups
Source: https://docs.synq.io/api-reference/synqentitiescustomv1groupsservice/listentitygroups
/api-reference/openapi.yaml post /api/entities/custom/v1/groups/list
ListEntityGroups lists all groups.
# UpsertEntitiesGroup
Source: https://docs.synq.io/api-reference/synqentitiescustomv1groupsservice/upsertentitiesgroup
/api-reference/openapi.yaml post /api/entities/custom/v1/groups
UpsertEntitiesGroup updates current definition of group to the server. As part of the upsert operation
the difference of entity ids is calculated between past state and the current state and entities that are
no longer part of the group are removed.
# DeleteRelationships
Source: https://docs.synq.io/api-reference/synqentitiescustomv1relationshipsservice/deleterelationships
/api-reference/openapi.yaml delete /api/entities/custom/v1/relationships
Delete relationships between entities. If the relationship does not exist, it will be ignored.
# ListRelationships
Source: https://docs.synq.io/api-reference/synqentitiescustomv1relationshipsservice/listrelationships
/api-reference/openapi.yaml post /api/entities/custom/v1/relationships/list
Delete relationships between entities. If the relationship does not exist, it will be ignored.
# UpsertRelationships
Source: https://docs.synq.io/api-reference/synqentitiescustomv1relationshipsservice/upsertrelationships
/api-reference/openapi.yaml post /api/entities/custom/v1/relationships
Create or update relationships between entities. If the relationship already exists, it will be updated, otherwise it will be created.
# DeleteType
Source: https://docs.synq.io/api-reference/synqentitiescustomv1typesservice/deletetype
/api-reference/openapi.yaml delete /api/entities/custom/v1/types
Delete an entity by its identifier. If the entity does not exist, it will be a no-op.
# ListTypes
Source: https://docs.synq.io/api-reference/synqentitiescustomv1typesservice/listtypes
/api-reference/openapi.yaml post /api/entities/custom/v1/types/list
List all entities.
# UpsertType
Source: https://docs.synq.io/api-reference/synqentitiescustomv1typesservice/upserttype
/api-reference/openapi.yaml post /api/entities/custom/v1/types
Create or update an entity. If the entity does not exist, it will be created, otherwise it will be updated. Entities are identified and deduplicated by their Identifier in a scope of a given customer workspace.
# BatchGetEntities
Source: https://docs.synq.io/api-reference/synqentitiesentitiesv1entitiesservice/batchgetentities
/api-reference/openapi.yaml post /api/entities/v1/by-id
Get multiple entities by their identifiers.
# ListEntities
Source: https://docs.synq.io/api-reference/synqentitiesentitiesv1entitiesservice/listentities
/api-reference/openapi.yaml get /api/entities/v1
List entities matching the given filter
# SearchEntities
Source: https://docs.synq.io/api-reference/synqentitiesentitiesv1entitiesservice/searchentities
/api-reference/openapi.yaml get /api/entities/v1/search
Search for entities.
# UpsertExecution
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv1entityexecutionsservice/upsertexecution
/api-reference/openapi.yaml post /api/executions/v1
Execution affects status of the custom entity
# UpsertLogEntry
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv1entityexecutionsservice/upsertlogentry
/api-reference/openapi.yaml post /api/executions/v1/log-entry
LogEntry is a log message for the custom entity
# BatchGetExecutions
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv2entityexecutionsservice/batchgetexecutions
/api-reference/openapi.yaml post /api/executions/v2/by-id
BatchGetExecutions retrieves multiple executions by their IDs.
This is useful when you already know the execution IDs and want to fetch their details.
# GetExecutionsSummary
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv2entityexecutionsservice/getexecutionssummary
/api-reference/openapi.yaml post /api/executions/v2/summary
GetExecutionsSummary provides aggregated statistics about executions for specified entities.
This is useful for quickly understanding execution patterns without fetching all execution details.
Returns:
- Counts by execution type
- Counts by status
- Time range of available executions
- Latest execution per entity
# GetLatestExecutions
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv2entityexecutionsservice/getlatestexecutions
/api-reference/openapi.yaml post /api/executions/v2/latest
GetLatestExecutions retrieves the most recent execution for each specified entity.
IMPORTANT: Only returns executions where the entity appears in EntityExecution.entities (what executed).
This means it returns executions OF the entity (e.g., model runs, monitor runs, task runs),
NOT executions that merely reference the entity in targets or extra_references.
For example, querying for a table won't return results because tables don't execute on their own -
they are created/updated by models (which do execute).
Optionally filter by execution status to get the latest execution with a specific status.
# ListExecutions
Source: https://docs.synq.io/api-reference/synqentitiesexecutionsv2entityexecutionsservice/listexecutions
/api-reference/openapi.yaml get /api/executions/v2/list
ListExecutions retrieves a paginated list of executions for one or more entities.
Executions are returned in reverse chronological order (newest first).
Supports filtering by:
- Entity identifiers (required)
- Time range
- Execution type(s)
- Status(es)
# Browse
Source: https://docs.synq.io/api-reference/synqentitiesfoldersv1foldersservice/browse
/api-reference/openapi.yaml get /api/entities/folders/v1/browse
Browse the hierarchy one level at a time. With no `parent`, returns the
roots (top-level integrations / containers). With a `parent` folder, returns
that folder's direct sub-folders and the entity ids of its direct,
non-folder members.
One level per call — sub-folders are returned as `Folder`s (each with a
`child_folder_count`), which you Browse into in turn; there is no nested
tree in the response. `filter` narrows the returned members to entities
matching a query.
# GetFolderOf
Source: https://docs.synq.io/api-reference/synqentitiesfoldersv1foldersservice/getfolderof
/api-reference/openapi.yaml get /api/entities/folders/v1/folder-of
Given entity ids, return the folder breadcrumb(s) each entity lives in —
ordered root first, leaf (immediate parent) last. An entity may appear in
more than one hierarchy; the response carries every folder along its
containing chain. Compose with `ListMembers` on an entity's immediate parent
to list its siblings.
# ListMembers
Source: https://docs.synq.io/api-reference/synqentitiesfoldersv1foldersservice/listmembers
/api-reference/openapi.yaml get /api/entities/folders/v1/members
List the entity ids contained in a folder, paginated. Direct members only by
default; set `deep = true` to include members of all nested sub-folders.
Narrow with `types` and/or `filter`.
Pagination is a stable client-side window over the folder's fully-resolved
member set: each page recomputes and re-orders that set, then returns the
requested slice. Results are consistent, but paging deep through a very
large folder repeats work — prefer a larger `page_size` over many small
pages.
# GetImpact
Source: https://docs.synq.io/api-reference/synqentitiesimpactv1impactservice/getimpact
/api-reference/openapi.yaml post /api/impact/v1
# GetLineage
Source: https://docs.synq.io/api-reference/synqentitieslineagev1lineageservice/getlineage
/api-reference/openapi.yaml post /api/lineage/v1
# BatchOrchestration
Source: https://docs.synq.io/api-reference/synqentitiesorchestrationv1orchestrationservice/batchorchestration
/api-reference/openapi.yaml get /api/orchestration/v1
BatchOrchestration retrieves orchestration relationships for multiple entities.
For each entity, it returns both upstream entities (what orchestrates it) and
downstream entities (what it orchestrates).
# BatchResolveIdentifiers
Source: https://docs.synq.io/api-reference/synqentitiesresolvev1identifierresolveservice/batchresolveidentifiers
/api-reference/openapi.yaml post /api/resolve/v1/by-id
Resolve multiple identifiers, returning their Coalesce Quality paths and identity groups.
# BatchSchemaMismatches
Source: https://docs.synq.io/api-reference/synqentitiesschemasv1schemamismatchesservice/batchschemamismatches
/api-reference/openapi.yaml post /api/schema-mismatches/v1
Get schema mismatches for a batch of entities by their identifiers.
# GetSchema
Source: https://docs.synq.io/api-reference/synqentitiesschemasv1schemasservice/getschema
/api-reference/openapi.yaml get /api/schema/v1
Get schema of the entity its identifier.
# BatchSqlDetails
Source: https://docs.synq.io/api-reference/synqentitiessql_insightsv1sqlinsightsservice/batchsqldetails
/api-reference/openapi.yaml post /api/sql-insights/v1/details:batch
BatchSqlDetails returns the SQL details (currently the set of detected SQL
constructs) for each of the requested entities, keyed by their synq path.
Entities with no SQL details are omitted from the response map.
# ListSqlConstructs
Source: https://docs.synq.io/api-reference/synqentitiessql_insightsv1sqlinsightsservice/listsqlconstructs
/api-reference/openapi.yaml get /api/sql-insights/v1/constructs
ListSqlConstructs returns the distribution of SQL constructs across all
entities in the workspace, with an occurrence count per construct. The
result is workspace-scoped (derived from the authenticated request) — no
entity paths are supplied. Useful for building filter/autocomplete UIs and
for high-level "shape of our SQL" analytics.
# BatchGetIncidents
Source: https://docs.synq.io/api-reference/synqentitiesstatusv1entityincidentsservice/batchgetincidents
/api-reference/openapi.yaml post /api/status/v1/incidents/by-id
Get multiple entity statuses by their identifiers.
# BatchGetIssuesStatus
Source: https://docs.synq.io/api-reference/synqentitiesstatusv1entityissuesservice/batchgetissuesstatus
/api-reference/openapi.yaml post /api/status/v1/issues/by-id
Get multiple entity statuses by their identifiers.
# Activate
Source: https://docs.synq.io/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/activate
/api-reference/openapi.yaml patch /api/extensions/atlan/integrations/v1
Activate or deactivate the integration.
# Get
Source: https://docs.synq.io/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/get
/api-reference/openapi.yaml get /api/extensions/atlan/integrations/v1
# Ping
Source: https://docs.synq.io/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/ping
/api-reference/openapi.yaml post /api/extensions/atlan/integrations/v1/ping
Pings Atlan with the given connection credentials.
# Remove
Source: https://docs.synq.io/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/remove
/api-reference/openapi.yaml delete /api/extensions/atlan/integrations/v1
# Upsert
Source: https://docs.synq.io/api-reference/synqextensionsatlanintegrationsv1atlanintegrationservice/upsert
/api-reference/openapi.yaml post /api/extensions/atlan/integrations/v1
Upserts an integration and validates it by checking if the provided API URL and token are valid.
# GetAtlanConnections
Source: https://docs.synq.io/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlanconnections
/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/connections
# GetAtlanDataProducts
Source: https://docs.synq.io/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlandataproducts
/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/data-products
# GetAtlanDomains
Source: https://docs.synq.io/api-reference/synqextensionsatlanproviderv1atlanproviderservice/getatlandomains
/api-reference/openapi.yaml get /api/extensions/atlan/provider/v1/domains
# FetchRuns
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/fetchruns
/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/runs
# GetConnectionMappings
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getconnectionmappings
/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/connection-mappings
# GetDomainMappings
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getdomainmappings
/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/domain-mappings
# GetMappingToggles
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getmappingtoggles
/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/mappings/toggle
# GetProductMappings
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/getproductmappings
/api-reference/openapi.yaml get /api/extensions/atlan/workflows/v1/product-mappings
# RemoveConnectionMappings
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/removeconnectionmappings
/api-reference/openapi.yaml delete /api/extensions/atlan/workflows/v1/connection-mappings
# SetConnectionMappings
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/setconnectionmappings
/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/connection-mappings
# SetMappingToggles
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/setmappingtoggles
/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/mappings/toggle
# Synchronize
Source: https://docs.synq.io/api-reference/synqextensionsatlanworkflowsv1atlanworkflowservice/synchronize
/api-reference/openapi.yaml post /api/extensions/atlan/workflows/v1/synchronize
Run a synchronization job for the integration.
# GetDiffByChangeId
Source: https://docs.synq.io/api-reference/synqgitcommitsv1commitsservice/getdiffbychangeid
/api-reference/openapi.yaml get /api/git/v1/change/{change_id}
# GetDiffByCommit
Source: https://docs.synq.io/api-reference/synqgitcommitsv1commitsservice/getdiffbycommit
/api-reference/openapi.yaml get /api/git/v1/commit/{commit_sha}
# AddIssuesToIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/addissuestoincident
/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/issues
# AssignIncidentOwner
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/assignincidentowner
/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/assign-owner
# BatchGetIncidents
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/batchgetincidents
/api-reference/openapi.yaml post /api/incidents/v1/by-id
# CancelIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/cancelincident
/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/cancel
Cancel an incident
# CloseIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/closeincident
/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/close
Close an incident
# CreateIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/createincident
/api-reference/openapi.yaml post /api/incidents/v1
# ListIncidents
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/listincidents
/api-reference/openapi.yaml get /api/incidents/v1
# MergeIncidents
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/mergeincidents
/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/merge
# PostComment
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/postcomment
/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/comment
Post a comment on an incident.
# RemoveIssuesFromIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/removeissuesfromincident
/api-reference/openapi.yaml delete /api/incidents/v1/{incident_id}/issues
# RenameIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/renameincident
/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/rename
# SplitIncident
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/splitincident
/api-reference/openapi.yaml post /api/incidents/v1/{incident_id}/split
# UpdateIncidentState
Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/updateincidentstate
/api-reference/openapi.yaml patch /api/incidents/v1/{incident_id}/state
# IngestDatahubAspects
Source: https://docs.synq.io/api-reference/synqingestairflowv1airflowlogsservice/ingestdatahubaspects
/api-reference/openapi.yaml post /api/ingest/airflow/v1/aspects
# IngestLog
Source: https://docs.synq.io/api-reference/synqingestairflowv1airflowlogsservice/ingestlog
/api-reference/openapi.yaml post /api/ingest/airflow/v1/{dag_id}/{task_id}/{run_id}/logs
# IngestCloudwatchLogsData
Source: https://docs.synq.io/api-reference/synqingestcloudwatchv1cloudwatchservice/ingestcloudwatchlogsdata
/api-reference/openapi.yaml post /api/ingest/cloudwatch/v1/{log_group}/{log_stream}
# IngestLineage
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestlineage
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/lineage
IngestLineage pushes data-flow lineage between warehouse objects (and,
optionally, between their columns) into the platform. Send the lineage you
extract from the warehouse — for example from Snowflake's GET_LINEAGE — as a
batch of directed edges. Use `replace_mode` to choose between an
incremental update (MERGE) and an authoritative refresh of a region of the
warehouse (REPLACE_SCOPE); REPLACE_SCOPE is what lets the platform expire
edges that no longer exist. Safe to retry: re-sending the same batch
converges to the same state.
# IngestObjectInformation
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestobjectinformation
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/object-information
# IngestObjectMetrics
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestobjectmetrics
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/object-metrics
# IngestQueryLogs
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestquerylogs
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/query-logs
# IngestSchemas
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestschemas
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/schemas
# IngestSqlDefinitions
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingestsqldefinitions
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/sql-definitions
# IngestTableConstraints
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingesttableconstraints
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/upload/{upload_id}/table-constraints
# IngestTaskResults
Source: https://docs.synq.io/api-reference/synqingestdwhv1dwhservice/ingesttaskresults
/api-reference/openapi.yaml post /api/datawarehouse/v1/connection/{connection_id}/task/{task_id}/task-results
# Ingest
Source: https://docs.synq.io/api-reference/synqingestopenlineagev1openlineageservice/ingest
/api-reference/openapi.yaml post /api/ingest/openlineage/v1
# BatchGetIntegrations
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/batchgetintegrations
/api-reference/openapi.yaml post /api/integrations/v1/by-id
Fetch multiple integrations by id in one call. Ids not found (or not in the
workspace) are omitted from the response rather than erroring.
# CreateIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/createintegration
/api-reference/openapi.yaml post /api/integrations/v1
Create a new integration. The server assigns the id and returns the created
integration including any generated outputs.
The integration type is fixed by the populated `config` variant and cannot
be changed later. Counts against the per-workspace quota.
Not safe to blindly retry: the server mints a new id on each call, so a
retried create produces a second integration. On a transport error, list /
look up before retrying.
# DeleteIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/deleteintegration
/api-reference/openapi.yaml delete /api/integrations/v1/{integration_id}
Delete an integration. The integration stops being scheduled and is removed
from listings. Safe to retry (deleting an already-deleted id is a no-op).
# DisableIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/disableintegration
/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/disable
Disable an integration without deleting it. The configuration is kept but
the integration is no longer scheduled or refreshed. No-op if already
disabled.
# EnableIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/enableintegration
/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/enable
Enable a previously disabled integration. No-op if already enabled.
# ListIntegrations
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/listintegrations
/api-reference/openapi.yaml get /api/integrations/v1
List all integrations in the workspace (optionally filtered by enabled
state). Secret config fields are masked. The full set is returned in one
response — a workspace has only a handful of integrations.
# RefreshIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/refreshintegration
/api-reference/openapi.yaml post /api/integrations/v1/{integration_id}/refresh
Trigger an immediate, ad-hoc refresh of an integration. Available only for
types whose `Capabilities.can_refresh` is true; otherwise rejected with
FAILED_PRECONDITION.
Not idempotent: each call enqueues a new refresh.
# UpdateIntegration
Source: https://docs.synq.io/api-reference/synqintegrationsv1integrationsservice/updateintegration
/api-reference/openapi.yaml put /api/integrations/v1/{integration_id}
Update an integration. The `config` is replaced wholesale — send the
complete desired config (omitted secrets are preserved; see the
service-level secret semantics). `title` is patch-style: omit it to leave
it unchanged.
The `config` variant must match the existing integration's type; changing
the type is rejected with FAILED_PRECONDITION.
Safe to retry: addresses an existing id and converges to the same state.
With an `etag` set, a retry after success returns ABORTED
(the version moved) — treat that as "already applied".
# BatchGetIssues
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/batchgetissues
/api-reference/openapi.yaml post /api/issues/v1/by-id
# ListIssues
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/listissues
/api-reference/openapi.yaml get /api/issues/v1
# MarkExpected
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/markexpected
/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-expected
Mark issue as expected.
# MarkFixed
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/markfixed
/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-fixed
Mark issue as fixed.
# MarkInvestigating
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/markinvestigating
/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-investigating
Mark issue as being investigated.
# MarkNoActionNeeded
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/marknoactionneeded
/api-reference/openapi.yaml patch /api/issues/v1/{issue_id}/mark-no-action-needed
Mark issue as no action needed.
# PostComment
Source: https://docs.synq.io/api-reference/synqissuesissuesv1issuesservice/postcomment
/api-reference/openapi.yaml post /api/issues/v1/{issue_id}/comment
Post a comment on an issue.
# BatchGetIssues
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/batchgetissues
/api-reference/openapi.yaml post /api/issues/v2/by-id
# ClearStatus
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/clearstatus
/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/clear-status
Clear the triage status of an issue, returning it to an untriaged state.
Reverses a previous MarkInvestigating / MarkFixed / MarkExpected /
MarkNoActionNeeded so the issue shows up again in open/untriaged views.
# ListIssues
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/listissues
/api-reference/openapi.yaml get /api/issues/v2
# MarkExpected
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/markexpected
/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-expected
Mark issue as expected.
# MarkFixed
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/markfixed
/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-fixed
Mark issue as fixed.
# MarkInvestigating
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/markinvestigating
/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-investigating
Mark issue as being investigated.
# MarkNoActionNeeded
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/marknoactionneeded
/api-reference/openapi.yaml patch /api/issues/v2/{issue_id}/mark-no-action-needed
Mark issue as no action needed.
# PostComment
Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/postcomment
/api-reference/openapi.yaml post /api/issues/v2/{issue_id}/comment
Post a comment on an issue.
# BatchDeleteDeploymentRules
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchdeletedeploymentrules
/api-reference/openapi.yaml delete /api/monitors/automated/v1/deployment-rules/batch
# BatchDeployDeploymentRules
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchdeploydeploymentrules
/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/batch/deployed
# BatchGetDeploymentRules
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchgetdeploymentrules
/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules/batch
# BatchUpdateDeploymentRuleTitle
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchupdatedeploymentruletitle
/api-reference/openapi.yaml patch /api/monitors/automated/v1/deployment-rules
# BatchUpsertDeploymentRules
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/batchupsertdeploymentrules
/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/batch
# DeleteDeploymentRule
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/deletedeploymentrule
/api-reference/openapi.yaml delete /api/monitors/automated/v1/deployment-rule/{id}
# DeployDeploymentRule
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/deploydeploymentrule
/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules/deployed
# GetDeployDeleteOverview
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/getdeploydeleteoverview
/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rule/{id}/deleted
# GetDeployOverview
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/getdeployoverview
/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rule
# ListDeploymentRules
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/listdeploymentrules
/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules
# ListDeploymentRulesForAsset
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/listdeploymentrulesforasset
/api-reference/openapi.yaml get /api/monitors/automated/v1/deployment-rules/{asset_path}
# UpsertDeploymentRule
Source: https://docs.synq.io/api-reference/synqmonitorsautomated_monitorsv1deploymentrulesservice/upsertdeploymentrule
/api-reference/openapi.yaml post /api/monitors/automated/v1/deployment-rules
# BatchCreateMonitor
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchcreatemonitor
/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1
# BatchDeleteMonitor
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchdeletemonitor
/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/delete
# BatchUpdateMonitor
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitor
/api-reference/openapi.yaml put /api/monitors/custom-monitors/v1
# BatchUpdateMonitorMode
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitormode
/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/mode
# BatchUpdateMonitorSeverity
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/batchupdatemonitorseverity
/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/severity
# ConfigChangesOverview
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/configchangesoverview
/api-reference/openapi.yaml post /api/monitors/custom-monitors/v1/config-changes
# ListConfigsMonitors
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/listconfigsmonitors
/api-reference/openapi.yaml get /api/monitors/custom-monitors/v1/by-config
# ListMonitors
Source: https://docs.synq.io/api-reference/synqmonitorscustom_monitorsv1custommonitorsservice/listmonitors
/api-reference/openapi.yaml get /api/monitors/custom-monitors/v1
# History
Source: https://docs.synq.io/api-reference/synqmonitorshistoryv1historyservice/history
/api-reference/openapi.yaml get /api/monitors/history/v1/{monitor_path}
# MonitorInfo
Source: https://docs.synq.io/api-reference/synqmonitorsinfov1monitorinfoservice/monitorinfo
/api-reference/openapi.yaml get /api/monitors/info/v1
# BatchGetLatestEntityMetrics
Source: https://docs.synq.io/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/batchgetlatestentitymetrics
/api-reference/openapi.yaml post /api/monitors/predictions/v1/entity-metrics:batchLatest
Returns the most recent observed table-stats sample (row count, freshness) for each
requested entity. Identity-aware: resolves logical assets to their underlying physical
tables. Paths with no recent sample are omitted from the response rather than returned
with empty values — callers should treat a missing entry as "no data". Lookback matches
GetEntityMetrics (30 days).
# GetEntityMetrics
Source: https://docs.synq.io/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/getentitymetrics
/api-reference/openapi.yaml get /api/monitors/predictions/v1/entity-metrics
Returns raw metric timeseries for an entity. Identity-aware: resolves
logical assets (e.g., dbt models) to their underlying physical tables.
# GetMonitorPredictions
Source: https://docs.synq.io/api-reference/synqmonitorspredictionsv1monitorpredictionsservice/getmonitorpredictions
/api-reference/openapi.yaml get /api/monitors/predictions/v1
Returns prediction timeseries for a monitor. The monitor must exist
and not be deleted. Defaults to the monitor's current metrics_version.
# BatchGetOwners
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/batchgetowners
/api-reference/openapi.yaml post /api/owners/v1/batch-get
Fetch multiple owners by id. Ids that do not exist (or, unless
`include_deleted` is set, are deleted) are omitted from the response rather
than causing an error.
# BatchGetOwnerships
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/batchgetownerships
/api-reference/openapi.yaml post /api/owners/v1/ownerships/batch-get
Fetch multiple ownerships by id (across owners). Ids that do not exist (or,
unless `include_deleted` is set, are deleted) are omitted.
# DeleteOwner
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/deleteowner
/api-reference/openapi.yaml post /api/owners/v1/delete
Delete an owner and all of its ownerships. Idempotent — deleting an
already-deleted or unknown owner succeeds. Soft-deletes by default; set
`purge` to hard-delete and release the id. Pass `etag` to guard against
deleting a concurrently-edited owner.
# DeleteOwnership
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/deleteownership
/api-reference/openapi.yaml post /api/owners/v1/ownerships/delete
Delete an ownership by id. Idempotent — deleting an already-deleted or
unknown ownership succeeds. Pass `etag` to guard against deleting a
concurrently-edited ownership.
# ListOwners
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/listowners
/api-reference/openapi.yaml get /api/owners/v1
List the owners in the workspace, paginated.
# ListOwnerships
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/listownerships
/api-reference/openapi.yaml get /api/owners/v1/{owner_id}/ownerships
List the ownerships of an owner, paginated.
# UpsertOwner
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/upsertowner
/api-reference/openapi.yaml post /api/owners/v1
Create or update an owner. The id is supplied by the caller (a UUID);
repeating the same request converges to the same owner. Mutable fields are
optional: a set field is written, an omitted field is left unchanged. Pass
`etag` to guard against overwriting a concurrent edit.
# UpsertOwnership
Source: https://docs.synq.io/api-reference/synqownersv1ownersservice/upsertownership
/api-reference/openapi.yaml post /api/owners/v1/{owner_id}/ownerships
Create or update an ownership under an owner. The ownership id is supplied
by the caller (a UUID). Assigning a data product that is already owned by a
different ownership moves it (the previous ownership of that product is
removed), matching the app.
# SetPlatformAuthentication
Source: https://docs.synq.io/api-reference/synqplatformsv1platformsservice/setplatformauthentication
/api-reference/openapi.yaml post /api/platforms/v1
# GenerateQuery
Source: https://docs.synq.io/api-reference/synqqueriesv1nlqueryservice/generatequery
/api-reference/openapi.yaml post /api/queries/v1/generate
GenerateQuery generates a Query from a natural language description.
# ResolveQuery
Source: https://docs.synq.io/api-reference/synqqueriesv1queriesservice/resolvequery
/api-reference/openapi.yaml post /api/queries/v1/resolve
Evaluate a selection and return the matched entity ids, paginated. Pass a
ResolverQL expression via `resolver_ql` (it is compiled server-side) or an
already-structured `query`. Invalid ResolverQL fails with INVALID_ARGUMENT.
# TranslateResolverQl
Source: https://docs.synq.io/api-reference/synqqueriesv1queriesservice/translateresolverql
/api-reference/openapi.yaml post /api/queries/v1/translate-resolver-ql
Compile a ResolverQL expression into a structured public `Query`. Unlike
`ResolveQuery`, it does not evaluate the query against the catalog. A
syntactically invalid or uncompilable expression fails with
INVALID_ARGUMENT.
# BatchGet
Source: https://docs.synq.io/api-reference/synqsavedviewsv1savedviewsservice/batchget
/api-reference/openapi.yaml post /api/saved-views/v1/batch-get
Fetch multiple saved views by id. Ids the caller cannot see, or that do not
exist, are omitted from the response rather than causing an error.
# Delete
Source: https://docs.synq.io/api-reference/synqsavedviewsv1savedviewsservice/delete
/api-reference/openapi.yaml post /api/saved-views/v1/delete
Delete a saved view. Idempotent — deleting an already-deleted or unknown
view succeeds. Pass `etag` to guard against deleting a concurrently-edited
view.
# List
Source: https://docs.synq.io/api-reference/synqsavedviewsv1savedviewsservice/list
/api-reference/openapi.yaml post /api/saved-views/v1/list
List the saved views the calling user can see. By default returns every
visible view (their own, workspace-owned, shared-with-workspace and
granted-to-them); narrow with `scopes`, `context` and `only_pinned`.
# SetPin
Source: https://docs.synq.io/api-reference/synqsavedviewsv1savedviewsservice/setpin
/api-reference/openapi.yaml post /api/saved-views/v1/set-pin
Pin or unpin a saved view to the calling user's main screen. Pinning is a
per-user preference: it applies only to the caller and does not modify the
view or its version, so any user who can see a view may pin it.
# Upsert
Source: https://docs.synq.io/api-reference/synqsavedviewsv1savedviewsservice/upsert
/api-reference/openapi.yaml post /api/saved-views/v1
Create or update a saved view.
The view id is supplied by the caller (a UUID), which makes this operation
idempotent — repeating the same request converges to the same view rather
than creating a duplicate. Mutable fields are optional: a field that is set
is written, a field that is omitted is left unchanged. To guard against
overwriting a concurrent edit, pass the `etag` you last read.
# PreviewSchedules
Source: https://docs.synq.io/api-reference/synqschedulev1scheduleservice/previewschedules
/api-reference/openapi.yaml post /api/schedule/v1/preview
PreviewSchedules returns the next occurrences for one or more schedule expressions.
Never fails at the RPC level; per-schedule errors are returned in the response items.
Response items match request items by index.
# Using Webhooks
Source: https://docs.synq.io/api-reference/webhook
Getting started with developer API at Coalesce Quality
# Using Webhooks to Keep External Applications Up-to-Date
Webhooks are a powerful way to receive real-time notifications from Coalesce Quality when specific events occur. This allows external applications to stay updated without constant polling, saving resources and ensuring timely updates.
## Introduction to Webhooks
Coalesce Quality sends HTTP POST requests to a predefined URL whenever certain events occur, including issue lifecycle changes, incident notifications, or a simple ping to confirm that the webhook endpoint is reachable.
Webhooks are defined by a schema that ensures the correct data structure is maintained. Each event has a specific payload format, allowing external applications to process the data accordingly.
Latest schema definition is available as a [JSON Schema](https://schemas.synq.io/webhook/v1/event.schema.json) and as [HTML documentation](https://schemas.synq.io/webhook/v1/event.html).
### Key Concepts
* **Event Types**: Webhook events can represent different actions, such as `ping`, `issue_created`, `issue_updated`, `issue_status_updated`, `issue_closed`, `incident_open`, `incident_closed`, and `incident_cancelled`.
* **Payload Structure**: Each event payload adheres to a defined JSON schema, ensuring consistency and reliability in the data received.
* **Callback Mechanisms**: Webhooks can trigger specific commands or actions in the receiving application, making it possible to automate workflows based on incoming events.
## Webhook Event Schema
The webhook event schema defines the structure of the payload sent for each event type:
* **`workspace`**: Identifies the workspace where the event occurred.
* **`event_id`**: A unique identifier for the event.
* **`event_time`**: The time when the event occurred, formatted as a date-time string.
* **`event_type`**: One of the specific event types (`ping`, `issue_created`, `issue_updated`, `issue_status_updated`, `issue_closed`, `incident_open`, `incident_closed`, `incident_cancelled`), each with its own structured payload.
* **`callbacks`**: An array of callbacks that can be invoked based on the event, containing details such as `url`, `action_name`, and associated `issues_command`.
### Event Types
#### Issue Events
* **Issue Created**: Notifies that a new issue has been created. Contains an `IssueSummary` with details such as `issue_id`, `title`, `description`, `status`, trigger and affected entities, and `owners` (the people or teams responsible for the affected entities).
* **Issue Updated**: Indicates that an existing issue has been updated.
* **Issue Status Updated**: Signals that the status of an issue has changed (e.g., investigating, expected, fixed, no action needed).
* **Issue Closed**: Signals that an issue has been closed.
#### Incident Events
* **Incident Open**: Notifies that a new incident has been opened. Contains an `IncidentSummary` with `incident_id`, `title`, `description`, and `incident_url`.
* **Incident Closed**: Indicates that an incident has been closed.
* **Incident Cancelled**: Signals that an incident has been cancelled.
#### Other Events
* **Ping**: A simple test event sent during webhook setup to confirm the endpoint is functional. Payload contains a `message`.
## Working with Webhook Events
To start using webhooks:
1. **Register a Webhook Endpoint**: Provide a URL endpoint where Coalesce Quality can send events. Use Settings > Integrations > Add integration > Webhook.
2. **Handle Incoming Events**: Set up your server to process incoming POST requests. Ensure that your endpoint correctly interprets the payload format defined in the webhook event schema. Return 2xx status codes to confirm receipt.
3. **Verify the Signature** (recommended): Confirm each request genuinely came from Coalesce Quality before acting on it. See [Verifying Webhook Signatures](#verifying-webhook-signatures).
4. **Automate Actions**: Use the event data to trigger specific actions in your application, such as updating a database, notifying users, or calling other APIs.
### Custom request headers
You can attach custom HTTP headers to every webhook request under Settings > Integrations > your webhook integration — for example an `Authorization` header so Coalesce Quality can reach a protected endpoint.
Mark a header **secret** to store its value securely instead of in the plaintext configuration: secret header values are write-only — masked in the UI and API responses and never returned — and are sent only in the outgoing request. Non-secret headers keep a visible, editable value. To change a secret header enter a new value; leave it blank to keep the stored one.
For authenticating that a request genuinely came from Coalesce Quality, prefer [signature verification](#verifying-webhook-signatures) over a static token in a custom header.
## Verifying Webhook Signatures
Every webhook delivery is signed so your endpoint can verify that the request genuinely originated from Coalesce Quality and was not tampered with or replayed. Verification is strongly recommended — it is the most robust way to authenticate incoming webhooks (stronger than a static bearer token in a custom header).
### Signing secret
Each webhook integration has its own signing secret, generated by Coalesce Quality. The secret is **shown once**, at the moment it is generated — when you create the webhook integration and when you rotate it. Copy it then and store it somewhere secure; it is not retrievable afterwards. The value is prefixed with `whsec_`; use the entire string, including the prefix, as the HMAC key.
If you lose the secret, **rotate** it (Settings > Integrations > your webhook integration) to obtain a fresh one.
**Rotating without downtime**: when you rotate, the previous secret stays valid for a 24-hour grace window. During that window every delivery is signed with *both* the new and previous secrets (two values in `X-Coalesce-Signature`), so your endpoint keeps verifying whether it holds the old or the new secret. Update your endpoint to the new secret any time within the window.
### Signature headers
Two headers are sent on every request:
| Header | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Coalesce-Timestamp` | Unix timestamp (seconds) of when the delivery was signed. |
| `X-Coalesce-Signature` | One or more space-separated, scheme-prefixed signatures — e.g. `v1=` or, during a rotation grace window, `v1= v1=`. A request is authentic if **any** `v1=` value matches. The `v1=` prefix identifies the signature scheme. |
### Signature scheme
Each signature is a hex-encoded HMAC-SHA256 computed over the timestamp and the raw request body, joined by a `.`:
```
signed_payload = "{X-Coalesce-Timestamp}." +
signature = hex( HMAC_SHA256(key = signing_secret, msg = signed_payload) )
```
To verify a request:
1. Read the `X-Coalesce-Timestamp` header and the **raw** request body (verify before any JSON parsing or re-serialization — a re-serialized body will not match).
2. Recompute the signature with your copy of the signing secret and check it against **each** `v1=` value in `X-Coalesce-Signature` using a **constant-time** comparison; accept the request if any matches.
3. Optionally reject requests whose timestamp is outside your tolerance window. Retries reuse the original signing timestamp, so allow for the retry backoff window (deliveries may be retried for up to \~30 minutes).
### Examples
```python Python theme={null}
import hmac
import hashlib
def verify(signing_secret: str, timestamp: str, raw_body: bytes, signature_header: str) -> bool:
signed_payload = timestamp.encode() + b"." + raw_body
expected = hmac.new(signing_secret.encode(), signed_payload, hashlib.sha256).hexdigest()
# signature_header is one or more space-separated "v1=" values;
# accept the request if any of them matches.
for token in signature_header.split():
scheme, _, provided = token.partition("=")
if scheme == "v1" and hmac.compare_digest(expected, provided):
return True
return False
# In your handler (e.g. Flask): pass request.headers and request.get_data() (raw bytes)
```
```javascript Node.js theme={null}
const crypto = require("crypto");
function verify(signingSecret, timestamp, rawBody, signatureHeader) {
const signedPayload = `${timestamp}.${rawBody}`;
const expected = crypto
.createHmac("sha256", signingSecret)
.update(signedPayload)
.digest("hex");
// signatureHeader is one or more space-separated "v1=" values;
// accept the request if any of them matches.
return signatureHeader.split(" ").some((token) => {
const [scheme, provided] = token.split("=");
return (
scheme === "v1" &&
provided &&
provided.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(provided))
);
});
}
// rawBody must be the unparsed request body (e.g. express.raw()), not a re-stringified object.
```
## Sample Webhook Event Payload
Here's an example of a webhook event payload for an issue created:
```json theme={null}
{
"workspace": "example_workspace",
"event_id": "0b6f9c2e-1a2b-4c3d-9e8f-123456789abc",
"event_time": "2026-07-16T12:34:56Z",
"event_type": "EVENT_TYPE_ISSUE_CREATED",
"issue_created": {
"issue": {
"issue_id": "789",
"issue_group_id": "group1",
"issue_url": "https://app.synq.io/incident/issues/group1?issueId=789",
"title": "Freshness check failed for orders table",
"description": "Table has not been updated in the last 2 hours\n\nOwned by: [Data Platform](https://app.synq.io/owners-v2/owner-a1b2c3d4-e5f6-7890-abcd-ef1234567890)",
"description_html": "
Table has not been updated in the last 2 hours
",
"trigger_entity": {
"name": "orders",
"type_name": "Clickhouse Table",
"identifier": {
"clickhouse_table": { "host": "prod", "schema": "analytics", "table": "orders" }
},
"entity_url": "https://app.synq.io/catalog/ch-prod::analytics::orders"
},
"monitored_entities": [
{
"name": "orders",
"type_name": "Clickhouse Table",
"identifier": {
"clickhouse_table": { "host": "prod", "schema": "analytics", "table": "orders" }
},
"entity_url": "https://app.synq.io/catalog/ch-prod::analytics::orders"
}
],
"started_at": "2026-07-16T12:34:56Z",
"trigger_run_id": "freshness-orders-2026-07-16T12:34:56Z",
"trigger_name": "Freshness monitor",
"trigger_message": "Table has not been updated in the last 2 hours",
"status": "ISSUE_STATUS_INVESTIGATING",
"owners": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Data Platform",
"url": "https://app.synq.io/owners-v2/owner-a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
]
}
}
}
```
This example is illustrative. The [JSON Schema](https://schemas.synq.io/webhook/v1/event.schema.json) is the authoritative, always-current field reference — code against it for the complete set of fields on each event type. `owners` is present on issue events (`issue_created`, `issue_updated`, `issue_status_updated`, `issue_closed`) and lists the owners of the affected entities, each with an `id` (matching the Owners API), a display `title`, and a deep-link `url`. It is omitted when the affected entities have no owner assigned. New fields are added in a backward-compatible way.
# Looker
Source: https://docs.synq.io/bi-integrations/looker
Integrating Looker with Coalesce Quality
This guide will walk you through how to set up the Coalesce Quality integration with Looker. We connect to Looker via API (to fetch the structure of your Looker objects) and via git (to fetch lookML) models. As a result, we can create a complete picture of your Looker setup and connect it to your data warehouse and transformation models (dbt, SQLMesh, or Coalesce Transform).
To finish this guide, you’ll need the following:
→ Admin permissions for Looker
→ Access to GitHub or GitLab
→ Admin Access to your Looker repository (only repo admins can add deploy keys)
⏱️ Estimated time to finish: 15 minutes.
# Integration
The optimal way to setup is an API key with admin role permissions, which would give Coalesce Quality the necessary permissions to fetch all observability data to reconstruct end-to-end lineage of your Looker objects.
*In case you are limited by security policies to provide Admin-level access, we also offer an admin-less integration using a CLI tool. Reach out to us in our shared Slack channel to set this up.*
# Setup guide
Follow the Looker access and LookML access guides below to set up the Looker integration.
## Looker access
To process your Looker data, we need access to your Looker instance. Coalesce Quality connects to Looker with `clientId` and `clientSecret`, which is bound to a user with Admin permissions.
1. Go to `Admin > Users` and create a new user with `Add User`
1. Use `synq@.com` as email address
2. Disable `Send setup emails` and Save
3. Give the user the `Admin` role
2. Edit the `synq@.com` user and create `clientId` and `clientSecret` API permissions (see [Looker integration docs](https://cloud.google.com/looker/docs/api-auth#authentication_with_an_sdk) for details).
1. click `Edit Keys`
2. click `New API Key`
3. In Coalesce Quality, you'll need your instance base URL (`https://.cloud.looker.com`), `clientId`, and `clientSecret` securely to complete the integration.
# LookML Access
To process LookML models, we need access to the underlying Looker repository. The Git integration has to be setup as a separate step and can be done in Coalesce Quality: [https://app.synq.io/settings/integrations/git](https://app.synq.io/settings/integrations/git). The process executes in two phases:
### 1. Collect information about your repo
1. **Repository URL**—The full URL of the git repository that contains your Looker project (we support both HTTPS and SSH URLs).
2. **Branches to analyze (default: `master` and `main`)**—By default, the `master` and `main` branches are analysed. Please provide the name if you prefer us to process the code from any other branch. We support multiple branches too.
3. **Path to analyze (default: `.`)**—By default, Coalesce Quality looks for your LookML source code in the root of the repository. If you store your code in a subdirectory, please provide us with a path if your Looker project uses a subdirectory. In most cases, it is best to leave this as the default to analyze everything in the repository.
### 2. Setup Deployment Key
To finish the setup, you will have to store the public part of the Coalesce Quality deployment key with your git provider. You can follow the instructions based on your git provider below:
* [GitHub - setup deploy key](https://synq-15.mintlify.app/code-integrations/github#setup-a-deploy-key)
* [GitLab - setup deploy key](https://synq-15.mintlify.app/code-integrations/gitlab#setup-a-deploy-key)
# Omni
Source: https://docs.synq.io/bi-integrations/omni
Integrating Omni with Coalesce Quality
This guide will walk you through how to set up the Coalesce Quality integration with Omni. As a result, we can create a complete picture of your Omni setup and connect it to your data warehouse and transformation models (dbt, SQLMesh, or Coalesce Transform).
⏱️ Estimated time to finish: 10 minutes.
# Integration
Get in touch with your Solutions Architect to set up the Omni integration in your Coalesce Quality workspace
# Tableau
Source: https://docs.synq.io/bi-integrations/tableau
Integrating Tableau with Coalesce Quality
This guide will walk you through how to set up the Coalesce Quality integration with Tableau. As a result, we can create a complete picture of your Tableau setup and connect it to your data warehouse and transformation models (dbt, SQLMesh, or Coalesce Transform).
To finish this guide, you’ll need the following:
→ Site Administrator, Site Administrator Explorer or Site Administrator Creator access to Tableau
⏱️ Estimated time to finish: 10 minutes.
# Integration
Coalesce Quality connects to your Tableau instance as a specific user, authenticated via [personal access token](https://help.tableau.com/current/server/en-us/security_personal_access_tokens.htm). The optimal way to set it up is to create a personal access token under at least `Site Administrator Explorer` user, which would give Coalesce Quality the necessary permissions to fetch all observability data to reconstruct the end-to-end lineage of your Tableau objects.
*In case you are limited by security policies to provide Admin-level access, we also offer an admin-less integration using a CLI tool. Reach out to us in our shared Slack channel to set this up.*
## Setup guide
### Connection URI
The base URL of your Tableau cloud instance (e.g., `https://dub01.online.tableau.com`)
### Site
The site for your Tableau project. You can find this after the `/site/` path in the URL (e.g., `synq` in `https://dub01.online.tableau.com/#/site/synq/`)
### Token name and token secret
Personal Access Tokens (PATs) are disabled by default. To enable them, log into Tableau as a site administrator, go into `Settings` (not `My Account Settings`), and scroll to the Personal Access Tokens section. Hit `save` to apply the changes.
Once you’ve enabled the creation of Personal Access Tokens, go to `My Account Settings` scroll down to Personal Access Tokens, and click `Create Token`. Copy the `token name` and `secret` and input them into Coalesce Quality.
### Projects
By default, we’ll ingest all your Tableau projects. If you only want some projects integrated, add the names of those in Coalesce Quality
# Atlan
Source: https://docs.synq.io/catalogs/atlan
Integrating Atlan with Coalesce Quality
Coalesce Quality has a deep bi-directional integration with Atlan, helping you manage data without duplicating effort across both platforms. Define data products and ownership in Atlan, then add monitoring and alerting rules in Coalesce Quality. The resulting quality score is visible to users on either platform, making the entire ecosystem transparent and seamless.
> Reach out to the Coalesce Quality team to enable Atlan integration for your workspace.
Once enabled, you can add an Atlan integration from the `Integrations` tab on the `Settings` page.
You then need to add the following information:
1. Tenant URL - This is the URL you use to access Atlan (eg. `https://.atlan.com`)
2. API token - Generated as following.
To generate the API token, head over to Atlan.
* In `Governance > Personas` , create a new persona. Name it something indicative like `Coalesce Quality - API Access`.
* Within the persona, create the following policies:
* `Domain Policy` with `Read` permission for domains. You can choose `All Domains` or cherry pick the ones you want to be visible in Coalesce Quality.
* `Metadata Policy` for each connection that you want to be visible in Coalesce Quality. Choose the permission `Assets -> Read`
* In `Admin > API Tokens` create a new API token. Name it something indicative like `Coalesce Quality - API`.
* Choose `Expiry Never`
* Add the persona you just created in the step above (`Coalesce Quality - API Access`)
* Download or copy the API token that you see.
Enter the Tenant URL and API token in the corresponding section of the Atlan integration.
If the URL and Token are valid you will be able to proceed to the next steps.
1. Map supported integrations with Atlan connections.
2. Choose which Atlan assets to synchronize.
The Atlan integration synchronizes every 30 minutes and performs a full catalog sync along with the domains, dataproducts and owners you selected. You can easily identify the assets pulled from Atlan by the logo next to them.
You can enhance the Owners with your monitoring and alerting preferences.
Reach out in our shared Slack channel for any assistance you might need with your Atlan integration.
# Command-line tools
Source: https://docs.synq.io/cli
Install any of the Coalesce Quality CLIs, and find the reference for each
Three command-line tools, all of them installable and runnable on your own
infrastructure without involving us. They share credentials, so one login covers
all three.
| Tool | What it does | Guides |
| ---------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`synqcli`** | Declares monitors, SQL tests and deployment rules as code, and reconciles a workspace with that declaration | [Monitors as code](/monitors/monitors-as-code) · [Agent workflow](/monitors/agent-workflow) · [CLI reference](/monitors/cli) |
| **`synq-recon`** | Compares a dataset in one database against another and reports whether they agree, without moving row data | [Overview](/reconciliation/overview) · [Getting started](/reconciliation/getting-started) · [Agent workflow](/reconciliation/agent-workflow) · [CLI reference](/reconciliation/cli) |
| **`synq-scout`** | Runs the Scout agent, or serves its tools locally over MCP | [Scout](/scout/scout) · [Agent workflow](/scout/agent-workflow) · [CLI reference](/scout/cli) |
Each tool ships an **`AGENTS.md`** beside the binary — the operating guide,
written for a coding agent to read top-down and act on. It is the same content as
the "Agent workflow" page linked above, so an agent with a download and no web
access still has it. If you are pointing an agent at one of these tools, that is
the file to give it.
## Install
Every release publishes archives for macOS and Linux on both `amd64` and `arm64`
(`synqcli` also builds for Windows), plus a `checksums.txt`. Pick a version from the
releases page — the archive filename carries it, so it has to be named explicitly.
```bash theme={null}
VERSION=0.4.3 # from https://github.com/getsynq/synqcli/releases
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
curl -fL "https://github.com/getsynq/synqcli/releases/download/v${VERSION}/synqcli_${VERSION}_${OS}_${ARCH}.tar.gz" \
| tar -xz
sudo mv synqcli /usr/local/bin/
synqcli --version
```
On Windows, download the `.zip` for your architecture from the releases page and
put `synqcli.exe` on your `PATH`.
```bash theme={null}
VERSION=0.2.0 # from https://github.com/getsynq/synq-recon/releases
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
curl -fL "https://github.com/getsynq/synq-recon/releases/download/v${VERSION}/synq-recon_${VERSION}_${OS}_${ARCH}.tar.gz" \
| tar -xz
sudo mv synq-recon /usr/local/bin/
synq-recon --version
```
Also available as a container image, which is the quickest way to try it with no
warehouse at all — the walkthrough in
[Getting started](/reconciliation/getting-started) runs against DuckDB:
```bash theme={null}
docker pull europe-docker.pkg.dev/synq-cicd-public/synq-public/synq-recon:latest
```
```bash theme={null}
VERSION=0.2.0 # from https://github.com/getsynq/synq-scout/releases
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
curl -fL "https://github.com/getsynq/synq-scout/releases/download/v${VERSION}/synq-scout_${VERSION}_${OS}_${ARCH}.tar.gz" \
| tar -xz
sudo mv synq-scout /usr/local/bin/
synq-scout --version
```
For a long-running deployment, use the Kubernetes manifests in
[getsynq/synq-scout-k8s](https://github.com/getsynq/synq-scout-k8s) — see
[Scout on-premise setup](/scout/on-premise).
You do **not** need this binary to use Scout's tools from an AI client: the MCP
server is hosted. See [MCP](/scout/mcp).
Verify a download against the checksums published with the release:
```bash theme={null}
sha256sum -c checksums.txt --ignore-missing
```
On macOS a downloaded binary may be quarantined. If it refuses to start,
`xattr -d com.apple.quarantine /usr/local/bin/` clears the flag.
## Sign in
All three resolve credentials the same way, and take the first they find:
1. **Client credentials** — `QUALITY_CLIENT_ID` + `QUALITY_CLIENT_SECRET`, for
servers, containers and CI. Create the pair under Settings → API.
2. **An API token** — `QUALITY_TOKEN`, the `st-…` token from your workspace.
3. **A browser login** — ` auth login`, which caches a refresh token under
`~/.synq/oauth/`.
The cache is shared, so one `auth login` covers all three for the same deployment.
```bash theme={null}
synqcli auth login
synqcli auth status # every stored credential, for every region
```
If your workspace is not in the EU, add `--region us` (or `au`), or set
`QUALITY_REGION`. The flag works on every command, and a successful login is
remembered, so later commands need neither it nor `--endpoint`.
Confirm which workspace you are pointed at before running anything that writes.
`synq-scout auth whoami` and `synqcli auth status` both print it. A `synqcli
deploy` against the wrong region reconciles the wrong workspace — and a reconcile
deletes what it does not find declared.
## Get the command reference
Each tool's full command and flag reference is generated from the tool itself, so it
always matches the release you have:
* [`synqcli` reference](/monitors/cli)
* [`synq-recon` reference](/reconciliation/cli)
* [`synq-scout` reference](/scout/cli)
`--help` on any command prints the same content locally, and every tool supports
shell completion.
## Field references for the YAML
Each tool's configuration schema is published and versioned, and each is
authoritative in a way prose is not. Two forms of the same thing: a rendered page to
read, and the JSON Schema to point an editor at.
| Tool | Configures | Reference | Schema URL |
| ------------ | --------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------- |
| `synqcli` | monitors, tests, deployment rules | [config.html](https://schemas.synq.io/synq-monitors/v1/config.html) | `https://schemas.synq.io/synq-monitors/v1/config.schema.json` |
| `synq-recon` | suites, connections, comparisons | [config.html](https://schemas.synq.io/synq-recon/v1/config.html) | `https://schemas.synq.io/synq-recon/v1/config.schema.json` |
| `synq-recon` | the audit log a run writes | [audit-log.html](https://schemas.synq.io/synq-recon/v1/audit-log.html) | `https://schemas.synq.io/synq-recon/v1/audit-log.schema.json` |
| `synq-scout` | `agent.yaml` | [config.html](https://schemas.synq.io/synq-scout/v1/config.html) | `https://schemas.synq.io/synq-scout/v1/config.schema.json` |
Put the matching line at the top of your YAML and any editor with the YAML language
server gives completion and validation as you type:
```yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-recon/v1/config.schema.json
```
The [data-warehouse agent](/dw-integrations/agent) publishes its config schema the
same way.
## Use them from CI
Client credentials plus the archive download is all CI needs; no interactive login
is involved. `synqcli deploy --auto-confirm` and `synq-recon`'s exit codes are the
two things worth reading before wiring a pipeline —
[Reconciliation in CI/CD](/reconciliation/cicd-and-automation) covers the second in
full.
Need something not covered here? [Get in touch](/support/support).
# Coalesce Catalog
Source: https://docs.synq.io/coalesce-integrations/coalesce-catalog
Connect Coalesce Quality with your Catalog workspace for bidirectional metadata sync
This guide will walk you through how to connect Coalesce Quality with Coalesce Catalog (formerly Castordoc). The integration allows bidirectional metadata synchronization between the two platforms.
To finish this guide, you'll need the following:
→ Admin access to your Coalesce Quality workspace
→ Admin access to your Coalesce Catalog workspace
→ At least one data warehouse integration configured in the platform (for warehouse mappings)
⏱️ Estimated time to finish: 15 minutes.
# Integration
Coalesce Catalog is a data catalog solution that helps organizations discover, understand, and govern their data assets. This integration connects your Catalog and quality workspaces to provide a unified view of your data assets and their health.
The integration is **bidirectional**:
**From Catalog to quality:**
* Pulls all catalog entities (tables, dashboards, etc.) and maps them to corresponding quality assets
* This ensures that assets in both platforms are linked, providing a unified view across your data stack
**From quality to Catalog:**
* Reports monitor status, test results, and asset health as **Data Qualities** in your catalog
* Supports both **table-level** and **column-level** quality reporting
* Keeps your catalog enriched with real-time data quality information
# Setup guide
## Name your integration
For example `Coalesce Catalog` or `Production Catalog`
## Select the region
Select your Coalesce Catalog region from the dropdown:
* **Rest of World (EU):** [https://app.castordoc.com/](https://app.castordoc.com/)
* **United States:** [https://app.us.castordoc.com/](https://app.us.castordoc.com/)
Choose the region that matches your Coalesce Catalog workspace. You can determine your region by looking at the URL you use to access Coalesce Catalog.
## Generate a token
Coalesce Catalog API tokens are managed by your organization's Catalog ops team
1. Contact your **Coalesce Catalog ops team** to request an API token
2. Ensure the token has appropriate read and write permissions for metadata synchronization
3. Store the token securely in a secrets manager — never commit tokens to version control
Store your API token securely. Coalesce Catalog tokens provide access to your workspace metadata and should be treated as sensitive credentials.
## Configure sync intervals
### Fetch interval (hours)
How often the platform should fetch catalog entities from Coalesce Catalog. Default: **2 hours**
This controls how frequently the platform pulls tables, dashboards, and other catalog entries to map them with your quality assets.
### Upload interval (minutes)
How often the platform should upload Data Qualities to your Catalog workspace. Default: **30 minutes**
This controls how frequently the platform pushes monitor status, test results, and asset health information to your catalog entries.
## Configure warehouse mappings
Warehouse mappings connect your Catalog warehouses to your data warehouse integrations. This enables the platform to correlate assets between both systems.
You must have at least one data warehouse integration (BigQuery, Snowflake, Databricks, etc.) configured before you can add warehouse mappings.
To add a warehouse mapping:
1. Click **Add Warehouse Mapping**
2. Select a **Coalesce Warehouse** from the dropdown (or enter the warehouse ID manually if not listed)
3. Select the corresponding **Data Warehouse** integration
4. The **Mapping Name** is auto-generated based on your selections, but you can customize it
You can add multiple warehouse mappings to connect all your Catalog warehouses with their corresponding data warehouse integrations.
# What data is synced?
## Catalog entities (Catalog → quality)
The platform pulls catalog entities and maps them to corresponding quality assets:
* Tables and views
* Dashboards and reports
* Other catalog entries
This mapping ensures that when you view an asset in either platform, it's linked to its counterpart, providing a unified experience.
## Data Qualities (quality → Catalog)
The platform uploads data quality information to your catalog as **Data Qualities**, which appear on your catalog entries:
**Table-level qualities:**
* Monitor status (passing, failing, warning)
* Test results from transformation layer tests (dbt, SQLMesh, Coalesce Transform) and custom SQL tests
* Freshness and volume health indicators
* Overall asset health status
**Column-level qualities:**
* Column-specific monitor results
* Field-level test outcomes
* Column health indicators
This enables your data consumers to see quality status directly in the catalog without needing to switch platforms.
# FAQ
### What access do you require?
We require write access to Data Qualities via the Coalesce Catalog Public API. The token also needs read access to list available warehouses during configuration. We don't access raw data in your data warehouse through this integration.
### What if I change regions?
If you change the region, you must provide a new API token for that region. Tokens are region-specific and cannot be used across different Coalesce Catalog regions.
### What if warehouses don't appear in the dropdown?
If warehouses don't load:
1. Verify your API token is correct and has read permissions
2. Ensure the region matches your Coalesce Catalog workspace
3. Check that warehouses are configured in your Coalesce Catalog
4. You can manually enter the warehouse UUID if the dropdown doesn't populate
### How are Data Qualities displayed in the catalog?
Data Quality entries appear on your table and column pages in Coalesce Catalog. These show the current status of monitors and tests, allowing catalog users to quickly assess data health.
# Coalesce Transform
Source: https://docs.synq.io/coalesce-integrations/coalesce-transform
Connect Coalesce Quality with your Transform workspace for pipeline monitoring and lineage
This guide will walk you through how to connect your Coalesce Transform workspace to Coalesce Quality, enabling you to track pipeline runs, job statuses, and metadata changes.
To finish this guide, you'll need the following:
→ Admin access to your Coalesce Quality workspace
→ Admin access to your Coalesce Transform workspace
→ Ability to generate API tokens in Coalesce
⏱️ Estimated time to finish: 10 minutes.
# Integration
[Coalesce](https://coalesce.io) is a metadata-driven data transformation platform that helps data teams build and operate governed data pipelines on cloud data platforms. It combines visual DAG-based design with code editing capabilities, built-in governance, and column-level lineage tracking.
This integration uses read-only APIs to fetch metadata from Coalesce. It cannot modify your projects, configurations, or pipelines.
Integrating Coalesce Transform gives you:
## Transformation Catalog & Discovery
See your entire Coalesce landscape in one place:
* **Projects** with their Git repository connections
* **Environments** (dev, staging, prod) with their configurations
* **Nodes** (transformations) - what each one does, where it writes data
* **Jobs** - scheduled transformation groups
## Run Monitoring & Alerting
Every transformation execution is tracked:
* **Deploy runs** - when new transformation code is deployed
* **Refresh runs** - when scheduled jobs execute
* **Per-query details** - which SQL ran, how long it took, rows affected
Status tracking includes success/failure, test failures (blocking vs non-blocking), error messages, and who triggered the run.
## Data Lineage
**Table-level lineage:**
* Which Coalesce nodes feed into which downstream nodes
* Connection to physical warehouse tables (Snowflake, BigQuery, etc.)
**Column-level lineage:**
* Which source columns flow into which target columns
* Whether columns are passed through, renamed, or transformed
## Data Quality Test Results
Coalesce SQL tests are tracked as part of runs:
* Node-level tests (custom SQL assertions)
* Column-level tests (null checks, uniqueness, etc.)
* Pass/fail status per test
* Whether failures block the pipeline or just warn
## SQL Visibility
The actual SQL executed by Coalesce is captured:
* Pre-SQL (setup statements)
* Main transformation query
* Post-SQL (cleanup/grants)
* Test queries
## Cross-Platform Connectivity
Coalesce nodes are linked to:
* Their physical warehouse tables (identity relationship)
* Git files that define them
* Downstream BI tools that query the output tables
This provides true end-to-end lineage from source → Coalesce transformation → warehouse table → dashboard.
# Setup guide
## Name your integration
For example `Coalesce Transform` or `Production Coalesce`
## Select the region
Select your Coalesce server region from the dropdown:
| Region | Endpoint |
| ------------------------------- | ------------------------------------------------------------- |
| US primary | `https://app.coalescesoftware.io` |
| Europe primary | `https://app.eu.coalescesoftware.io` |
| Australia primary | `https://app.australia-southeast1.gcp.coalescesoftware.io` |
| US AWS US East | `https://app.us-east-1.aws.coalescesoftware.io` |
| US AWS US East with PrivateLink | `https://app.us-east-1.aws.privatelink.coalescesoftware.io` |
| US AWS US West | `https://app.us-west-2.aws.coalescesoftware.io` |
| US AWS US West with PrivateLink | `https://app.us-west-2.aws.privatelink.coalescesoftware.io` |
| Canada Primary | `https://app.northamerica-northeast1.gcp.coalescesoftware.io` |
| US Azure West 2 | `https://app.westus2.azure.coalescesoftware.io` |
| US Azure East 2 | `https://app.eastus2.azure.coalescesoftware.io` |
| Custom endpoint | Enter your own URL |
Choose the region that matches your Coalesce workspace. You can find your region by looking at the URL you use to access Coalesce.
If your Coalesce instance uses a custom domain or private deployment, select **Custom endpoint** and enter your Coalesce API URL. Must be an HTTPS URL.
## Generate a token
These steps will take you through how to create a token to grant read access to your Coalesce Transform project
1. Log into your Coalesce workspace
2. Navigate to the **Deploy** section
3. Click **Generate Access Token**
4. Copy the generated token immediately (you won't be able to view it again)
5. Paste it into the **API Token** field in the integration setup
Store your access token securely. Coalesce tokens provide access to your workspace metadata and should be treated as sensitive credentials. Copy the token immediately after generation as you won't be able to view it again.
Your Coalesce account must have API access enabled. The generated token will have the same access rights as the user who created it, so ensure you have access to the projects you want to sync.
## Configure fetch interval
Configure how often the platform should poll Coalesce Transform for updates. Default: **5 minutes**
You can adjust this based on:
* **Higher frequency (1-5 minutes):** For production environments where you need near real-time monitoring
* **Lower frequency (10-30 minutes):** For development environments or when API rate limits are a concern
## Select projects
After entering valid credentials, the platform will automatically load your available Coalesce Transform projects.
You can:
* **Select specific projects** by checking the boxes next to project names
* **Sync all projects** by leaving all checkboxes unchecked. This is useful when you want the platform to automatically include new projects as they're created in Coalesce Transform.
For each selected project, you can configure environment filtering:
* **All environments** - sync all environments in the project
* **Include specific environments** - only sync selected environments
* **Exclude specific environments** - sync all except selected environments
**Recommendation:** If you have many projects, start by selecting only production projects. You can always edit the integration later to include additional projects.
# Typical use cases
| Use Case | How it helps |
| ------------------------------------------- | ---------------------------------------------------------------------------- |
| "Our dashboard is showing stale data" | See if Coalesce refresh job failed, when it last ran successfully |
| "We're changing a source table schema" | Trace lineage to see which Coalesce nodes and downstream assets are affected |
| "Transformation is slow" | See query execution times, identify bottlenecks |
| "Data quality issue in production" | Check which Coalesce tests passed/failed, see test history |
| "Who changed this transformation?" | See deploy runs with commit info and user who triggered |
| "What does this Coalesce node actually do?" | View the SQL definition and column-level lineage |
# FAQ
### What access do you require?
We only request read access to your metadata and won't be able to read raw data or update or run any models.
### Will you store personal or business-critical data?
The platform only stores log-level data and doesn't access any actual data from your data warehouse.
### What if projects don't load?
If projects don't appear after entering your credentials:
1. Verify your API token is correct
2. Ensure the API endpoint matches your Coalesce region
3. Check that your token has the required read permissions
4. Try regenerating the token in Coalesce with appropriate permissions
### Can I use a custom Coalesce deployment?
Yes, select **Custom endpoint** from the region dropdown and enter your Coalesce API URL. This supports private deployments and custom domains.
### What if I need to change the region?
To change the region after creating the integration, you'll need to delete the integration and create a new one with the correct region.
# Azure DevOps Integration
Source: https://docs.synq.io/code-integrations/azure-devops
Add SSH keys to Azure DevOps Repos for Coalesce Quality
## Overview
This guide covers how to add the generated public SSH key to Azure DevOps Repos for repository access.
**Before you start:** Create your Git integration first by following the [integration form instructions](/code-integrations/overview#configuring-the-integration). You'll need the public SSH key from that integration.
## Prerequisites
* Access to Azure DevOps
* **Read permissions** on the repository you want to integrate
* Public SSH key from your Git integration
* A service account or user account to add the SSH key to
⏱️ **Estimated time:** 10 minutes
**Important:** Azure DevOps does not support repository-level deploy keys. You must use a service account or user account with SSH keys. The account should have **Read** permissions only on the repository.
## IP Whitelisting (If Required)
If your Azure DevOps organization uses IP restrictions, add the Coalesce Quality egress IP addresses for your region. See [IP Whitelist](/security/ip) for the complete list.
For instructions on configuring IP restrictions in Azure DevOps, see Azure DevOps' guide on [IP address restrictions](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/change-application-access-policies).
## Setting Up SSH Access
### Step 1: Create or Use a Service Account
1. Create a dedicated service account (recommended) or use an existing account
2. Grant the account **Read** permissions on the repository:
* Navigate to **Project Settings > Repositories**
* Select your repository
* Go to **Security** tab
* Add the service account with **Read** permission only
Using a dedicated service account makes it easier to audit and revoke access if needed.
### Step 2: Add SSH Public Key
1. Sign in to Azure DevOps with the service account
2. Click on your **User settings** icon (top right)
3. Select **SSH public keys**
4. Click **+ New Key**
5. Configure the SSH key:
* **Name:** Enter a descriptive name (e.g., `Coalesce Quality Integration`)
* **Public Key Data:** Paste the complete public SSH key from your integration
Make sure to paste the **complete key** including the `ssh-rsa` or `ssh-ed25519` prefix.
6. Click **Add**
The SSH key is now active for this account.
### Step 3: Verify Repository Access
Ensure the service account has access to the specific repository:
1. Navigate to **Project Settings > Repositories**
2. Select your repository
3. Go to **Security** tab
4. Verify the service account is listed with **Read** permissions
## Repository URL Format
When configuring the integration, use the Azure DevOps SSH URL format:
**Format:** `git@ssh.dev.azure.com:v3/organization/project/repository`
**Example:** `git@ssh.dev.azure.com:v3/mycompany/DataPlatform/analytics-repo`
The URL format for Azure DevOps SSH is different from other Git providers. Make sure to use the exact format shown above with `ssh.dev.azure.com:v3/`. This is automatically converted to `dev.azure.com` for the web URL.
### Commit URL Format
For most Azure DevOps instances, the correct commit URL format is detected automatically. If auto-detection doesn't work for your setup, you can specify it manually in the integration form.
**Recommended format (works with all Azure DevOps instances):**
`{web_url}/commit/{hash}`
The `{web_url}` placeholder automatically resolves to your full repository web URL including organization, project, and repository components.
**Alternative explicit format:**
`https://dev.azure.com/{owner}/{name}/commit/{hash}`
Note: This format may not work correctly if the project and repository cannot be properly parsed from your SSH URL. Use the `{web_url}` format for better reliability.
### Finding Your Repository URL
To find your repository's SSH URL:
1. Go to your repository in Azure DevOps
2. Click **Clone** button (top right)
3. Select **SSH** tab
4. Copy the URL (it will be in the format above)
## Troubleshooting
### SSH key not working
* Verify the **complete public key** was copied (including the `ssh-rsa` or `ssh-ed25519` prefix)
* Ensure the SSH key was added to the **correct user/service account**
* Confirm the account has **Read** permissions on the repository
### Connection refused
* Check that your organization's **IP restrictions** (if configured) include the Coalesce Quality egress IPs
* Verify the repository **SSH URL** uses the correct format: `git@ssh.dev.azure.com:v3/org/project/repo`
* Ensure the URL has `v3` in the path (required for Azure DevOps Git)
### Permission denied
* Verify the service account has **explicit Read permissions** on the repository
* Check that the account is not disabled or expired
* Ensure the SSH key is added to the same account that has repository access
### SSH URL format issues
* Azure DevOps requires a specific SSH URL format: `git@ssh.dev.azure.com:v3/org/project/repo`
* Do not use HTTPS URLs - only SSH URLs are supported
* The `v3` in the path is required
* Organization, project, and repository names are case-sensitive
## Security Best Practices
1. **Use a dedicated service account** for the integration
2. **Grant Read permissions only** - write access is never needed
3. **Regularly audit access** - Review service account permissions periodically
4. **Enable IP restrictions** - Limit access to the Coalesce Quality egress IPs
5. **Monitor access logs** - Check for unexpected authentication attempts
## Additional Resources
* [Azure DevOps SSH Authentication](https://learn.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate)
* [Azure DevOps IP Address Restrictions](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/change-application-access-policies)
* [Azure DevOps Git Repository Permissions](https://learn.microsoft.com/en-us/azure/devops/repos/git/set-git-repository-permissions)
* [Back to Integration Overview](/code-integrations/overview)
# Bitbucket Integration
Source: https://docs.synq.io/code-integrations/bitbucket
Add deploy keys to Bitbucket repositories for Coalesce Quality
## Overview
This guide covers how to add the generated public SSH key as an access key (deploy key) to your Bitbucket repository.
**Before you start:** Create your Git integration first by following the [integration form instructions](/code-integrations/overview#configuring-the-integration). You'll need the public SSH key from that integration.
## Prerequisites
* Access to Bitbucket Cloud or Bitbucket Server/Data Center
* **Admin access** to your repository (required to add access keys)
* Public SSH key from your Git integration
⏱️ **Estimated time:** 5 minutes
## IP Whitelisting (If Required)
If your Bitbucket workspace uses IP allowlisting, add the Coalesce Quality egress IP addresses for your region. See [IP Whitelist](/security/ip) for the complete list.
For instructions on configuring IP allowlisting in Bitbucket, see Bitbucket's guide on [IP allowlisting](https://support.atlassian.com/bitbucket-cloud/docs/control-access-to-your-private-content/).
## Adding the Access Key
Bitbucket CloudBitbucket Server/Data Center
### Bitbucket Cloud
Follow these steps to add an access key (deploy key) to your Bitbucket Cloud repository.
#### Navigate to Repository Settings
1. Go to your repository in Bitbucket Cloud
2. Click **Repository settings** (gear icon in the left sidebar)
#### Add Access Key
3. Under **Security**, click **Access keys**
4. Click **Add key**
5. Configure the access key:
* **Label:** Enter a descriptive name (e.g., `Coalesce Quality Integration`)
* **Key:** Paste the public SSH key from your integration
**Do not enable write access.** Only read-only access is required.
6. Click **Add SSH key**
That's it! Your Bitbucket repository is now connected in read-only mode.
#### Documentation
For more details, see Bitbucket's official guide on [Access Keys](https://support.atlassian.com/bitbucket-cloud/docs/add-access-keys/).
### Bitbucket Server/Data Center
Follow these steps to add an access key to your Bitbucket Server or Data Center repository.
#### Navigate to Repository Settings
1. Navigate to your repository in Bitbucket Server
2. Click **Repository settings** in the left sidebar
#### Add Access Key
3. Under **Security**, click **Access keys**
4. Click **Add key**
5. Configure the access key:
* **Key:** Paste the public SSH key from your integration
* **Permission:** Set to **Read** only
**Set permissions to Read only.** Write access is not required.
6. Click **Add key**
The access key is now active. Your Bitbucket repository is connected in read-only mode.
#### Documentation
For more details, see Bitbucket's documentation on [SSH Access Keys](https://confluence.atlassian.com/bitbucketserver/ssh-access-keys-for-system-use-776639781.html).
## Repository URL Format
When configuring the integration, use the SSH URL format for Bitbucket:
**Format:** `git@bitbucket.org:workspace/repository.git`
**Example:** `git@bitbucket.org:mycompany/analytics-platform.git`
For Bitbucket Server/Data Center, the format may vary:
* `git@bitbucket.example.com:project/repository.git`
* `ssh://git@bitbucket.example.com:7999/project/repository.git`
## Troubleshooting
### Access key not working
* Verify the **complete public key** was copied (including the `ssh-rsa` or `ssh-ed25519` prefix)
* Ensure the access key was added to the **correct repository**
* Confirm the key has **read-only permissions**
### Connection refused
* Check that your workspace's **IP allowlist** (if configured) includes the Coalesce Quality egress IPs
* Verify the repository **SSH URL** is correct in the integration form
* For **Bitbucket Server**, ensure the instance is accessible from the Coalesce Quality IP addresses
### No Repository Settings visible
* Confirm you have **admin access** to the repository
* Check with your Bitbucket administrator for access permissions
### SSH URL format issues
* Bitbucket Cloud uses: `git@bitbucket.org:workspace/repo.git`
* Bitbucket Server may use a custom port: `ssh://git@hostname:7999/project/repo.git`
* Do not use HTTPS URLs - only SSH URLs are supported
## Additional Resources
* [Bitbucket Cloud Access Keys Documentation](https://support.atlassian.com/bitbucket-cloud/docs/add-access-keys/)
* [Bitbucket Server SSH Access Keys](https://confluence.atlassian.com/bitbucketserver/ssh-access-keys-for-system-use-776639781.html)
* [Bitbucket IP Allowlisting](https://support.atlassian.com/bitbucket-cloud/docs/control-access-to-your-private-content/)
* [Back to Integration Overview](/code-integrations/overview)
# GitHub Integration
Source: https://docs.synq.io/code-integrations/github
Add deploy keys to GitHub repositories for Coalesce Quality
## Overview
This guide covers how to add the generated public SSH key as a deploy key to your GitHub repository.
**Before you start:** Create your Git integration first by following the [integration form instructions](/code-integrations/overview#configuring-the-integration). You'll need the public SSH key from that integration.
## Prerequisites
* Access to GitHub
* **Admin access** to your repository (required to add deploy keys)
* Public SSH key from your Git integration
⏱️ **Estimated time:** 5 minutes
## IP Whitelisting (If Required)
If your GitHub organization uses IP allow lists, add the Coalesce Quality egress IP addresses for your region. See [IP Whitelist](/security/ip) for the complete list.
For instructions on adding IP addresses to GitHub, see GitHub's guide on [managing allowed IP addresses](https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-allowed-ip-addresses-for-your-organization).
## Adding the Deploy Key
Follow these steps to add the public key as a deploy key to your GitHub repository.
### Navigate to Your Repository
1. In the upper-right corner of any GitHub page, click your **profile photo**, then click **Your profile**
2. On your profile page, click **Repositories**, then click the name of your repository
### Access Repository Settings
3. From your repository, click **Settings**
If you don't see the **Settings** tab, you likely don't have admin access to the repository. Contact your repository administrator to add the deploy key.
### Add the Deploy Key
4. In the sidebar, click **Deploy Keys**, then click **Add deploy key**
5. Configure the deploy key:
* **Title:** Enter a descriptive name (e.g., `Coalesce Quality Integration`)
* **Key:** Paste the public key from your integration (Step 1)
* **Allow write access:** Leave this checkbox **unticked** (unchecked)
**Do not grant write access.** Coalesce Quality only requires read-only access to your repository.
6. Click **Add key** to save the deploy key
That's it! Your GitHub repository is now connected in read-only mode.
## Troubleshooting
### Deploy key not working
* Verify the **complete public key** was copied (including the `ssh-rsa` or `ssh-ed25519` prefix)
* Ensure the deploy key was added to the **correct repository**
* Confirm **write access is disabled** (unchecked)
### Connection refused
* Check that your GitHub organization's **IP allow list** (if configured) includes the Coalesce Quality egress IPs
* Verify the repository **SSH URL** is correct in the integration form
### No Settings tab visible
* Confirm you have **admin access** to the repository
* Organization owners may need to adjust access permissions
## Additional Resources
* [GitHub Deploy Keys Documentation](https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys)
* [GitHub IP Allow Lists](https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-allowed-ip-addresses-for-your-organization)
* [Back to Integration Overview](/code-integrations/overview)
# GitLab Integration
Source: https://docs.synq.io/code-integrations/gitlab
Add deploy keys to GitLab projects for Coalesce Quality
## Overview
This guide covers how to add the generated public SSH key as a deploy key to your GitLab project.
**Before you start:** Create your Git integration first by following the [integration form instructions](/code-integrations/overview#configuring-the-integration). You'll need the public SSH key from that integration.
## Prerequisites
* Access to GitLab (GitLab.com or self-managed instance)
* **Maintainer or Owner access** to your project (required to add deploy keys)
* Public SSH key from your Git integration
⏱️ **Estimated time:** 5 minutes
## IP Whitelisting (If Required)
If your GitLab group uses IP address restrictions, add the Coalesce Quality egress IP addresses for your region. See [IP Whitelist](/security/ip) for the complete list.
For instructions on configuring IP restrictions in GitLab, see GitLab's guide on [IP address restrictions](https://docs.gitlab.com/ee/user/group/access_and_permissions.html#restrict-group-access-by-ip-address).
## Adding the Deploy Key
Follow these steps to add the public key as a deploy key to your GitLab project.
### Navigate to Repository Settings
1. On the top bar, select **Menu > Projects** and find your project
2. On the left sidebar, select **Settings > Repository**
If you don't see the **Settings** menu, you likely don't have Maintainer or Owner access to the project. Contact your project administrator to add the deploy key.
### Add the Deploy Key
3. Expand **Deploy keys**
4. Configure the deploy key:
* **Title:** Enter a descriptive name (e.g., `Coalesce Quality Integration`)
* **Key:** Paste the public key from your integration (Step 1)
* **Grant write permissions to this key:** Leave this checkbox **unticked** (unchecked)
**Do not grant write permissions.** Coalesce Quality only requires read-only access to your repository.
5. Click **Add key** to save the deploy key
The deploy key is enabled immediately upon creation. Your GitLab project is now connected in read-only mode.
## Troubleshooting
### Deploy key not working
* Verify the **complete public key** was copied (including the `ssh-rsa` or `ssh-ed25519` prefix)
* Ensure the deploy key was added to the **correct project**
* Confirm **write permissions are disabled** (unchecked)
### Connection refused
* Check that your GitLab group's **IP address restrictions** (if configured) include the Coalesce Quality egress IPs
* Verify the repository **SSH URL** is correct in the integration form
* For **self-managed GitLab**, ensure the instance is accessible from the Coalesce Quality IP addresses
### No Settings menu visible
* Confirm you have **Maintainer or Owner access** to the project
* Check with your GitLab administrator for access permissions
## Additional Resources
* [GitLab Deploy Keys Documentation](https://docs.gitlab.com/ee/user/project/deploy_keys/)
* [GitLab IP Address Restrictions](https://docs.gitlab.com/ee/user/group/access_and_permissions.html#restrict-group-access-by-ip-address)
* [Back to Integration Overview](/code-integrations/overview)
# Code Integration Requirements
Source: https://docs.synq.io/code-integrations/overview
Requirements and supported Git providers for code integrations
## Overview
Coalesce Quality integrates with your Git repositories to extract information about code changes across your data platform. The integration works with multiple frameworks and tools, including:
* **dbt** (Data Build Tool)
* **Looker** (LookML)
* **SQLMesh**
* **Coalesce** (Transform)
* **Custom entities**
* **Any other data transformation or analytics code**
By connecting your Git repositories, you can:
* **Display model changes** in the UI with optional diffs for quick inspection and troubleshooting
* **Show recent Git commits** for failing models in alerts, helping you identify what changed
* **Link code changes to data assets** for easier debugging
* **Understand the impact** of code changes on data quality
* **Track lineage** from code to data warehouse
* **Provide context** for data incidents with relevant code changes
## Supported Git Providers
Coalesce Quality works with **any Git provider** that supports SSH access. We provide native support and detailed guides for the following:
### Primary Supported Providers
* **GitHub** (Cloud and Enterprise)
* **GitLab** (Cloud and self-managed)
* **Bitbucket** (Cloud and Server/Data Center)
* **Azure DevOps Repos**
### Other Providers
* **Self-hosted Git** (Gitea, Gogs, etc.)
* **Any other SSH-based Git provider**
The unified integration form works with all SSH-based Git providers. Choose your provider below for specific deploy key setup instructions:
* [GitHub Integration](/code-integrations/github) - Deploy key setup for GitHub
* [GitLab Integration](/code-integrations/gitlab) - Deploy key setup for GitLab
* [Bitbucket Integration](/code-integrations/bitbucket) - Access key setup for Bitbucket
* [Azure DevOps Integration](/code-integrations/azure-devops) - SSH key setup for Azure DevOps
* [Other Git Providers](/code-integrations/ssh-git) - Self-hosted and other SSH-based Git
## Integration Requirements
Your Git provider must meet the following requirements:
### 1. Internet Accessibility
Your Git repository must be accessible over the internet. Access can be limited to static egress IP addresses for your region. See [IP Whitelist](/security/ip) for the complete list.
### 2. SSH Access
* Git repository must be accessible via **SSH** (typically port 22)
* Only SSH URLs are supported - HTTPS URLs will not work
* SSH deploy keys are used for secure, read-only access
### 3. Authentication
* Repositories must support authentication using **deploy keys** (SSH keys)
* Following the principle of least privilege, only **read-only access** to the selected repository is required
## IP Whitelisting
If your organization uses IP whitelisting for Git provider access, you'll need to add the Coalesce Quality egress IP addresses to your allowlist. Consult your provider's documentation for specific instructions:
### GitHub
* [Adding an Allowed IP Address to GitHub](https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-allowed-ip-addresses-for-your-organization)
### GitLab
* [IP Address Restrictions in GitLab](https://docs.gitlab.com/ee/user/group/access_and_permissions.html#restrict-group-access-by-ip-address)
## Setup Overview
Setting up a code integration involves two main steps:
1. **Configure the integration** using the universal Git integration form
2. **Add the deploy key to your Git provider** following provider-specific instructions
## Configuring the Integration
All Git providers use the same integration form. Navigate to **Settings > Add integration > Git** to get started.
### Integration Name
Provide a descriptive name for your integration.
**Examples:**
* `Production Analytics Repo`
* `Data Platform GitHub`
* `Bitbucket Staging`
### Repository URL (SSH)
Enter the SSH URL of your Git repository.
**Format:** `git@hostname:organization/repository.git`
**Examples:**
* GitHub: `git@github.com:myorg/analytics.git`
* GitLab: `git@gitlab.com:myorg/data-platform.git`
* Bitbucket: `git@bitbucket.org:myworkspace/dbt-project.git`
Only SSH URLs are supported. HTTPS URLs will not work.
### Branches to Analyse
Specify which branches to analyze.
* **Default:** Leave empty to automatically use `main` or `master`
* **Custom:** Enter specific branch names (e.g., `develop`, `staging`, `production`)
### Path to Analyse
Define the directory path where your source code is located.
* **Default:** Leave empty to analyze the entire repository
* **Custom:** Enter a subdirectory path (e.g., `analytics/`, `transform/dbt/`)
In most cases, analyzing the entire repository (default) is recommended.
### Commit URL Format (Optional)
For most Git providers (GitHub, GitLab, Bitbucket), the correct commit URL format is determined automatically. For custom or self-hosted instances, you may need to specify it manually.
**Available Placeholders:**
* `{owner}` - Repository owner/organization
* `{name}` - Repository name
* `{hash}` - Commit hash
* `{branch}` - Branch name
* `{web_url}` - Repository web URL
* `{provider}` - Git provider (github, gitlab, bitbucket, azuredevops)
**Format Examples:**
* **GitHub:** `https://github.com/{owner}/{name}/commit/{hash}`
* **GitLab:** `https://gitlab.com/{owner}/{name}/-/commit/{hash}`
* **Bitbucket:** `https://bitbucket.org/{owner}/{name}/commits/{hash}`
* **Custom:** `{web_url}/commit/{hash}` (works with most Git providers)
Leave this field empty unless you're using a custom Git instance that requires a specific URL format.
### Data Collection
**Store commit diff:** Enable this option (checked by default) to collect and display actual code changes in the Code & Changes screen.
### Create and Get Public Key
Click **Create** to generate the integration. After creation, navigate back to edit the integration to view the **public SSH key**.
The public key is generated when you create the integration but is only visible when you edit the integration afterward. Make sure to copy it before proceeding to add it to your Git provider.
## Access Permissions
**Admin access** to the repository is required to configure deploy keys. However, the deploy key itself only provides **read-only access** to the repository content. This ensures:
* Your code cannot be modified
* Access is limited to the specific repository
* No organization-wide permissions are granted
## Adding Deploy Keys to Your Git Provider
After creating the integration and copying the public SSH key, you need to add it as a deploy key in your Git provider. The process varies by provider.
Choose your Git provider for detailed setup instructions:
Add deploy key to GitHub repositories
Add deploy key to GitLab projects
Add access key to Bitbucket repositories
Add SSH key to Azure DevOps Repos
Self-hosted and other SSH-based Git
# Other Git Providers
Source: https://docs.synq.io/code-integrations/ssh-git
Add deploy keys to self-hosted and other SSH-based Git providers
## Overview
This guide covers how to add the generated public SSH key to self-hosted and other SSH-based Git providers, including:
* **Self-hosted Git** (Gitea, Gogs, GitBucket, etc.)
* **Any other SSH-based Git provider**
For GitHub, GitLab, Bitbucket, and Azure DevOps, see their dedicated setup guides:
* [GitHub Integration](/code-integrations/github)
* [GitLab Integration](/code-integrations/gitlab)
* [Bitbucket Integration](/code-integrations/bitbucket)
* [Azure DevOps Integration](/code-integrations/azure-devops)
**Before you start:** Create your Git integration first by following the [integration form instructions](/code-integrations/overview#configuring-the-integration). You'll need the public SSH key from that integration.
## Prerequisites
* Admin or appropriate access to configure SSH keys/deploy keys
* Public SSH key from your Git integration
* Git provider accessible over the internet via SSH
⏱️ **Estimated time:** 10-15 minutes
## Adding SSH Keys to Self-Hosted Git
The process for adding SSH keys to self-hosted Git instances varies by software, but generally follows this pattern:
### General Setup Steps
1. Navigate to your **repository settings** in your Git interface
2. Look for one of these sections:
* **Deploy Keys** (most common)
* **Access Keys**
* **SSH Keys**
3. Click **Add key** or similar button
4. Configure the key:
* **Title/Name:** Enter a descriptive name (e.g., `Coalesce Quality Integration`)
* **Key:** Paste the complete public SSH key from your integration
* **Permissions:** Select **Read-only** or equivalent
5. Save the key
Always configure the key with **read-only permissions**. Coalesce Quality never needs write access to your repository.
### Common Self-Hosted Git Platforms
1. Go to your repository in Gitea
2. Click **Settings** > **Deploy Keys**
3. Add the title and paste the public key
4. **Do not** check "Grant Write Access"
5. Click **Add Deploy Key**
For more details, see the [Gitea Documentation](https://docs.gitea.com/).
1. Navigate to your repository
2. Go to **Settings** > **Deploy Keys**
3. Enter a key name and paste the public key
4. Click **Add Deploy Key**
[Gogs Deploy Keys Documentation](https://gogs.io/)
1. Open your repository settings
2. Navigate to **Deploy Keys**
3. Add the title and public key
4. Set permission to **Read Only**
5. Click **Add**
[GitBucket Documentation](https://github.com/gitbucket/gitbucket)
For other self-hosted Git software:
1. Consult your Git software's documentation for SSH key or deploy key configuration
2. Look for repository-level SSH key settings (preferred over user-level keys)
3. Ensure the key is configured with read-only access
4. Test the connection after adding the key
Most Git software follows similar patterns to the examples above.
### Requirements for Self-Hosted Git
Ensure your self-hosted Git instance meets these requirements:
* **Internet accessible:** Must be reachable from the Coalesce Quality IP addresses
* **SSH enabled:** SSH protocol must be enabled (typically port 22)
* **Firewall configured:** Allow connections from the Coalesce Quality egress IPs
* **Valid SSL certificate:** If using HTTPS for the web interface
## IP Whitelisting (If Required)
If your Git provider uses IP whitelisting, add the Coalesce Quality egress IP addresses for your region. For self-hosted Git instances, configure your firewall to allow connections from these IP addresses.
See [IP Whitelist](/security/ip) for the complete list.
## Troubleshooting
### Deploy key/SSH key not working
* Verify the **complete public key** was copied (including the `ssh-rsa` or `ssh-ed25519` prefix)
* Ensure the key was added to the **correct repository or account**
* Confirm the key has **read-only permissions**
### Connection refused
* Check that **IP whitelisting** (if configured) includes the Coalesce Quality egress IPs
* Verify the repository **SSH URL** is correct in the integration form
* For **self-hosted Git**, ensure the instance is accessible from the Coalesce Quality IP addresses
### Self-hosted Git issues
* Confirm your Git instance is accessible over the **internet**
* Verify **firewall rules** allow connections from the Coalesce Quality IPs
* Check that **SSH is enabled** and listening on the expected port (usually 22)
* Test SSH connectivity: `ssh -T git@your-hostname.com`
## Additional Resources
* [IP Whitelist](/security/ip)
* [Back to Integration Overview](/code-integrations/overview)
* [GitHub Integration Guide](/code-integrations/github)
* [GitLab Integration Guide](/code-integrations/gitlab)
## Need Help?
If you're having trouble connecting your Git provider, [contact support](/support/support) with:
* Your Git provider type (Bitbucket, Azure DevOps, self-hosted, etc.)
* The SSH URL format you're using
* Any error messages from the connection attempt
# BI Status Badge
Source: https://docs.synq.io/data-products/bi-badge
Often, the best way to notify end-users of issues is directly in the tools they use on a daily basis. With BI status badges, you can display if there are any issues on or upstream of a chart directly in your BI tool.
### Creating a BI badge
* Navigate to [Products](https://app.synq.io/products)
* Select the data product that contains the assets that you want to display the status of in your BI tool and navigate to the `settings` tab
* Depending on your BI tool, copy the relevant Markdown or SVG URL
* Navigate to your BI tool and insert a widget that points to the URL above. The level of support for this may vary depending on the BI tool you use
**Looker example**
If you use Looker, click `Add > Markdown` and paste the Markdown URL from Coalesce Quality into the `Body`
* Your BI tool will show a tile with the status of the data product. Clicking on the tile brings you back to Coalesce Quality with an overview of the issues to connect the dots.
# Creating a data product
Source: https://docs.synq.io/data-products/creating-a-data-product
### Setting up a new data product
1. Navigate to [Products](https://app.synq.io/products) and click `Create product`
2. Name your data product (e.g., marketing KPIs) and set a priority (i.e., `P-1` for business-critical data)
3. Assign a folder to the data product. This is useful for grouping related data products (optional)
4. Use the `Assets selection` to find relevant assets. Use the browser to select or search for specific assets or annotations to select assets based on code definitions.
### Setting ownership of a data product
The Data Product owner is a person or team responsible for the data product. Owners can see an overview of everything they are responsible for and understand who the owners of critical data are downstream.
1. `Choose an owner` or `Create a new owner` to assign ownership to the data product. *When you create an owner, you also set how owners are notified of issues (e.g., which Slack channel)*
### Setting alerts on a data product
1. Toggle `Setup alerts` to active alerts for issues on the data product. Owners of the data product are notified based on the Slack or Email settings you’ve defined for the owner (see [Ownership overview](/ownership/ownership-overview))
* **Severity**—choose which type of issues alerts will include (e.g., check `warn` to be notified of warn-level test issues from dbt, SQLMesh, or Coalesce Transform)
* **Upstream issues**—check if you want to receive alerts about upstream issues that could be impacting your data product
* **Ongoing issues**—get notified about ongoing issues to ensure they get resolved (will result in more alerts)
# Data products overview
Source: https://docs.synq.io/data-products/data-products-overview
Coalesce Quality enables you to deploy relevant monitors, track uptime, and manage ownership of your business-critical data assets through Data Products
You should consider data products based on downstream use cases of your most important data. By setting up data products, you can head to `Products` for a complete overview of your products and their status.
*Data products showing the priority, owner, and status of all monitors and tests*
*Examples of data products are*
A set of transformation models and metrics within a specific folder, like a finance mart (e.g., dbt models, SQLMesh models, or Coalesce nodes).
A group of transformation models linked by an exposure, for instance, models used by a CLTV model that powers marketing automation.
A selected collection of dashboards in a BI tool, such as core KPI reporting.
A compilation of tables or transformation models that carry a common tag, like all 'P1' models that require high-priority management.
### Benefits of creating data products
Data products give you an easy way to manage the end reliability of your business-critical data.
* **Understand end-end health**—understand all monitors and tests on the data product and its upstream dependencies.
* **Set relevant monitors**—one-click monitor setup based on your data product definitions.
* **Define and activate ownership**—manage ownership and alerting on the data product level.
* **Communicate uptime & SLAs**—see historical issues and share insights around quality scores and test coverage of the data product.
### Understanding a data product
Data products are simple on the surface but complex under the hood. The key concepts to understand around a data product are `lineage`, `assets`, `definitions`, `historical uptime`, `product health`, and `upstream health`.
A Data Product has four sections:
1. **Overview**-key information about the data product assets, current status, and health over the past 15 days.
2. **Issues**-list all the issues that are currently affecting your data product.
3. **Lineage**-the relationships between your product's assets.
4. **Settings**-modify your product's name, alert settings, owner, and assets.
Data Product overview:
* **Summary**—platforms, priority, description, and a summary of the quality score and coverage
* **Related incidents & issues**—shows all issues and incidents on or upstream of the data product
* **Lineage**—data assets and data products up and downstream of the data product
* **Assets**—all data assets that are part of the data product definition
### Creating a data product
1. Go to [Creating a data product](/data-products/creating-a-data-product)
### Modifying or deleting a data product
1. Navigate to [Products](https://app.synq.io/products)
2. Click the three dots for the data product you want to modify and select `Settings` to edit it or `Delete` to delete it.
# dbt Cloud
Source: https://docs.synq.io/dbt-integrations/dbt-cloud
Integrating dbt Cloud with Coalesce Quality
This guide will walk you through how to create a service token and set up the relevant configurations for your dbt Cloud project
We need this information so we can connect to dbt and extract metadata such as runs and test failures. We only request read access to your metadata and won’t be able to read raw data or update or run any models.
In order to be able to finish this guide you’ll need:
→ Access to dbt cloud
→ Having been assigned the owner role in dbt cloud
⏱️ Estimated time to finish: 10 minutes.
## Name your integration
For example `dbt cloud`
## Set the API endpoint
The dbt Cloud default region is in the US but if you’re on the enterprise plan you can host your project in a different region. Select the region where your dbt Cloud project is hosted
* **Production (US):** [https://cloud.getdbt.com](https://cloud.getdbt.com) (*default*)
* **Production (Europe):** [https://emea.dbt.com](https://emea.dbt.com)
* **Production (AU):** [https://au.dbt.com](https://au.dbt.com)
## Generate a token
These steps will take you through how to create a token you can use to manage Coalesce Quality access to your dbt Cloud project
1. Open dbt cloud and go to **Account Settings** in the menu bar
* *If you don’t see this option in the sidebar you don’t have the right dbt permission. If this is the case, either ask your dbt admin to make you an **Owner** (expand to see how) or ask the dbt admin to complete the steps in this guide*
2. Click **Service Tokens**
3. Create **New Token**
4. **Name** your token
*This could be synq\_token so you can identify it later*
5. Click **Add** to add a new permission
6. Set permissions
* `Permission Set` should be set to **Read-Only.** This will let Coalesce Quality read your dbt logs
* `Project` should be set to your main dbt project. If you want to integrate multiple projects, add all projects you want to integrate or set to All Projects
7. **Save** the token
8. **Copy** the token value
Make sure to write the token id down as you will not be able to access it again afterwards
## Select your dbt project
Choose your main dbt project
## Select the job(s) you want Coalesce Quality to monitor
You’ll most likely want to monitor your production and freshness job(s). Unless you have a good reason, we suggest you don’t monitor jobs such as CI, staging, or experimental jobs
# FAQ
### What access do you require?
We only request read access to your metadata and won’t be able to read raw data or update or run any models
### Will you store personal or business-critical data
Coalesce Quality only stores log level data and doesn’t access any actual data from your data warehouse
### Which artifacts are you collecting from dbt
We are collecting the following artifacts from dbt. For more information about dbt artifacts see [this article](https://docs.getdbt.com/docs/dbt-cloud/using-dbt-cloud/artifacts)
* manifest.json — to understand the structure of the warehouse
* run\_results.json — to see the status of executions
* catalog.json — to be able to provide catalog-like functionality
* Optionally sources.json — to capture dbt source freshness
# dbt Core
Source: https://docs.synq.io/dbt-integrations/dbt-core
Integrating dbt Core with Coalesce Quality
This guide shows you how to connect your dbt Core project to Coalesce Quality to track model runs, test results, and metadata changes.
**Prerequisites:**
* Admin access to your Coalesce Quality workspace
* Ability to modify your dbt orchestration tool (Airflow, GitHub Actions, etc.)
⏱️ **Estimated time:** 15 minutes
Using dbt Cloud? You can integrate directly through **Settings → Integrations → Add Integration → dbt Cloud** instead of following this guide.
# Set up dbt Core integration
## Create integration in Coalesce Quality
1. Navigate to **Settings → Integrations → Add Integration**
2. Select **dbt Core** from the integration options
### Configure integration settings
**Integration name:** Enter a descriptive name (e.g., `Production dbt Core`)
**Generate token:** Click **Create** to generate your integration token. You'll use this token with the `synq-dbt` tool to send artifacts securely to Coalesce Quality.
**Git integration:** Select your Git provider to link model changes to repository commits. This enables change tracking and lineage visualization.
**Relative path to dbt:** If your dbt project isn't in the repository root, specify the directory path (e.g., `analytics/dbt/`).
## Manage integration tokens
Access token management through **Settings → Integrations**, then select your dbt Core integration and click **Manage tokens**.
From the token management screen, you can:
* Create new tokens for different environments
* Invalidate compromised tokens
* Copy token snippets for easy integration
# Install synq-dbt
## About synq-dbt
[`synq-dbt`](https://github.com/getsynq/synq-dbt) is a command-line wrapper that runs your existing dbt Core commands and automatically uploads artifacts to Coalesce Quality. It's version-agnostic — working with any dbt Core version by passing all arguments directly to your installed dbt — and integrates seamlessly with orchestration tools like Airflow, GitHub Actions, and Dagster.
**Collected artifacts:**
* `manifest.json` — Project structure and dependencies
* `run_results.json` — Execution status and performance metrics
* `catalog.json` — Complete data warehouse schema information
* `sources.json` — Source freshness test results
**How it works:**
1. Executes your locally installed dbt Core with all provided arguments (version-agnostic, passes arguments directly)
2. Captures the original dbt exit code
3. Reads your `SYNQ_TOKEN` environment variable
4. Uploads artifacts from the target directory to Coalesce Quality
5. Returns the original dbt Core exit code, even if upload fails (preserving pipeline behavior and ensuring CI/CD reliability)
## Installation methods
Choose the installation method that matches your dbt orchestration setup:
### Airflow with DockerOperator
1. **Set environment variable:** In Airflow UI, create a new environment variable `SYNQ_TOKEN` with your integration token.
2. **Update Dockerfile:**
```dockerfile theme={null}
ENV SYNQ_VERSION=v2.0.0
RUN wget -O /usr/bin/synq-dbt https://github.com/getsynq/synq-dbt/releases/download/${SYNQ_VERSION}/synq-dbt-amd64-linux && \
chmod +x /usr/bin/synq-dbt
```
3. **Update your operator:**
```python theme={null}
KubernetesPodOperator(
env_vars={
"SYNQ_TOKEN": Variable.get("SYNQ_TOKEN"),
# US: "SYNQ_API_ENDPOINT": "https://api.us.synq.io"; AU: "https://api.au.synq.io"
},
cmds=["synq-dbt"],
arguments=["build"], # Your dbt command here
# ... other configuration
)
```
**Linking dbt models to Airflow tasks:** To automatically link your dbt models with the Airflow tasks that execute them, see the [Airflow + dbt Core Linking guide](/orchestration-integrations/airflow-dbt-core). This enables bidirectional visibility between your orchestration and data layers.
### Airflow with dbt Plugin
1. **Set environment variable:** Create `SYNQ_TOKEN` in Airflow UI.
2. **Install synq-dbt:**
```shell theme={null}
export SYNQ_VERSION=v2.0.0
wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/download/${SYNQ_VERSION}/synq-dbt-amd64-linux
chmod +x ./synq-dbt && mv synq-dbt /usr/local/bin/synq-dbt
```
3. **Update DbtOperator:**
```python theme={null}
dbt_run = DbtRunOperator(
dbt_bin='synq-dbt',
env={
"SYNQ_TOKEN": Variable.get("SYNQ_TOKEN"),
# US: "SYNQ_API_ENDPOINT": "https://api.us.synq.io"; AU: "https://api.au.synq.io"
},
# ... other configuration
)
```
For linking dbt models to Airflow tasks, see the [Airflow + dbt Core Linking guide](/orchestration-integrations/airflow-dbt-core).
### Dagster
1. **Configure environment:** Add `SYNQ_TOKEN=` to your `.env` file. For US region workspaces also add `SYNQ_API_ENDPOINT=https://api.us.synq.io`, and for AU `https://api.au.synq.io`.
2. **Update resources in `definitions.py`:**
```python theme={null}
resources = {
"dbt": DbtCliResource(
dbt_executable='synq-dbt',
project_dir=os.fspath(dbt_project_dir)
),
}
```
3. **Update assets in `assets.py`:**
```python theme={null}
@dbt_assets(manifest=dbt_manifest_path)
def jaffle_shop_dbt_assets(context: AssetExecutionContext, dbt: DbtCliResource):
dbt_target_path = Path('target')
yield from dbt.cli(["build"], target_path=dbt_target_path, context=context).stream()
```
### Docker
Add to your Dockerfile:
```dockerfile theme={null}
ENV SYNQ_VERSION=v2.0.0
RUN wget -O /usr/bin/synq-dbt https://github.com/getsynq/synq-dbt/releases/download/${SYNQ_VERSION}/synq-dbt-amd64-linux && \
chmod +x /usr/bin/synq-dbt
```
### Linux/macOS
**Download and install:**
```shell theme={null}
# For Linux
export SYNQ_VERSION=v2.0.0
wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/download/${SYNQ_VERSION}/synq-dbt-amd64-linux
# For macOS
wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/download/${SYNQ_VERSION}/synq-dbt-arm64-darwin
# Make executable and move to PATH
chmod +x ./synq-dbt && mv synq-dbt /usr/local/bin/synq-dbt
# Set your token and test
export SYNQ_TOKEN=
synq-dbt --version
```
# Use synq-dbt
## Basic usage
Replace your existing dbt Core commands with `synq-dbt`:
```shell theme={null}
# Instead of: dbt run --select finance --threads 5
synq-dbt run --select finance --threads 5
# Instead of: dbt test --select reports
synq-dbt test --select reports
# Instead of: dbt build
synq-dbt build
```
All dbt Core arguments and options work exactly the same way.
## Upload existing artifacts
If you have already generated dbt artifacts and want to upload them to Coalesce Quality:
```shell theme={null}
export SYNQ_TOKEN=
synq-dbt synq_upload_artifacts
```
**Include dbt logs:**
```shell theme={null}
dbt build | tee dbt.log
synq-dbt synq_upload_artifacts --dbt-log-file dbt.log
```
## Configuration options
**Environment variables:**
* `SYNQ_TOKEN` — Your integration token (required)
* `SYNQ_TARGET_DIR` — Artifact directory path (default: `target/`)
* `SYNQ_API_ENDPOINT` — API endpoint for your region (required outside EU)
**Regional configuration:**
EU region customers (default) don't need to set `SYNQ_API_ENDPOINT`. US and AU region customers must configure it.
For **US region** workspaces, set the API endpoint:
```shell theme={null}
export SYNQ_API_ENDPOINT=https://api.us.synq.io
```
For **EU region** workspaces (default), no additional configuration needed — the tool automatically uses `https://developer.synq.io`.
**Network requirements:**
* Allow outbound HTTPS traffic to `developer.synq.io:443` (EU), `api.us.synq.io:443` (US) or `api.au.synq.io:443` (AU)
**Data visibility:**
* Artifacts appear in Coalesce Quality within minutes of upload under normal conditions
* Failed uploads are logged and can be retried
* Typical payload sizes range from several megabytes to tens of megabytes depending on project size
For advanced configuration options and troubleshooting, see the [synq-dbt GitHub repository](https://github.com/getsynq/synq-dbt).
# Coalesce Quality options for dbt
Source: https://docs.synq.io/dbt-integrations/synq-options
Customize how dbt resources appear in Coalesce Quality using meta configuration
This guide explains how to use dbt's `meta` configuration to customize how your dbt resources are displayed and categorized in Coalesce Quality.
**Prerequisites:**
* A working dbt Core or dbt Cloud integration with Coalesce Quality
* Familiarity with dbt's [meta configuration](https://docs.getdbt.com/reference/resource-configs/meta)
# Overview
Coalesce Quality reads custom metadata from your dbt project's `meta` configuration to enhance how resources are displayed and organized. By adding specific options to your dbt models and tests, you can:
* Categorize tests into specific Check categories
* Improve organization and filtering in the Coalesce Quality interface
# Check category
Use the `check_category` option to assign a dbt test to a specific Check category in Coalesce Quality. This is useful for organizing standalone dbt tests (generic or singular) into meaningful groups.
## Configuration
Add the `synq` configuration to your test's `meta` block:
```sql theme={null}
{{ config(
meta = {
'synq': {'check_category': 'e2e'}
}
)
}}
```
## Example: Singular test
For a singular test file (e.g., `tests/e2e_order_flow.sql`):
```sql theme={null}
{{ config(
meta = {
'synq': {'check_category': 'e2e'}
}
)
}}
-- Test that verifies the complete order flow from creation to fulfillment
SELECT order_id
FROM {{ ref('orders') }}
WHERE status = 'created'
AND created_at < CURRENT_TIMESTAMP - INTERVAL '24 hours'
AND fulfilled_at IS NULL
```
## Example: Generic test in schema.yml
For generic tests defined in your schema files:
```yaml theme={null}
models:
- name: orders
columns:
- name: order_id
tests:
- unique:
meta:
synq:
check_category: 'data-quality'
- not_null:
meta:
synq:
check_category: 'data-quality'
```
## Example: Custom generic test
For custom generic tests, add the config at the top of the test file:
```sql theme={null}
{% test custom_validation(model, column_name) %}
{{ config(
meta = {
'synq': {'check_category': 'validation'}
}
)
}}
SELECT {{ column_name }}
FROM {{ model }}
WHERE {{ column_name }} IS NOT NULL
AND NOT {{ column_name }} REGEXP '^[A-Z]{2}[0-9]{6}$'
{% endtest %}
```
# How it works
Coalesce Quality automatically categorizes dbt tests based on the test type and package (e.g., `dbt`, `dbt_expectations`, `dbt_utils`). However, for singular tests or custom generic tests, it may not be able to determine the appropriate category automatically.
Using `check_category` allows you to:
* Override the automatic categorization for any test
* Assign meaningful categories to singular tests that would otherwise be uncategorized
* Group related tests together for better filtering and analysis in Coalesce Quality
# Custom categories
You can use any category name that makes sense for your organization. Common examples:
| Category | Description |
| ---------------- | ------------------------------------------------------ |
| `e2e` | End-to-end tests that validate complete workflows |
| `data-quality` | Tests for data completeness, accuracy, and consistency |
| `business-rules` | Tests that enforce business logic and constraints |
| `reconciliation` | Tests that compare data across sources |
| `validation` | Input validation and format checks |
| `sla` | Service level agreement compliance tests |
# Default categories
Coalesce Quality automatically assigns the following categories to known test types from `dbt`, `dbt_expectations`, `dbt_utils`, and other packages:
| Category | Description |
| ------------------ | ---------------------------------------------------- |
| `accepted_values` | Tests that validate values are within an allowed set |
| `nullness` | Tests for null or not-null constraints |
| `unique` | Uniqueness validation tests |
| `relationships` | Referential integrity and foreign key tests |
| `freshness` | Data timeliness and recency tests |
| `row_count` | Row count validation and volume tests |
| `range_validation` | Tests that check values are within expected ranges |
| `comparison` | Tests comparing values between columns or tables |
| `structure` | Schema structure and column existence tests |
| `match_regex` | Pattern matching and regex validation tests |
Setting `check_category` will override the default categorization for any test.
# Best practices
1. **Use custom categories** to group tests by business domain or testing strategy
2. **Be consistent** with category names across your project
3. **Document your categories** so team members understand what each category represents
# DWH Agent
Source: https://docs.synq.io/dw-integrations/agent
Integrating to databases via on-premise installed Coalesce Quality agent
This guide explains how to configure the Coalesce Quality Data Warehouse agent installed on-premise.
When possible, use standard integration methods as they are much simpler and provide full functionality.
Reach out to us for installation details.
## Data we collect
For the automated data anomaly testing, we collect the following:
* Number of rows in every table in the monitored dataset(s)
* Timestamp of the last change of data in all tables in the monitored dataset(s)
**We provide built-in monitors for data volume and freshness without accessing your actual data. However, for custom monitors, the agent needs access to query your raw data. Only the aggregated results are sent to the platform.**
# Setup DWH Agent integration
1. In the app, navigate to Data Sources and click "Add integration"
2. Select "On-premise DWH Agent" from the list of available integrations
3. Enter a title for your integration (e.g., "Production DWH Agent")
4. Click "Create". You will receive:
* `client_id`
* `client_secret`
Save these credentials - you'll need them to configure the agent in the next section.
Keep your client credentials secure. They allow the agent to authenticate with
the platform.
# Agent Configuration
Agent is configured via `agent.yaml` file or through environment variables.
## Example configuration:
```yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-dwh/v1/config.schema.json
synq:
client_id: "xxxx-xxxx-xxxx-xxx"
client_secret: "${SYNQ_CLIENT_SECRET}"
connections:
"pg-local":
name: "PG Local"
postgres:
host: 1.2.3.4
port: 54320
username: postgres
password: ${PG_PASSWORD}
database: db
allow_insecure: true
"bq-nifty-motif-341212":
bigquery:
project_id: big-query-project-id
region: europe-west2
"ch-staging":
name: Clickhouse
clickhouse:
host: host.clickhouse.cloud
port: 9440
username: default
password: ${STAGING_CLICKHOUSE_PASSWORD}
"prod-snowflake":
disabled: true
snowflake:
username: "SYNQ"
password: "${SNOWFLAKE_DWH_PASSSWORD}"
account: "snowflake-account"
warehouse: "SYNQ_WH"
databases: ["DB"]
role: "SYNQ_ROLE"
use_get_ddl: true
```
For details about all available configuration options, refer to the [JSON Schema](https://schemas.synq.io/synq-dwh/v1/config.schema.json) or the [HTML documentation](https://schemas.synq.io/synq-dwh/v1/config.html).
# BigQuery
Source: https://docs.synq.io/dw-integrations/bigquery
Integrating BigQuery with Coalesce Quality
This guide explains how to connect Coalesce Quality to BigQuery securely.
We need this information so we can collect relevant data about your tables.
To be able to finish this guide, you’ll need the following:
→ Access to modify your BigQuery configuration
⏱️ Estimated time to finish: 10 minutes.
## Data we collect
For the automated data anomaly testing, we collect the following:
* Number of rows in every table in the monitored dataset(s)
* Timestamp of the last change of data in all tables in the monitored dataset(s)
**To provide out-of-the-box monitors for volume and freshness, we don’t require access to your actual data. For custom monitors, however, access to query your raw data is required.**
Permission overview:
| Permission | Description | Included in BQ role | Purpose |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | --------------------------------------------------- |
| bigquery.datasets.get | Get metadata about a dataset. | Data Viewer | automated / custom monitors |
| bigquery.datasets.getIamPolicy | Required by the Cloud Console to give the user the option of getting a dataset's IAM permissions. Fails open. The ability to actually perform the operation of getting the permissions is gated by the bigquery.datasets.get permission. | Data Viewer | automated / custom monitors |
| bigquery.jobs.create | Run jobs (including queries) within the project. | Job User | automated / custom monitors |
| bigquery.jobs.get | Get data and metadata on any job — required to retrieve the result of the metadata queries we submit. | Job User | automated / custom monitors |
| bigquery.jobs.list | List all jobs and retrieve metadata on any job submitted by any user. For jobs submitted by other users, details and metadata are redacted. | Resource Viewer | query logs |
| bigquery.jobs.listAll | List all jobs and retrieve metadata on any job submitted by any user. | Resource Viewer | query logs |
| bigquery.tables.get | Get table metadata. | Data Viewer | automated monitors |
| bigquery.tables.getData | Get table data. | Data Viewer | custom monitors (optional — skip for metadata-only) |
| bigquery.tables.list | List tables and metadata on tables. | Data Viewer | automated / custom monitors |
| bigquery.routines.get | Get metadata for user-defined functions, table-valued functions and stored procedures. | Data Viewer | connection validation only |
| bigquery.routines.list | List routines in a dataset. | Data Viewer | connection validation only |
| resourcemanager.projects.get | | Data/Jobs/Resource Viewer | All |
# Setup BigQuery access
### Create a dedicated Coalesce Quality role
1. Select the project with your BigQuery instance in the project picker.
2. Go to `IAM and Admin` → `Roles` → `Create Role`.
3. Fill in:
* Title: `Coalesce Quality Monitoring`
* Description: `Coalesce Quality Monitoring role`
* Role launch stage: `General Availability`
4. Click `Add permissions` and add:
```yaml theme={null}
bigquery.datasets.get
bigquery.datasets.getIamPolicy
bigquery.jobs.create
bigquery.jobs.get
bigquery.jobs.list
bigquery.jobs.listAll
bigquery.tables.get
bigquery.tables.getData
bigquery.tables.list
bigquery.routines.get
bigquery.routines.list
resourcemanager.projects.get
```
5. Click `Create`.
### Create a service account
1. Go to `IAM and Admin` → `Service Accounts` → `Create Service Account`.
2. Fill in:
* Service account name: `synq-monitoring`
* Service account description: `Coalesce Quality Monitoring Service Account`
3. Click `Create and continue`.
4. In section *Grant this service account access to the project*, select the previously created `Coalesce Quality Monitoring` role, then click `Done`.
### Create a service account key
1. Open your newly created service account and switch to the `Keys` tab.
2. Click `Add key` → `Create new key`, choose **JSON**, and click `Create`.
3. Store the downloaded JSON key file securely.
## Personal access (user OAuth)
In addition to the workspace service account above, you can let each Coalesce Quality member authenticate as themselves against BigQuery. Queries then run under the member's own Google identity and respect the IAM grants on that user. See [Data Warehouse Access](/security/dwh-access) for the full model and when to enable it.
To enable personal access, a Google Cloud admin creates a single OAuth 2.0 Client ID once, then pastes the client ID and secret into the BigQuery integration's edit page in Coalesce Quality.
### Configure branding
Skip this step if your project's Google Auth Platform is already configured.
1. In the Google Cloud console for the project that will host the OAuth app, go to `Google Auth Platform` → `Branding`.
2. Fill in the app name (e.g. `Coalesce Quality`), user support email, and developer contact.
3. Save.
### Choose the audience
1. Go to `Google Auth Platform` → `Audience`.
2. **User type**: pick `Internal` if every Coalesce Quality member has a Google account in your Workspace organisation, otherwise `External`.
If you use `External` and stay in **Testing** mode, Google caps refresh tokens at 7 days — members will need to re-consent weekly. Promote the publishing status to **Production** (or use `Internal`) for long-lived access.
### Create the OAuth client
1. Go to `Google Auth Platform` → `Clients` → `Create client`.
2. **Application type**: `Web application`.
3. **Name**: e.g. `Coalesce Quality`.
4. Under **Authorised redirect URIs**, add the URI(s) for the Coalesce Quality region(s) your members use, with no trailing slash:
* EU: `https://app.synq.io/auth/dwh-oauth/callback`
* US: `https://app.us.synq.io/auth/dwh-oauth/callback`
* AU: `https://app.au.synq.io/auth/dwh-oauth/callback`
5. Click `Create`. Copy the **Client ID** and **Client secret**.
### Enable the BigQuery API
In the same project, go to `APIs & Services` → `Library`, search for **BigQuery API**, and click `Enable` (already enabled if you scrape BigQuery from this project).
### Paste credentials into Coalesce Quality
In Settings → Integrations → *(your BigQuery integration)* → Warehouse access → Personal credentials, paste the Client ID and Client secret. Members will then see this BigQuery integration listed under Settings → Warehouse access → My credentials and can connect their own Google account.
Coalesce Quality requests two OAuth scopes during member consent: `https://www.googleapis.com/auth/bigquery` (BigQuery access — required to run queries, which BigQuery executes as jobs) and `https://www.googleapis.com/auth/userinfo.email` (to label the connected account in the UI). Member queries are also bounded by each member's IAM grants — the OAuth scope is the outer limit, not the policy, so a member with read-only IAM permissions still can only read.
## Network Configuration
If your BigQuery project has firewall rules or VPC configurations that restrict access, you may need to whitelist our IP addresses. See [Coalesce Quality IP Whitelist](/security/ip) for the complete list of IP addresses by region.
Once you've successfully completed these steps, input the following data in the platform.
## Input data in the Coalesce Quality UI
### Integration name
For example `BigQuery`
### Project ID
Open the project picker at the top of the Google Cloud console and copy the **ID** column value for your project.
### Service account key
The content of the JSON file you created earlier in the guide
### Region
Location of your BigQuery instance (typically US or EU)
### Blacklisted datasets (optional)
Comma-separated list of dataset name patterns to exclude from ingestion. Use `*` to match any string, e.g. `dbt_pr_*`.
### Datasets (optional)
Comma-separated list of dataset names to scrape explicitly (e.g. `analytics, mart_core`). When set, only these datasets are queried and the service account does **not** need the project-level `bigquery.datasets.list` permission — this lets you grant the Coalesce Quality Monitoring role on individual datasets instead of the whole project.
Leave empty to auto-discover every visible dataset in the project.
### Audit table FQN (optional)
Fully-qualified table name (e.g. `my-project.analytics.synq_sql_test__audit`) where Coalesce Quality writes SQL test execution results. The integration creates the table automatically if it does not yet exist. Leave empty if you do not run SQL tests.
Using this field requires two extra permissions on the target dataset that are **not** in the default role above: `bigquery.tables.create` and `bigquery.tables.updateData`. Add them to the Coalesce Quality Monitoring role (or grant them just on the audit dataset) before enabling the feature.
### Fetch query logs (recommended)
Enables ingestion of query history from `INFORMATION_SCHEMA.JOBS`, which powers anomaly-monitor training, data-usage insights, unused-table detection, and cost signals. Expect a small additional query cost (typically a few dollars per month).
# ClickHouse
Source: https://docs.synq.io/dw-integrations/clickhouse
Integrating ClickHouse with Coalesce Quality
Coalesce Quality has deep ClickHouse support. In fact, our platform is built on ClickHouse. See the talk by our CEO: [Building a Unified Data Platform with ClickHouse](https://clickhouse.com/blog/building-a-unified-data-platform-with-clickhouse)
Get in touch with us to integrate ClickHouse in your workspace.
# Databricks
Source: https://docs.synq.io/dw-integrations/databricks
Integrating Databricks with Coalesce Quality
This guide details the steps to integrate Coalesce Quality with Databricks using the Unity Catalog feature. This integration enables efficient data observability and management across your Databricks environment.
Before proceeding, ensure you have:
* Administrative access to your Databricks workspace
* Permissions to manage Unity Catalog settings
⏱️ Estimated time to complete: 10 minutes.
## Integration Overview
Integrating with Databricks through Unity Catalog allows you to monitor and manage data reliability and quality directly within your Databricks environment.
## Prerequisites
* **Databricks Workspace URL**: The URL of your Databricks workspace where Unity Catalog is configured.
* **OAuth Client ID and Client Secret** / **Access Token**: A Databricks credentials with permissions to access to monitored catalogs.
* **Warehouse ID**: The identifier for the SQL warehouse within Databricks that will be used to run monitoring queries. We recommend using Serverless SQL Warehouses.
## Step-by-Step Guide
### Step 1: Configuring Unity Catalog
1. **Log in to your Databricks workspace**:
Navigate to your Databricks workspace by entering the Workspace URL in your browser.
2. **Access the Unity Catalog**:
From the sidebar, select 'Data' and then 'Unity Catalog' to configure the data catalog settings.
3. **Create or Select a Catalog**:
Choose an existing catalog or create a new one for the integration to operate on.
### Step 2: Create authentication method
#### Option 1: Using Service Principal and OAuth (recommended)
1. **Create Service Principal**:
Navigate to the 'Admin Console' and select 'Identity and access' > 'Service Principals' > 'Manage'. Click on 'Add Service Principal' > 'Add new' and provide the name of the service principal. Note the generated Service Principal ID.
2. **Generate OAuth Secret**:
Click on the created Service Principal, go to the Secrets tab and click on 'Generate secret'. Note the generated OAuth token securely.
3. **Assign Permissions**:
Assign the necessary permissions to the Service Principal to access the Unity Catalog and other required resources.
```SQL theme={null}
GRANT USE CATALOG ON CATALOG TO ``;
GRANT USE SCHEMA ON CATALOG TO ``;
GRANT SELECT ON CATALOG TO ``;
```
These catalog grants are enough to read metadata and run monitoring queries, but they are **not** enough to build column- and table-level lineage. See [Query log lineage permissions](#query-log-lineage-permissions) below.
#### Option 2: Using Personal Access Token (not recommended)
1. **Navigate to the User Settings**:
Click on your profile at the bottom left corner and select 'User Settings'.
2. **Access Tokens**:
Go to the 'Access Tokens' tab and click on 'Generate New Token'.
Enter a description, set the expiration according to your policy, and note the generated token securely.
### Step 3: Configure the Integration
1. **Log in to Coalesce Quality**:
Access your dashboard.
2. **Add Databricks as an Integration**:
Navigate to 'Data Sources', select 'Add integration', and choose 'Databricks'.
3. **Enter Integration Details**:
Provide the Workspace URL, Access Token, and Warehouse ID to establish the connection.
4. **Network Configuration**:
If your Databricks workspace has network access controls or firewall restrictions, you may need to whitelist our IP addresses. See [Coalesce Quality IP Whitelist](/security/ip) for the complete list of IP addresses by region.
5. **Set Exclusion Rules**:
Define any exclusion rules for catalogs, schemas, and tables to tailor the monitoring to your needs.
## Query log lineage permissions
Coalesce Quality derives cross-table lineage from your Databricks **query history**: it reads the executed statements (such as `CREATE TABLE AS SELECT` and `MERGE`) and parses the relationships between source and target tables. Views are the exception — they carry their own SQL definition, so they show lineage without query history.
Databricks query history is permission-scoped. A service principal (or user) sees:
* its **own** queries; plus
* queries that ran on a SQL warehouse it has at least **CAN VIEW** access to.
A workspace admin sees all queries.
This means the catalog grants above are not sufficient on their own. Without warehouse access, the integration sees only the queries it runs itself, so the statements that build your tables stay invisible and **no lineage is produced**.
To enable lineage, grant the service principal access to the query history of the warehouse(s) where your transformations run. Choose one of:
* Grant **CAN VIEW** (or **CAN MANAGE**) on each SQL warehouse that executes your transformations, via the warehouse's **Permissions** settings, **or**
* Make the service principal a **workspace admin** (broadest, simplest).
Query history only covers queries executed on **SQL warehouses**. Statements that run on all-purpose clusters, Jobs compute, or Delta Live Tables / Lakeflow pipelines do not appear in query history regardless of permissions — so make sure the transformations you want lineage for run on a SQL warehouse.
## Personal access (user OAuth)
In addition to the workspace service principal above, you can let each Coalesce Quality member authenticate as themselves against Databricks. Queries then run under the member's own Databricks user and respect the Unity Catalog grants on that user. See [Data Warehouse Access](/security/dwh-access) for the full model and when to enable it.
To enable personal access, a Databricks **account admin** registers a custom OAuth app once at the account level, then pastes the client ID and secret into the Databricks integration's edit page in Coalesce Quality. The same app can be reused across every workspace in the account.
### Register the OAuth app in Databricks
1. Sign in to the [Databricks Account Console](https://accounts.cloud.databricks.com) (`accounts.cloud.databricks.com` for AWS, `accounts.azuredatabricks.net` for Azure, `accounts.gcp.databricks.com` for GCP) as an account admin.
2. Open `Settings` → `App connections` → `Add connection`.
3. Fill in:
* **Name**: e.g. `Coalesce Quality`.
* **Redirect URLs** — add the URL(s) for the Coalesce Quality region(s) your members use, with no trailing slash:
* EU: `https://app.synq.io/auth/dwh-oauth/callback`
* US: `https://app.us.synq.io/auth/dwh-oauth/callback`
* AU: `https://app.au.synq.io/auth/dwh-oauth/callback`
* **Access scopes**: `all-apis` and `offline_access`.
* Mark the app as **Confidential** (Coalesce Quality stores the client secret server-side).
4. Save. Copy the **Client ID** and **Client secret** — the secret is shown only once.
If your Databricks tier exposes app connections at the workspace level as well (`/settings` → `Developer` or `Identity and access` → `App connections`), either surface works — the resulting OAuth app is the same. Account-level registration is the recommended path because the app then covers every workspace in the account.
Coalesce Quality builds the authorize URL automatically from the workspace URL you configured on the integration (`/oidc/v1/authorize`) — you don't need to enter the authorize endpoint anywhere.
### Grant Unity Catalog access to your members
Personal access uses each member's own Unity Catalog grants — the OAuth app itself does not need catalog grants. Make sure every member who will use this path has at least:
```sql theme={null}
GRANT USE CATALOG ON CATALOG TO ``;
GRANT USE SCHEMA ON CATALOG TO ``;
GRANT SELECT ON CATALOG TO ``;
```
Members also need access to the SQL warehouse configured on the integration — `CAN USE` on the warehouse is enough.
### Paste credentials into Coalesce Quality
In Settings → Integrations → *(your Databricks integration)* → Warehouse access → Personal credentials, paste the Client ID and Client secret. Members will then see this Databricks integration listed under Settings → Warehouse access → My credentials and can connect their own Databricks user.
## Conclusion
Once configured, the platform will begin monitoring the specified data assets within Databricks, leveraging Unity Catalog for enhanced data management and observability.
For further assistance, contact our support team.
# Microsoft Fabric
Source: https://docs.synq.io/dw-integrations/fabric
Integrating Microsoft Fabric with Coalesce Quality
This guide explains how to connect Coalesce Quality to a Microsoft Fabric workspace securely.
We need this information so we can collect metadata about the tables in your Fabric Warehouses and Lakehouses.
To finish this guide, you'll need the following:
→ Permission to register a Microsoft Entra application (service principal) in your tenant, or an admin who can
→ A **Fabric administrator** to enable the tenant setting that lets service principals call Fabric
→ A workspace **admin** to give the service principal a role on the workspace (**Contributor** for the full feature set, including query history)
⏱️ Estimated time to finish: 15 minutes.
Microsoft Fabric exposes each workspace through a shared **SQL analytics endpoint** that speaks T-SQL. Coalesce Quality connects to that endpoint to read the metadata of every Warehouse and Lakehouse in the workspace. A single integration covers the whole workspace — each Warehouse / Lakehouse appears as a database, and Coalesce Quality queries across them using three-part `[database].[schema].[table]` names.
Authentication is via a Microsoft Entra ID **service principal**. Fabric does not accept SQL logins, so this is the only way to connect a headless integration.
## Data we collect
We read metadata from your workspace's SQL analytics endpoint using the dedicated service principal described below. Depending on which features you enable in the integration, we ingest:
* **Catalog** — the workspace's databases (Warehouses and Lakehouse SQL endpoints), schemas, tables, views, columns, data types, and constraints. Fabric constraints (primary key / unique / foreign key) are informational (`NOT ENFORCED`) but are still read from metadata.
* **SQL definitions** — the T-SQL of views, stored procedures, and functions. Used for lineage and to detect references between objects.
* **Table metrics** — row counts and last-modified timestamps for anomaly detection, collected for the tables in scope (see **Metrics scope** below).
* **Query history** *(recommended, on by default)* — read from the workspace's `queryinsights` system views for cost attribution and SQL / column-level lineage. Management-plane reads only — no per-query billing. Requires the service principal to have the **Contributor** (or higher) workspace role — see [Give the service principal a role on the workspace](#3-give-the-service-principal-a-role-on-the-workspace).
**Metadata only.** The service principal below only needs to read your **schema and DDL**, never row data. Coalesce Quality issues data-reading queries (row counts, samples for monitors) only when you enable the corresponding opt-in feature in the integration UI. With every opt-in disabled, the integration runs metadata queries only.
## Set up access
### 1. Register an Entra service principal
The integration authenticates as a Microsoft Entra application (service principal) with a client secret. You can create one in the [Entra admin center](https://entra.microsoft.com) (**App registrations → New registration**), or with the Azure CLI:
```bash theme={null}
# Sign in to your tenant
az login --tenant
# 1. Create the app registration
APP_ID=$(az ad app create \
--display-name "coalesce-quality-fabric-scraper" \
--sign-in-audience AzureADMyOrg \
--query appId -o tsv)
echo "Client (application) ID: $APP_ID"
# 2. Create the service principal for that app
az ad sp create --id "$APP_ID"
# 3. Mint a client secret (the value is shown only once — store it securely)
az ad app credential reset \
--id "$APP_ID" \
--display-name "coalesce-quality" \
--years 1 \
--query "{clientId:appId, clientSecret:password, tenantId:tenant}" -o json
```
Take note of the **Client ID**, **Client secret**, and **Tenant ID** — you'll enter them in the Coalesce Quality UI.
### 2. Allow service principals to use Fabric
A **Fabric administrator** must enable this once for the tenant:
1. Open the [Fabric admin portal](https://app.fabric.microsoft.com/admin-portal) → **Tenant settings → Developer settings**.
2. Enable **"Service principals can use Fabric APIs"**.
3. We recommend scoping it to a security group that contains only this service principal, to keep the blast radius small.
Without this setting the service principal cannot obtain a Fabric token and every connection fails.
### 3. Give the service principal a role on the workspace
A workspace admin adds the service principal to the workspace that holds the Warehouses / Lakehouses you want to monitor. Open the workspace → **Manage access → Add people or groups**, search for the app registration by name, and assign a role.
Which role you need depends on the features you enable:
| Feature | Minimum access |
| --------------------------------------------------------- | --------------------------------------------------------------------- |
| Databases, schemas, tables, columns, constraints | **Viewer** |
| View / procedure / function **SQL definitions** (lineage) | **Viewer** + `GRANT VIEW DEFINITION` (see step 4), or **Contributor** |
| **Table metrics** and monitor samples (row data) | **Viewer** + `GRANT SELECT` (see step 4), or **Contributor** |
| **Query history** (`queryinsights`) | **Contributor**, Member, or Admin |
We recommend **Contributor** — it covers every feature, including query history, with no extra SQL grants. Query history in particular reads Fabric's `queryinsights` system views, which are **only accessible to Contributor / Member / Admin**; a Viewer cannot read them even with SQL grants.
Choose **Viewer** only for tightest least privilege, and add the SQL grants in step 4 to recover SQL definitions and metrics. Query history is not available to a Viewer.
### 4. (Optional) Least-privilege SQL grants for a Viewer
If you assigned **Viewer** rather than Contributor, grant the service principal exactly what the enabled features read. Run this in each Warehouse you monitor, using the app registration's display name — Fabric resolves the Entra principal by name, so no separate user-creation step is needed:
```sql theme={null}
GRANT VIEW DEFINITION TO [coalesce-quality-fabric-scraper]; -- SQL definitions / lineage
GRANT SELECT TO [coalesce-quality-fabric-scraper]; -- only if table metrics / samples are enabled
```
These grants cannot unlock query history: `queryinsights` is gated by the workspace role, so leave the service principal on **Contributor** (or higher) if you want **Fetch query history** enabled.
### 5. Network access
The Fabric SQL analytics endpoint is a public Azure endpoint (`.datawarehouse.fabric.microsoft.com`, port 1433, TLS required). There is nothing to allowlist on the Fabric side. See the [Coalesce Quality IP Whitelist](/security/ip) only if your tenant restricts outbound access to the endpoint by IP.
## Input data in the Coalesce Quality UI
Navigate to **Data Sources → Add integration → Microsoft Fabric** and provide:
### Integration name
For example `Microsoft Fabric`.
### SQL analytics endpoint
The workspace SQL analytics endpoint, e.g. `.datawarehouse.fabric.microsoft.com`. You'll find it on any Warehouse or SQL analytics endpoint in the workspace under **Settings → SQL analytics endpoint** (the SQL connection string). Every Warehouse and Lakehouse in the workspace shares this host, so one integration covers the whole workspace.
### Default warehouse (optional)
The Warehouse or Lakehouse name used to resolve *unqualified* ad-hoc queries; leave empty to use `master`. Metadata and monitor SQL are fully qualified across every Warehouse in the workspace, so this only affects ad-hoc queries.
### Microsoft Entra service principal
* **Application (client) ID** — the Entra application (client) ID from step 1.
* **Client secret** — the service principal client secret. Stored encrypted and never displayed again in our UI.
* **Directory (tenant) ID (optional)** — only needed when the service principal lives in a different Entra tenant than the Fabric endpoint; inferred automatically when left blank.
### Data collection
* **Fetch query history** *(recommended, on by default)* — reads the workspace's `queryinsights` query history for cost attribution and SQL / column-level lineage. Management-plane reads only — no per-query billing. Needs the service principal on the **Contributor** (or higher) workspace role; a Viewer cannot read `queryinsights`. Databases without a `queryinsights` schema (Lakehouse SQL endpoints, Fabric SQL databases, mirrored databases) are skipped automatically.
### Scope
Narrow the workspace down to what you want to monitor. Both scopes support include **and** exclude rules at the **Warehouse**, **schema**, and **table** levels:
* **Catalog scope** — which Warehouses, schemas, and tables are ingested into the catalog. Empty means everything is ingested.
* **Metrics scope** — which tables are scanned for metrics. Empty means metrics are collected for all ingested tables.
## Personal access (user OAuth)
In addition to the workspace service principal above, you can let each Coalesce Quality member authenticate as themselves against Fabric through Microsoft Entra. Queries then run under the member's own Entra identity and respect the Fabric workspace roles, item permissions, and row-level security on that user. See [Data Warehouse Access](/security/dwh-access) for the full model and when to enable it.
To enable personal access, an Entra admin registers a **separate** OAuth app once (distinct from the connection service principal above), then pastes its client ID and secret into the Fabric integration's edit page in Coalesce Quality under **Warehouse access**.
### Register the OAuth app in Microsoft Entra
1. In the [Entra admin center](https://entra.microsoft.com), open **App registrations → New registration** and give it a name, e.g. `coalesce-quality-fabric-user-oauth`.
2. Under **Authentication → Add a platform → Web**, add the **Redirect URI(s)** for the Coalesce Quality region(s) your members use, with no trailing slash:
* EU: `https://app.synq.io/auth/dwh-oauth/callback`
* US: `https://app.us.synq.io/auth/dwh-oauth/callback`
* AU: `https://app.au.synq.io/auth/dwh-oauth/callback`
3. Under **API permissions → Add a permission → APIs my organization uses**, search for **Azure SQL Database**, choose **Delegated permissions**, and add **`user_impersonation`** (this is the `https://database.windows.net/user_impersonation` scope). No tenant-admin consent is required — it's user-consentable, so each member consents once at sign-in.
4. Under **Certificates & secrets → New client secret**, create a secret and copy its value (shown only once).
5. Copy the **Application (client) ID** and the **client secret**.
In Settings → Integrations → *(your Fabric integration)* → Warehouse access → Personal credentials, paste the Client ID and Client secret. Members will then see this Fabric integration listed under Settings → Warehouse access → My credentials and can connect with their own Entra identity.
Coalesce Quality builds the Entra authorize URL automatically (`https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize`) — you don't need to enter an authority or tenant. `organizations` lets each member's home tenant resolve the app, so one app registration works across every workspace and Coalesce Quality region whose redirect URI you added in step 2.
# MotherDuck
Source: https://docs.synq.io/dw-integrations/motherduck
Integrating MotherDuck with Coalesce Quality
This guide explains how to connect Coalesce Quality to your MotherDuck account securely.
We need this information so we can collect relevant metadata about your DuckDB tables for monitoring and data quality testing.
To be able to finish this guide, you’ll need the following:
→ Access to your MotherDuck workspace and API token
⏱️ Estimated time to finish: 5 minutes.
## Data we collect
For automated data anomaly testing, we collect the following from your MotherDuck instance:
* Table names and metadata
* Number of rows in each table
* Timestamp of the last data update
**We don’t access or store your raw data — only metadata needed to assess freshness, volume, and stability.**
## Setup MotherDuck Access
### 1. Get your MotherDuck account name
1. Go to [app.motherduck.com](https://app.motherduck.com) and log in.
2. Click your **profile icon** in the top-right corner.
3. In the dropdown, you’ll see your **organization name** and **email**.\
Your account name is typically your **organization name** (e.g. `acme-corp`) and often matches the prefix of your default database — for example, `acme-corp.db`.
You’ll need this account name when filling in the **MotherDuck account** field in the platform.
### 2. Generate a MotherDuck API token
1. While logged in to [app.motherduck.com](https://app.motherduck.com), click your **profile icon** again and choose **Account settings**.
2. Navigate to the **API Tokens** tab.
3. Click **Generate new token**, give it a name (e.g. `synq-integration`), and choose an expiry period.
4. Copy the generated token immediately — you won’t be able to see it again once you leave the page.
5. Paste it into the **MotherDuck API token** field in the platform.
Alternatively, if you’re using the CLI, you can generate a token via:
```bash theme={null}
motherduck auth token
```
# Redshift
Source: https://docs.synq.io/dw-integrations/redshift
Integrating Redshift with Coalesce Quality
This guide will show you how to securely connect Coalesce Quality to your Redshift cluster or Redshift Serverless workgroup.
We need this information so we collect metadata about your tables.
To be able to finish this guide, you'll need the following:
→ Access to modify your Redshift configuration as a superuser
⏱️ Estimated time to finish: 10 minutes.
## Data we collect
We read metadata from your Redshift database using the dedicated user described below. Depending on which features you enable in the integration, we ingest:
* **Catalog** — databases, schemas, tables, views, late-binding views, materialized views, columns, comments, data types, constraints (informational primary / unique / foreign keys).
* **SQL definitions** — view definitions, materialized view definitions, stored procedure bodies, and UDF bodies. Used for lineage and to detect references between objects.
* **Distribution and sort metadata** — `DISTSTYLE`, `DISTKEY`, `SORTKEY` (compound / interleaved / auto) per table.
* **Table metrics** *(opt-in)* — row counts and last-modified timestamps for anomaly detection.
* **Query logs** *(opt-in)* — `SYS_QUERY_HISTORY` for performance, cost, and lineage signals.
* **Freshness from query logs** *(opt-in)* — `SYS_QUERY_DETAIL` for tables touched by recent writes. Requires the `sys:monitor` role on Redshift Serverless.
* **External tables** — Spectrum external schemas and tables, when present.
**Metadata vs. data access.** The baseline grants below give Coalesce Quality access to your **schema and DDL**, never to row data. With every opt-in disabled, the integration runs metadata-only queries against `SVV_*` and `pg_catalog` views. Data-reading queries are issued only when you enable *Fetch table metrics*, *Fetch query logs*, *Freshness from query logs*, or run SQL test execution against the audit table.
We connect on a schedule (typically every 30 minutes). On Redshift Serverless this corresponds to roughly one minute of compute per scrape at the workgroup's base capacity — the actual bill depends on your base RPU setting. On provisioned Redshift our queries run on your existing cluster's compute and are negligible compared to a regular workload.
## Setup Redshift access
### Create a dedicated user with sufficient permissions
1. Open the Query Editor in Redshift and make sure the right cluster / workgroup and database are selected.
2. Run the following SQL as a superuser to create a dedicated user and group with the necessary read-only permissions, where `` is a secret you define for the integration.
```sql theme={null}
CREATE GROUP synq;
CREATE USER synq_user PASSWORD '' IN GROUP synq;
-- Catalog metadata views (svv_*)
GRANT SELECT ON pg_catalog.svv_redshift_databases TO GROUP synq;
GRANT SELECT ON pg_catalog.svv_all_schemas TO GROUP synq;
GRANT SELECT ON pg_catalog.svv_all_tables TO GROUP synq;
GRANT SELECT ON pg_catalog.svv_all_columns TO GROUP synq;
GRANT SELECT ON pg_catalog.svv_table_info TO GROUP synq;
GRANT SELECT ON pg_catalog.svv_external_tables TO GROUP synq;
```
3. Grant `USAGE` on each schema you want monitored. This is required even for views that use `WITH NO SCHEMA BINDING` — both the schema in which the late-binding view is defined and any schemas it reads from need `USAGE`.
```sql theme={null}
GRANT USAGE ON SCHEMA TO GROUP synq;
```
To grant `USAGE` on every schema in the database:
```sql theme={null}
DO $do$
DECLARE
sch text;
BEGIN
FOR sch IN SELECT nspname FROM pg_namespace
LOOP
EXECUTE format($$ GRANT USAGE ON SCHEMA %I TO GROUP synq $$, sch);
END LOOP;
END;
$do$;
```
4. Grant the user visibility into stored procedures, UDFs, and materialized views in the schemas you want monitored. Without these grants, procedure / UDF metadata and materialized view definitions will not be collected.
```sql theme={null}
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA TO GROUP synq;
GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA TO GROUP synq;
ALTER DEFAULT PRIVILEGES IN SCHEMA
GRANT EXECUTE ON FUNCTIONS TO GROUP synq;
ALTER DEFAULT PRIVILEGES IN SCHEMA
GRANT EXECUTE ON PROCEDURES TO GROUP synq;
```
5. (Optional) Grant access to table data within a schema. Required if you want Coalesce Quality to run monitors on your raw data — for example [Custom SQL monitors](/monitor-types/custom-sql-monitor):
```sql theme={null}
GRANT SELECT ON ALL TABLES IN SCHEMA TO GROUP synq;
ALTER DEFAULT PRIVILEGES IN SCHEMA
GRANT SELECT ON TABLES TO GROUP synq;
```
### Enable freshness monitoring (Redshift Serverless)
To estimate table freshness from query logs, the user needs access to `SYS_QUERY_DETAIL`. On Redshift Serverless this is gated behind the predefined `sys:monitor` role.
```sql theme={null}
GRANT ROLE sys:monitor TO synq_user;
```
For provisioned Redshift, equivalent visibility comes from `STV_*` / `STL_*` views — see the [official Redshift system table reference](https://docs.aws.amazon.com/redshift/latest/dg/cm_chap_system-tables.html).
### Whitelist the Coalesce Quality IP
For the complete list of IP addresses by region, see [Coalesce Quality IP Whitelist](/security/ip).
1. From Redshift, navigate to `Workgroup configuration` and click your default workgroup.
2. Under Network and security click `Edit` and check the *Turn on Publicly accessible* checkmark. Then click `Save changes`.
3. Close the window to return to the workgroup view and click your VPC security group.
4. Under the *Inbound rules* tab click `Edit inbound rules`, then `Add rule`:
* Type: `Redshift` (port 5439)
* Source: `Custom` with `34.105.135.39` (EU) or `35.238.250.82` (US)
5. Click `Save rules`.
### Database, dataset and host name
1. Take a note of your database name. It can be found in the Query Editor.
2. Go to `Workgroup configuration` and select your workgroup. Take a note of your `JDBC URL`.
## Input data in the Coalesce Quality UI
### Integration name
For example `Redshift`.
### Database
The name of your database (e.g. `analytics_prod`).
### Host
The hostname of your workgroup endpoint (e.g. `my-workgroup.123456789012.eu-central-1.redshift-serverless.amazonaws.com` or `my-cluster.us-east-1.redshift.amazonaws.com`).
To find the host: open Workgroup configuration, copy the Endpoint, and strip the trailing `:5439/` part.
### Port
Default is `5439`.
### User and password
`synq_user` and the password you set in step 2 above.
### Audit table name (optional)
Fully qualified name (`schema.table`) of the table where Coalesce Quality should write SQL test audit logs — for example `analytics.synq_sql_test__audit`. Coalesce Quality creates the table if it does not exist. Leave empty if you only run metadata monitors and don't execute custom SQL tests against the warehouse.
### SSH Tunnel (optional)
If your Redshift workgroup is private and only reachable through a bastion host, click `Add SSH tunnel` and fill in the bastion details. Leave this empty for clusters reachable via the public endpoint (the standard setup described above).
### Data collection options
Two opt-in checkboxes control what beyond catalog metadata Coalesce Quality reads:
* **Fetch query logs (Recommended)** — pulls from `SYS_QUERY_HISTORY`. Required for proactive anomaly-monitor training, unused-table detection, and cost insights. Adds a small recurring query cost — typically a few dollars per month on Serverless.
* **Estimate freshness of tables from `SYS_QUERY_DETAIL` view** — derives a per-table last-modified timestamp from query history. Requires the `sys:monitor` role on Serverless (see [Enable freshness monitoring](#enable-freshness-monitoring-redshift-serverless) above).
In some cases, permission grants can take a while to propagate. If you keep getting a `Connect failed` error after double-checking your details, try again after a minute.
# Snowflake
Source: https://docs.synq.io/dw-integrations/snowflake
Integrating Snowflake with Coalesce Quality
This guide will show you how to securely connect Coalesce Quality to your Snowflake instance.
We need this information so we collect metadata about your tables.
To be able to finish this guide, you’ll need the following:
→ Access to modify your Snowflake configuration as account admin
⏱️ Estimated time to finish: 10 minutes.
## Data we collect
We read metadata from your Snowflake account using the dedicated role described below. Depending on which features you enable in the integration, we ingest:
* **Catalog** — databases, schemas, tables, views, materialized views, dynamic tables, semantic views, streams, stages, comments, column types, tags.
* **SQL definitions** — `GET_DDL` output for tables, views, materialized views, dynamic tables, semantic views, streams, stored procedures, and user-defined functions. Used for lineage and to detect references between objects.
* **Constraints** — primary keys (via `SHOW PRIMARY KEYS`) and clustering keys. Foreign keys, uniques, and checks are read from `GET_DDL` when present.
* **Table metrics** *(opt-in)* — row counts and last-modified timestamps for anomaly detection.
* **Query logs** *(opt-in)* — `SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY` for performance, cost, and lineage signals.
* **Tasks** *(opt-in)* — `SHOW TASKS` plus `TASK_HISTORY` for execution outcomes.
* **Stored procedures and UDFs** — `SHOW PROCEDURES` / `SHOW USER FUNCTIONS` plus `GET_DDL` for SQL, JavaScript, Python, Java, and Scala languages (automatic when the role has `USAGE` on them).
* **Table-level lineage** *(opt-in)* — via `SNOWFLAKE.CORE.GET_LINEAGE` on Enterprise+ editions.
**Metadata vs. data access.** The baseline grants below give Coalesce Quality access to your **schema and DDL**, never to row data. The `SELECT` privileges on tables/views/etc. are required so the role can call `SHOW` and `GET_DDL` (Snowflake gates object visibility behind any object privilege), but Coalesce Quality only issues data-reading queries when you enable the corresponding opt-in feature in the integration UI — *Fetch table metrics*, *Fetch query logs*, *Fetch table lineage*, or SQL test execution against the audit table. With every opt-in disabled, the integration runs metadata commands only.
We use a dedicated XSMALL warehouse to isolate our workload from your production compute, and a dedicated user and role with the minimum required privileges. Metadata is collected on a schedule (typically every 30 minutes).
*This should be expected to consume \$0.0003 ([see warehouses overview](https://docs.snowflake.com/en/user-guide/warehouses-overview)) x 48 (every 30 minutes) x 10 (10s per check) = 0.14 credits per day.*
Before you execute your scripts you will need several key variables:
* `warehouse_name` — the name of the warehouse you will create (e.g. `SYNQ_WH`)
* `database_name` as an identifier of database (or multiple) you want to monitor
The following setup does several separate steps:
1. It creates a dedicated `username` and `role` for Coalesce Quality
2. It creates `xsmall` data warehouse that we can use to query your metadata
3. Grant necessary privileges to the dedicated user and role so we can pull query history and monitor the target database
## **Setup a user and warehouse**
As a super user, execute the following SQL commands to create a read-only role, a user assigned to that role, and a warehouse for that role.
We recommend creating a dedicated user name and warehouse.
### Password authentication
In the code, remember to replace:
* `` with a password that meets your account's [password policy](https://docs.snowflake.com/en/sql-reference/sql/create-password-policy)
* `` with the name you want the dedicated warehouse to have
```sql theme={null}
-- Configuration
set user_name='SYNQ';
set user_password='';
set warehouse_size='XSMALL';
set warehouse_name='';
set role_name='SYNQ';
-- Set role for grants
USE ROLE ACCOUNTADMIN;
-- Create warehouse for the monitoring workload
CREATE WAREHOUSE IF NOT EXISTS identifier($warehouse_name)
warehouse_size=$warehouse_size
auto_resume = true
auto_suspend = 60
initially_suspended=true
;
-- Create the dedicated role
CREATE ROLE IF NOT EXISTS identifier($role_name);
-- Create the dedicated user and grant access to role
CREATE USER IF NOT EXISTS identifier($user_name) PASSWORD=$user_password DEFAULT_ROLE=$role_name;
GRANT ROLE identifier($role_name) TO USER identifier($user_name);
-- Grant permissions to use the new warehouse
GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($warehouse_name) TO ROLE identifier($role_name);
-- Grant privileges to allow access to query history
GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE" TO ROLE identifier($role_name);
```
### Key-pair authentication
For more details on Snowflake's key-pair authentication, see the [official Snowflake documentation](https://docs.snowflake.com/en/user-guide/key-pair-auth).
Coalesce Quality supports two key-pair authentication methods:
1. **Managed Key-pair**: The key pair is generated and managed for you
2. **User Managed Key-pair**: You generate and provide your own private key (supports both encrypted and unencrypted keys)
#### Option A: Managed Key-pair
When configuring the integration, select "Managed Key-pair" and a public key will be generated for you. Copy this public key and use it in the setup below.
In the code, remember to replace:
* `` with the key generated in the previous step
* `` with the name you want the dedicated warehouse to have
```sql theme={null}
-- Configuration
set user_name='SYNQ';
set rsa_public_key='';
set warehouse_size='XSMALL';
set warehouse_name='';
set role_name='SYNQ';
-- Set role for grants
USE ROLE ACCOUNTADMIN;
-- Create warehouse for the monitoring workload
CREATE WAREHOUSE IF NOT EXISTS identifier($warehouse_name)
warehouse_size=$warehouse_size
auto_resume = true
auto_suspend = 60
initially_suspended=true
;
-- Create the dedicated role
CREATE ROLE IF NOT EXISTS identifier($role_name);
-- Create the dedicated user and grant access to role
CREATE USER IF NOT EXISTS identifier($user_name) RSA_PUBLIC_KEY=$rsa_public_key DEFAULT_ROLE=$role_name;
GRANT ROLE identifier($role_name) TO USER identifier($user_name);
-- Grant permissions to use the new warehouse
GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($warehouse_name) TO ROLE identifier($role_name);
-- Grant privileges to allow access to query history
GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE" TO ROLE identifier($role_name);
```
#### Option B: User Managed Key-pair
Both **encrypted** and **unencrypted** private keys in PKCS#8 PEM format are supported. If you use an encrypted key, you'll need to provide the passphrase when configuring the integration.
##### Generate a new key pair
Snowflake requires a minimum 2048-bit RSA private key in PKCS#8 PEM format.
**Generate an unencrypted private key:**
```bash theme={null}
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
```
**Generate an encrypted private key (recommended for better security):**
```bash theme={null}
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8
```
When prompted, enter a passphrase to encrypt the private key. You'll need to provide this passphrase when configuring the integration.
##### Extract the public key
After generating your private key, extract the public key:
```bash theme={null}
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
```
##### Configure Snowflake with your public key
Remove the header and footer from the public key file (`-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----`), then use the remaining content as `` in the setup script:
```sql theme={null}
-- Configuration
set user_name='SYNQ';
set rsa_public_key='';
set warehouse_size='XSMALL';
set warehouse_name='';
set role_name='SYNQ';
-- Set role for grants
USE ROLE ACCOUNTADMIN;
-- Create warehouse for the monitoring workload
CREATE WAREHOUSE IF NOT EXISTS identifier($warehouse_name)
warehouse_size=$warehouse_size
auto_resume = true
auto_suspend = 60
initially_suspended=true
;
-- Create the dedicated role
CREATE ROLE IF NOT EXISTS identifier($role_name);
-- Create the dedicated user and grant access to role
CREATE USER IF NOT EXISTS identifier($user_name) RSA_PUBLIC_KEY=$rsa_public_key DEFAULT_ROLE=$role_name;
GRANT ROLE identifier($role_name) TO USER identifier($user_name);
-- Grant permissions to use the new warehouse
GRANT OPERATE, USAGE, MONITOR ON WAREHOUSE identifier($warehouse_name) TO ROLE identifier($role_name);
-- Grant privileges to allow access to query history
GRANT IMPORTED PRIVILEGES ON DATABASE "SNOWFLAKE" TO ROLE identifier($role_name);
```
##### Configure the integration
In the integration settings:
1. Select "User Managed Key-pair" as the authentication method
2. Paste your **private key** (including the `-----BEGIN PRIVATE KEY-----` and `-----END PRIVATE KEY-----` headers)
3. If your key is encrypted (starts with `-----BEGIN ENCRYPTED PRIVATE KEY-----`), provide the passphrase
Keys in PKCS#1 format (`-----BEGIN RSA PRIVATE KEY-----`) are not supported by Snowflake. If you have a PKCS#1 key, convert it to PKCS#8 format using:
```bash theme={null}
openssl pkcs8 -topk8 -inform PEM -in rsa_key.pem -out rsa_key.p8 -nocrypt
```
## **Grant access to monitored database**
We recommend setting access on Schema level, as long as it is aligned with your permissions management strategy.
Applying schema level future grants in a Snowflake account where there are only database future grants can break existing roles! From [Snowflake's docs](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege.html#considerations):
*"When future grants are defined at both the database and schema level, the schema level grants take precedence over the database level grants, and the database level grants are ignored. An important point to note here is that as long as there is a SCHEMA level future grants, ALL DATABASE levels will be ignored, even for the roles that are NOT defined in the SCHEMA level future grants."*
If you use schema grants follow Option 1, if you use database grants follow Option 2.
### Option 1 (Recommended): Grant access to all schemas
The following stored procedure iterates through each schema in a given database, then grants access to each table in a given schema. This stored procedure should be run as follows each time a new schema is created. Run it in the same Worksheet as the **Setup a user and warehouse** step above so the `$role_name` session variable is still set.
Replace `` with the name of your database.
```sql theme={null}
set database_name='';
-- Grant metadata privileges to database to be monitored
GRANT USAGE,MONITOR ON DATABASE identifier($database_name) TO ROLE identifier($role_name);
GRANT USAGE,MONITOR ON ALL SCHEMAS IN DATABASE identifier($database_name) TO ROLE identifier($role_name);
GRANT USAGE,MONITOR ON FUTURE SCHEMAS IN DATABASE identifier($database_name) TO ROLE identifier($role_name);
USE DATABASE identifier($database_name);
CREATE OR REPLACE PROCEDURE grantFutureAccess(databaseName string, roleName string)
returns string not null
language javascript
as
$$
var schemaResultSet = snowflake.execute({ sqlText: 'SELECT SCHEMA_NAME FROM ' + DATABASENAME + ".INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME != 'INFORMATION_SCHEMA';"});
var numberOfSchemasGranted = 0;
while (schemaResultSet.next()) {
numberOfSchemasGranted += 1;
var schemaAndRoleSuffix = ' in schema ' + DATABASENAME + '."' +
schemaResultSet.getColumnValue('SCHEMA_NAME') + '" to role ' + ROLENAME + ';'
snowflake.execute({ sqlText: 'grant USAGE on schema ' + DATABASENAME + '."' +
schemaResultSet.getColumnValue('SCHEMA_NAME') + '" to role ' + ROLENAME + ';'});
snowflake.execute({ sqlText: 'grant SELECT on all tables' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on all views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on all materialized views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on all dynamic tables' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on all streams' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on all semantic views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant REFERENCES on all semantic views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant USAGE on all procedures' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant USAGE on all functions' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future tables' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future materialized views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future dynamic tables' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future streams' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant SELECT on future semantic views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant REFERENCES on future semantic views' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant USAGE on future procedures' + schemaAndRoleSuffix});
snowflake.execute({ sqlText: 'grant USAGE on future functions' + schemaAndRoleSuffix});
}
return 'Granted access to ' + numberOfSchemasGranted + ' schemas';
$$
;
grant USAGE on database identifier($database_name) to role identifier($role_name);
call grantFutureAccess($database_name, $role_name);
```
`MATERIALIZED VIEW`, `STREAM`, and `SELECT ON DYNAMIC TABLE` grants are silently ignored on Snowflake editions that do not support those object types — the `grant` statements still succeed, so the procedure is safe to run on Standard edition.
**Semantic views need both `SELECT` and `REFERENCES`.** `SELECT` lets the role list them via `SHOW SEMANTIC VIEWS` and query them via `SEMANTIC_VIEW(sv DIMENSIONS … METRICS …)`. `REFERENCES` is required separately so `GET_DDL('SEMANTIC_VIEW', …)` returns the body — without it, the catalog scrape can see the asset but cannot read its definition. Snowflake gates this differently from every other object kind, where `SELECT` / `USAGE` cover both visibility and `GET_DDL`.
### Option 2: Grant access to a database
Run this in the same Worksheet as the **Setup a user and warehouse** step above.
Replace `` with the name of your database.
```sql theme={null}
set database_name='';
-- Read-only access to database
grant USAGE, MONITOR on database identifier($database_name) to role identifier($role_name);
grant USAGE, MONITOR on all schemas in database identifier($database_name) to role identifier($role_name);
grant USAGE, MONITOR on future schemas in database identifier($database_name) to role identifier($role_name);
grant SELECT on all tables in database identifier($database_name) to role identifier($role_name);
grant SELECT on future tables in database identifier($database_name) to role identifier($role_name);
grant SELECT on all views in database identifier($database_name) to role identifier($role_name);
grant SELECT on future views in database identifier($database_name) to role identifier($role_name);
grant SELECT on all materialized views in database identifier($database_name) to role identifier($role_name);
grant SELECT on future materialized views in database identifier($database_name) to role identifier($role_name);
grant SELECT on all dynamic tables in database identifier($database_name) to role identifier($role_name);
grant SELECT on future dynamic tables in database identifier($database_name) to role identifier($role_name);
grant SELECT on all streams in database identifier($database_name) to role identifier($role_name);
grant SELECT on future streams in database identifier($database_name) to role identifier($role_name);
-- Semantic views: SELECT enables SHOW + SEMANTIC_VIEW(...) querying;
-- REFERENCES is required separately for GET_DDL('SEMANTIC_VIEW', ...).
grant SELECT on all semantic views in database identifier($database_name) to role identifier($role_name);
grant SELECT on future semantic views in database identifier($database_name) to role identifier($role_name);
grant REFERENCES on all semantic views in database identifier($database_name) to role identifier($role_name);
grant REFERENCES on future semantic views in database identifier($database_name) to role identifier($role_name);
grant USAGE on all procedures in database identifier($database_name) to role identifier($role_name);
grant USAGE on future procedures in database identifier($database_name) to role identifier($role_name);
grant USAGE on all functions in database identifier($database_name) to role identifier($role_name);
grant USAGE on future functions in database identifier($database_name) to role identifier($role_name);
```
## **Grant access to Snowflake tasks (Optional)**
If you want to monitor Snowflake tasks, you need to grant MONITOR privileges on the specific tasks you want to observe. This allows us to collect task execution history and metadata.
Replace ``, ``, and `` with your actual database, schema, and task names before running:
```sql theme={null}
-- Grant MONITOR privilege on a specific task
GRANT MONITOR ON TASK .. TO ROLE identifier($role_name);
-- To grant MONITOR on all tasks in a schema (if needed)
GRANT MONITOR ON ALL TASKS IN SCHEMA . TO ROLE identifier($role_name);
-- To grant MONITOR on future tasks in a schema (if needed)
GRANT MONITOR ON FUTURE TASKS IN SCHEMA . TO ROLE identifier($role_name);
```
The MONITOR privilege on tasks allows viewing task execution history, status, and metadata but does not allow executing or modifying the tasks. This is required for task monitoring and anomaly detection.
After granting these privileges, you must also enable task monitoring in the integration settings. In the integration configuration screen, make sure to enable "Fetch tasks and their executions" to start collecting task data.
## **Grant access to Snowflake tags (Optional)**
If your Snowflake objects use [tags](https://docs.snowflake.com/en/user-guide/object-tagging) and you want Coalesce Quality to read them (e.g. to filter tables or deploy monitors based on tag values), you need to grant the `APPLY TAG` privilege. Without this privilege, Snowflake's [`GET_DDL`](https://docs.snowflake.com/en/sql-reference/functions/get_ddl#usage-notes) function replaces tag names and values with `#UNKNOWN_TAG='#UNKNOWN_VALUE'` placeholders.
```sql theme={null}
-- Grant ability to read tags from GET_DDL output
GRANT APPLY TAG ON ACCOUNT TO ROLE identifier($role_name);
```
This grant is only needed if you use Snowflake tags on your tables/views and want Coalesce Quality to use them for filtering or monitor rules. Coalesce Quality will show a warning during ingestion if it detects unknown tag placeholders in your metadata, so you can decide at that point whether to apply this grant.
The `APPLY TAG` privilege allows reading tag assignments but does not grant the ability to modify data or other security policies. See the [Snowflake GET\_DDL documentation](https://docs.snowflake.com/en/sql-reference/functions/get_ddl#usage-notes) for more details.
## **Stored procedures and user-defined functions**
Coalesce Quality automatically discovers stored procedures and UDFs using `SHOW PROCEDURES IN DATABASE` / `SHOW USER FUNCTIONS IN DATABASE` and fetches each object's DDL via `GET_DDL`. All languages are supported (SQL, JavaScript, Python, Java, Scala). The grants in Option 1 / Option 2 above already include the required `USAGE` on procedures and functions — no extra steps are needed.
Procedures and UDFs show up as first-class assets in Coalesce Quality and participate in lineage whenever they are referenced by tables, views, or tasks.
## Personal access (user OAuth)
In addition to the workspace credentials above, you can let each Coalesce Quality member authenticate as themselves against Snowflake. Queries then run under the member's own Snowflake account and respect the grants, masking policies, and row-level security configured on that user. See [Data Warehouse Access](/security/dwh-access) for the full model and when to enable it.
To enable personal access, an account admin creates a Snowflake security integration of type `OAUTH` once, then pastes the client ID and secret into the Snowflake integration's edit page in Coalesce Quality.
### Create the security integration
```sql theme={null}
USE ROLE ACCOUNTADMIN;
CREATE SECURITY INTEGRATION COALESCE_QUALITY_USER_OAUTH
TYPE = OAUTH
ENABLED = TRUE
OAUTH_CLIENT = CUSTOM
OAUTH_CLIENT_TYPE = 'CONFIDENTIAL'
OAUTH_REDIRECT_URI = 'https://app.synq.io/auth/dwh-oauth/callback'
OAUTH_ALTERNATE_REDIRECT_URIS = ('https://app.us.synq.io/auth/dwh-oauth/callback', 'https://app.au.synq.io/auth/dwh-oauth/callback')
OAUTH_ISSUE_REFRESH_TOKENS = TRUE
OAUTH_REFRESH_TOKEN_VALIDITY = 7776000 -- 90 days
BLOCKED_ROLES_LIST = ('ACCOUNTADMIN','ORGADMIN','SECURITYADMIN');
```
Keep only the redirect URI(s) for the Coalesce Quality region(s) your members use. The EU app is `https://app.synq.io`, the US app is `https://app.us.synq.io` and the AU app is `https://app.au.synq.io` — pass one as `OAUTH_REDIRECT_URI` and any others in `OAUTH_ALTERNATE_REDIRECT_URIS`. No trailing slash.
`BLOCKED_ROLES_LIST` prevents members from minting OAuth tokens for high-privilege account roles. Add any other roles your security policy reserves for break-glass use.
### Fetch the client credentials
```sql theme={null}
SELECT SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('COALESCE_QUALITY_USER_OAUTH');
```
The function returns a JSON object with `OAUTH_CLIENT_ID`, `OAUTH_CLIENT_SECRET`, and `OAUTH_CLIENT_SECRET_2` (the second secret exists for rotation; either can be used). Paste the client ID and one of the secrets into Settings → Integrations → *(your Snowflake integration)* → Warehouse access → Personal credentials in Coalesce Quality.
No user mapping is required. When a member consents, they sign in to Snowflake on the standard authorize page, and the access token is issued for that Snowflake user. If your account uses SSO/SAML, the consent page transparently redirects through the IdP. Coalesce Quality stores per-user access/refresh tokens; queries from that member then run as the Snowflake user they signed in as.
### Optional: restrict which roles members can request
Each member can pass a `role` parameter when consenting (Coalesce Quality forwards it as `scope=session:role:`). If you want to constrain the set of roles reachable through this OAuth app, use `ALLOWED_ROLES_LIST`:
```sql theme={null}
ALTER SECURITY INTEGRATION COALESCE_QUALITY_USER_OAUTH
SET ALLOWED_ROLES_LIST = ('ANALYST', 'READER');
```
`ALLOWED_ROLES_LIST` is a whitelist that complements `BLOCKED_ROLES_LIST` (blacklist) above. Leave it empty to allow any role the member is granted on Snowflake, minus the blocked ones.
## Network Configuration
If your Snowflake instance is behind a firewall or has network access controls, you may need to whitelist our IP addresses. See [IP Whitelist](/security/ip) for the complete list of IP addresses by region.
Once you've successfully created the warehouse, database, and dedicated role, input the following data in the Coalesce Quality UI.
## Input data in the UI
### Integration name
For example, `snowflake`
### Account name
You can find it under `Admin` > `Accounts` when you highlight the link icon (🔗). Both formats work:
* `-` (preferred, e.g. `acme-prod1`)
* `.` (legacy, e.g. `xy12345.eu-west-1`)
Do **not** include `https://` or a trailing slash. A trailing `.snowflakecomputing.com` is stripped and the value is lowercased automatically, so either `acme-prod1` or `acme-prod1.snowflakecomputing.com` will work.
### Databases
The names of the databases you granted access to earlier in the guide. You can monitor multiple databases with the same integration.
### Role, username, and password
The role name, username, and password you created earlier in the guide.
### Warehouse
The name of the warehouse you created earlier in the guide.
### Audit table FQN (optional)
Fully-qualified table name (e.g. `MY_DB.PUBLIC.SYNQ_AUDIT`) where Coalesce Quality will write SQL test execution results. The integration creates the table automatically if it does not yet exist. Leave empty if you do not run SQL tests.
### ACCOUNT\_USAGE database name (optional)
Defaults to `SNOWFLAKE`. Override only if your account has the `SNOWFLAKE` share imported under a non-default name.
### Optional flags
* **Fetch query logs** — enables query history ingestion from `SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY`. You can optionally restrict the set of source databases.
* **Fetch Snowflake tasks** — discovers Snowflake Tasks (`SHOW TASKS`). Select a subset of databases or leave empty for all.
* **Fetch task executions from `ACCOUNT_USAGE.TASK_HISTORY`** — when on, centralized task history is used (up to 45-minute lag). When off, `INFORMATION_SCHEMA.TASK_HISTORY` is queried per database (lower lag, more warehouse time).
* **Task execution fetch interval (minutes)** — minimum 5.
* **Fetch table lineage** — uses `SNOWFLAKE.CORE.GET_LINEAGE` for table-level lineage (Enterprise+). Optionally restrict to a subset of databases.
* **Don't use GET\_DDL for table schema collection** — enable only if `GET_DDL` causes warehouse pressure; Coalesce Quality will fall back to parsing query logs.
# Trino
Source: https://docs.synq.io/dw-integrations/trino
Integrating Trino (Iceberg) with Coalesce Quality
This guide will show you how to securely connect Coalesce Quality to your Trino instance.
We need this information so we collect metadata about your tables.
To be able to finish this guide, you’ll need the following:
→ Access to modify your Trino configuration as account admin
⏱️ Estimated time to finish: 10 minutes.
## Data we collect
For the automated data anomaly testing we collect the following:
* Number of rows in every table in a given dataset
* Timestamp of the last change of data in all tables in a given dataset
You will need several key variables:
* `host` Host of your Trino cluster, e.g. host.trino.com
* `port` Port of your Trino cluster. If not specified the Trino driver will decide which port to use
* `username`
* `password`
# Google Cloud Storage
Source: https://docs.synq.io/gcp-integrations/cloud-storage
Automatically discover and track GCS buckets in Coalesce Quality
## Overview
The Coalesce Quality Google Cloud Storage integration automatically discovers all GCS buckets in your Google Cloud project and creates custom entities for centralized asset management and governance.
This integration can also serve as a reference implementation for building custom integrations using the [Coalesce Quality Public API](/api-reference/getting-started).
**Source code:** [github.com/getsynq/synq-google-cloud-storage](https://github.com/getsynq/synq-google-cloud-storage)
## What It Does
The integration:
* **Discovers** all GCS buckets in your Google Cloud project
* **Creates** custom entities for each bucket with rich metadata
* **Syncs** comprehensive bucket information including:
* Storage class and location
* Versioning status
* Lifecycle rules with detailed conditions
* Uniform bucket-level access settings
* User-defined labels
* **Filters** buckets based on include/exclude patterns
* **Auto-cleanup** removes entities when buckets are deleted
Each bucket entity includes a detailed description with storage class, location, creation date, versioning status, and complete lifecycle rule configurations.
## Use Cases
* **Data Catalog Management**: Track all cloud storage resources in one place
* **Resource Discovery**: Automatically maintain an up-to-date inventory of GCS buckets
* **Compliance Tracking**: Monitor storage configurations and lifecycle policies
* **Cross-Platform Lineage**: Connect storage buckets with data pipelines and tables
## Installation
### Download Pre-built Binaries
Download the latest release for your platform from the [releases page](https://github.com/getsynq/synq-google-cloud-storage/releases).
**Intel:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-storage/releases/latest/download/synq-google-cloud-storage_darwin_amd64.tar.gz
tar -xzf synq-google-cloud-storage_darwin_amd64.tar.gz
sudo mv synq-google-cloud-storage /usr/local/bin/
```
**Apple Silicon:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-storage/releases/latest/download/synq-google-cloud-storage_darwin_arm64.tar.gz
tar -xzf synq-google-cloud-storage_darwin_arm64.tar.gz
sudo mv synq-google-cloud-storage /usr/local/bin/
```
**AMD64:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-storage/releases/latest/download/synq-google-cloud-storage_linux_amd64.tar.gz
tar -xzf synq-google-cloud-storage_linux_amd64.tar.gz
sudo mv synq-google-cloud-storage /usr/local/bin/
```
**ARM64:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-storage/releases/latest/download/synq-google-cloud-storage_linux_arm64.tar.gz
tar -xzf synq-google-cloud-storage_linux_arm64.tar.gz
sudo mv synq-google-cloud-storage /usr/local/bin/
```
Download the `.zip` file from the [releases page](https://github.com/getsynq/synq-google-cloud-storage/releases) and extract it.
Requires Go 1.24 or later:
```bash theme={null}
git clone https://github.com/getsynq/synq-google-cloud-storage.git
cd synq-google-cloud-storage
go build
```
## Configuration
### Required: API Credentials
Create a `.env` file with your Coalesce Quality API credentials:
```bash theme={null}
SYNQ_CLIENT_ID=your_client_id_here
SYNQ_CLIENT_SECRET=your_client_secret_here
# GCP Project ID (optional if running on GCP or using gcloud)
GCP_PROJECT_ID=your-gcp-project-id
```
The GCP project ID can be auto-detected from:
* Environment variables (`GCP_PROJECT_ID`, `GOOGLE_CLOUD_PROJECT`, `GCLOUD_PROJECT`)
* `gcloud` CLI configuration
* GCP metadata server (when running on GCP)
### Optional: Advanced Configuration
For advanced customization, create a `config.yaml` file:
```yaml theme={null}
# Coalesce Quality API Configuration (defaults shown for EU region)
synq:
endpoint: "developer.synq.io:443" # EU region (default)
# For US region, use: "api.us.synq.io:443"; for AU, "api.au.synq.io:443"
oauth_url: "https://developer.synq.io/oauth2/token" # EU region (default)
# For US region, use: "https://api.us.synq.io/oauth2/token"; for AU, "https://api.au.synq.io/oauth2/token"
# GCP Configuration
gcp:
user_agent: "synq-gcs-client-v1.0.0"
# project_id: "your-project-id" # Alternative to GCP_PROJECT_ID env var
# entity_group_id: "gcs::custom-group-id" # Defaults to gcs::
# Custom Entity Type IDs
types:
bucket_type_id: 40
# bucket_icon: "path/to/custom-bucket-icon.svg"
# Resource Filters
filter:
buckets:
include: [] # Empty means include all
exclude: [] # Regex patterns to exclude
# Examples:
# include: ["prod-.*"] # Only include buckets starting with prod-
# exclude: ["test-.*"] # Skip buckets starting with test-
```
**Configuration precedence:** defaults → config.yaml → environment variables → CLI flags
## Network Requirements
If your GCP project has firewall rules that restrict outbound connections, whitelist the Coalesce Quality egress IP addresses:
* App: [https://app.synq.io](https://app.synq.io)
* API: [https://developer.synq.io](https://developer.synq.io)
* **Egress IP: `34.105.135.39`**
* App: [https://app.us.synq.io](https://app.us.synq.io)
* API: [https://api.us.synq.io](https://api.us.synq.io)
* **Egress IP: `35.238.250.82`**
* App: [https://app.au.synq.io](https://app.au.synq.io)
* API: [https://api.au.synq.io](https://api.au.synq.io)
* **Egress IP: `35.189.4.22`**
See [IP Addresses](/security/ip) for the latest information.
## Running the Integration
### Basic Usage
```bash theme={null}
# Minimal setup: just create .env with credentials
cp .env.example .env
# Edit .env and add your credentials
# Run with defaults
./synq-google-cloud-storage
# Run with debug logging
LOG_LEVEL=DEBUG ./synq-google-cloud-storage
# Run with JSON logging for production
LOG_FORMAT=json ./synq-google-cloud-storage
```
### Dry-Run Mode
Preview what entities would be created without making API calls:
```bash theme={null}
# Dry-run mode (no API calls)
./synq-google-cloud-storage --dry-run
# Dry-run with debug logging
LOG_LEVEL=DEBUG ./synq-google-cloud-storage --dry-run
```
In dry-run mode, the integration scans GCS buckets and shows what would be created, but does not call the API or require credentials.
### Command-Line Options
Common flags:
* `--dry-run` - Preview changes without calling the API
* `--gcp.project-id` - Specify GCP project ID
* `--filter.buckets.include` - Bucket name patterns to include
* `--filter.buckets.exclude` - Bucket name patterns to exclude
* `--types.bucket-type-id` - Custom entity type ID (default: 40)
* `--synq.endpoint` - API endpoint for your region
For US region:
```bash theme={null}
./synq-google-cloud-storage \
--synq.endpoint=api.us.synq.io:443 \
--synq.oauth-url=https://api.us.synq.io/oauth2/token
```
For AU region:
```bash theme={null}
./synq-google-cloud-storage \
--synq.endpoint=api.au.synq.io:443 \
--synq.oauth-url=https://api.au.synq.io/oauth2/token
```
Run `./synq-google-cloud-storage --help` for all available options.
## How It Works
1. **Authenticates** with the Coalesce Quality API using OAuth2 client credentials
2. **Creates/updates** custom entity type for GCS buckets
3. **Discovers** all GCS buckets in your project
4. **Creates entities** with comprehensive metadata
5. **Uses entity groups** to enable automatic cleanup of deleted buckets
### Entity Groups
The integration uses entity groups to track all entities created in each run. When the group is updated, Coalesce Quality automatically removes entities that were in the previous group but not in the current one, enabling automatic cleanup of deleted buckets.
### Custom Identifiers
All entities use custom identifiers with `gcs::` prefix for namespace isolation. Buckets use identifiers in the format: `gcs::`.
## Scheduling with Cron
To keep your bucket inventory up-to-date, schedule the integration to run periodically:
```bash theme={null}
# Run every hour
0 * * * * cd /path/to/integration && ./synq-google-cloud-storage
# Run every 6 hours
0 */6 * * * cd /path/to/integration && ./synq-google-cloud-storage
```
## Using as a Public API Example
This integration demonstrates best practices for using the Coalesce Quality Public API:
* OAuth2 authentication with client credentials
* Creating and managing custom entity types
* Using entity groups for automatic cleanup
* Implementing filtering and dry-run modes
* Handling regional deployments
See the [source code](https://github.com/getsynq/synq-google-cloud-storage) and [API documentation](/api-reference/getting-started) for more details.
## Troubleshooting
Verify your credentials are correct in the `.env` file. Ensure you're using the correct endpoint for your region (EU or US).
Set the `GCP_PROJECT_ID` environment variable explicitly or configure `gcloud` CLI with your project:
```bash theme={null}
gcloud config set project YOUR_PROJECT
```
Ensure your GCP credentials have the `storage.buckets.list` permission and can read bucket metadata.
If running behind a firewall, verify that outbound connections to the API endpoint are allowed. Check your network configuration and firewall rules.
## Support
For issues or questions:
* GitHub Issues: [github.com/getsynq/synq-google-cloud-storage/issues](https://github.com/getsynq/synq-google-cloud-storage/issues)
* Coalesce Quality Support: [support](/support/support)
# Google Cloud Pub/Sub
Source: https://docs.synq.io/gcp-integrations/pubsub
Automatically discover and track Pub/Sub topics and subscriptions in Coalesce Quality
## Overview
The Coalesce Quality Google Cloud Pub/Sub integration automatically discovers all Pub/Sub topics and subscriptions in your Google Cloud project and creates custom entities for centralized asset management, governance, and cross-platform data lineage.
This integration can also serve as a reference implementation for building custom integrations using the [Coalesce Quality Public API](/api-reference/getting-started).
**Source code:** [github.com/getsynq/synq-google-cloud-pubsub](https://github.com/getsynq/synq-google-cloud-pubsub)
## What It Does
The integration:
* **Discovers** all Pub/Sub topics and subscriptions in your GCP project
* **Creates** custom entities for each resource
* **Tracks relationships** between topics and their subscriptions (optional)
* **Automatically cleans up** entities when resources are deleted
* **Supports flexible filtering** with include/exclude patterns
## Use Cases
* **Data Catalog Management**: Track all messaging infrastructure in one place
* **Resource Discovery**: Automatically maintain an up-to-date inventory
* **Compliance Tracking**: Monitor messaging configurations and subscriptions
* **Cross-Platform Lineage**: Connect Pub/Sub topics with data pipelines, BigQuery tables, and other systems
## Installation
### Download Pre-built Binaries
Download the latest release for your platform from the [releases page](https://github.com/getsynq/synq-google-cloud-pubsub/releases).
**Intel:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-pubsub/releases/latest/download/synq-google-cloud-pubsub_darwin_amd64.tar.gz
tar -xzf synq-google-cloud-pubsub_darwin_amd64.tar.gz
sudo mv synq-google-cloud-pubsub /usr/local/bin/
```
**Apple Silicon:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-pubsub/releases/latest/download/synq-google-cloud-pubsub_darwin_arm64.tar.gz
tar -xzf synq-google-cloud-pubsub_darwin_arm64.tar.gz
sudo mv synq-google-cloud-pubsub /usr/local/bin/
```
**AMD64:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-pubsub/releases/latest/download/synq-google-cloud-pubsub_linux_amd64.tar.gz
tar -xzf synq-google-cloud-pubsub_linux_amd64.tar.gz
sudo mv synq-google-cloud-pubsub /usr/local/bin/
```
**ARM64:**
```bash theme={null}
curl -LO https://github.com/getsynq/synq-google-cloud-pubsub/releases/latest/download/synq-google-cloud-pubsub_linux_arm64.tar.gz
tar -xzf synq-google-cloud-pubsub_linux_arm64.tar.gz
sudo mv synq-google-cloud-pubsub /usr/local/bin/
```
Download the `.zip` file from the [releases page](https://github.com/getsynq/synq-google-cloud-pubsub/releases) and extract it.
Requires Go 1.24 or later:
```bash theme={null}
git clone https://github.com/getsynq/synq-google-cloud-pubsub.git
cd synq-google-cloud-pubsub
go build
```
## Configuration
### Required: API Credentials
Create a `.env` file with your Coalesce Quality API credentials:
```bash theme={null}
SYNQ_CLIENT_ID=your_client_id_here
SYNQ_CLIENT_SECRET=your_client_secret_here
# GCP Project ID (optional if running on GCP or using gcloud)
GCP_PROJECT_ID=your-gcp-project-id
```
The GCP project ID can be auto-detected from:
* Environment variables (`GCP_PROJECT_ID`, `GOOGLE_CLOUD_PROJECT`, `GCLOUD_PROJECT`)
* `gcloud` CLI configuration
* GCP metadata server (when running on GCP)
### Optional: Advanced Configuration
For advanced customization, create a `config.yaml` file:
```yaml theme={null}
# Coalesce Quality API Configuration (defaults shown for EU region)
synq:
endpoint: "developer.synq.io:443" # EU region (default)
# For US region, use: "api.us.synq.io:443"; for AU, "api.au.synq.io:443"
oauth_url: "https://developer.synq.io/oauth2/token" # EU region (default)
# For US region, use: "https://api.us.synq.io/oauth2/token"; for AU, "https://api.au.synq.io/oauth2/token"
# GCP Configuration
gcp:
user_agent: "synq-pubsub-client-v1.0.0"
# project_id: "your-project-id" # Alternative to GCP_PROJECT_ID env var
# entity_group_id: "pubsub::custom-group-id" # Defaults to pubsub::
# Custom Entity Type IDs
types:
topic_type_id: 20
subscription_type_id: 21
# topic_icon: "path/to/custom-topic-icon.svg"
# subscription_icon: "path/to/custom-subscription-icon.svg"
# Resource Filters
filter:
topics:
include: [] # Empty means include all
exclude: [] # Regex patterns to exclude
subscriptions:
include: [] # Empty means include all
exclude:
# Exclude auto-generated per-pod subscriptions
- '-[a-z0-9]{9,10}-[a-z0-9]{5}\.subscription$'
# Relationship Management (disabled by default)
relationships:
enabled: false # Set to true to enable topic->subscription relationships
filter:
include: [] # Empty means include all (format: "topic_id->subscription_id")
exclude: [] # Regex patterns to exclude relationship pairs
# Examples:
# include: ["important-topic->.*"] # Only relationships for important-topic
# exclude: ["test-.*->.*"] # Skip relationships for test topics
```
**Configuration precedence:** defaults → config.yaml → environment variables → CLI flags
## Network Requirements
If your GCP project has firewall rules that restrict outbound connections, whitelist the Coalesce Quality egress IP addresses:
* App: [https://app.synq.io](https://app.synq.io)
* API: [https://developer.synq.io](https://developer.synq.io)
* **Egress IP: `34.105.135.39`**
* App: [https://app.us.synq.io](https://app.us.synq.io)
* API: [https://api.us.synq.io](https://api.us.synq.io)
* **Egress IP: `35.238.250.82`**
* App: [https://app.au.synq.io](https://app.au.synq.io)
* API: [https://api.au.synq.io](https://api.au.synq.io)
* **Egress IP: `35.189.4.22`**
See [IP Addresses](/security/ip) for the latest information.
## Running the Integration
### Basic Usage
```bash theme={null}
# Minimal setup: just create .env with credentials
cp .env.example .env
# Edit .env and add your credentials
# Run with defaults
./synq-google-cloud-pubsub
# Run with debug logging
LOG_LEVEL=DEBUG ./synq-google-cloud-pubsub
# Run with JSON logging for production
LOG_FORMAT=json ./synq-google-cloud-pubsub
```
### Enabling Relationships
To track relationships between topics and subscriptions:
```bash theme={null}
# Enable relationships via command-line
./synq-google-cloud-pubsub --relationships.enabled
# Or configure in config.yaml
# relationships:
# enabled: true
```
Relationships are **disabled by default**. Enable them only if you need to track topic-to-subscription connections in your data lineage.
### Dry-Run Mode
Preview what entities would be created without making API calls:
```bash theme={null}
# Dry-run mode (no API calls)
./synq-google-cloud-pubsub --dry-run
# Dry-run with debug logging and relationships
LOG_LEVEL=DEBUG ./synq-google-cloud-pubsub --dry-run --relationships.enabled
```
In dry-run mode, the integration scans Pub/Sub resources and shows what would be created, but does not call the API or require credentials.
### Command-Line Options
Common flags:
* `--dry-run` - Preview changes without calling the API
* `--gcp.project-id` - Specify GCP project ID
* `--relationships.enabled` - Enable topic-to-subscription relationships
* `--filter.topics.include` - Topic name patterns to include
* `--filter.topics.exclude` - Topic name patterns to exclude
* `--filter.subscriptions.include` - Subscription name patterns to include
* `--filter.subscriptions.exclude` - Subscription name patterns to exclude
* `--types.topic-type-id` - Custom entity type ID for topics (default: 20)
* `--types.subscription-type-id` - Custom entity type ID for subscriptions (default: 21)
* `--synq.endpoint` - API endpoint for your region
For US region:
```bash theme={null}
./synq-google-cloud-pubsub \
--synq.endpoint=api.us.synq.io:443 \
--synq.oauth-url=https://api.us.synq.io/oauth2/token
```
For AU region:
```bash theme={null}
./synq-google-cloud-pubsub \
--synq.endpoint=api.au.synq.io:443 \
--synq.oauth-url=https://api.au.synq.io/oauth2/token
```
Run `./synq-google-cloud-pubsub --help` for all available options.
## How It Works
1. **Authenticates** with the Coalesce Quality API using OAuth2 client credentials
2. **Creates/updates** custom entity types for topics and subscriptions
3. **Discovers** all Pub/Sub topics and subscriptions in your project
4. **Creates entities** for each resource
5. **Manages relationships** between topics and subscriptions (if enabled)
6. **Uses entity groups** to enable automatic cleanup of deleted resources
### Entity Groups
The integration uses entity groups to track all entities created in each run. When the group is updated, Coalesce Quality automatically removes entities that were in the previous group but not in the current one, enabling automatic cleanup of deleted resources.
### Relationship Management
When enabled, the integration creates relationships between topics and their subscriptions. The system:
* Deduplicates relationships to avoid recreating existing ones
* Cleans up relationships that no longer exist
* Supports filtering with include/exclude patterns
### Custom Identifiers
All entities use custom identifiers with `pubsub::` prefix for namespace isolation. Subscriptions use composite identifiers: `pubsub::::`.
## Scheduling with Cron
To keep your Pub/Sub inventory up-to-date, schedule the integration to run periodically:
```bash theme={null}
# Run every hour
0 * * * * cd /path/to/integration && ./synq-google-cloud-pubsub
# Run every 6 hours with relationships
0 */6 * * * cd /path/to/integration && ./synq-google-cloud-pubsub --relationships.enabled
```
## Using as a Public API Example
This integration demonstrates best practices for using the Coalesce Quality Public API:
* OAuth2 authentication with client credentials
* Creating and managing multiple custom entity types
* Using entity groups for automatic cleanup
* Managing relationships between entities
* Implementing filtering and dry-run modes
* Handling regional deployments
See the [source code](https://github.com/getsynq/synq-google-cloud-pubsub) and [API documentation](/api-reference/getting-started) for more details.
## Troubleshooting
Verify your credentials are correct in the `.env` file. Ensure you're using the correct endpoint for your region (EU or US).
Set the `GCP_PROJECT_ID` environment variable explicitly or configure `gcloud` CLI with your project:
```bash theme={null}
gcloud config set project YOUR_PROJECT
```
Ensure your GCP credentials have the following permissions:
* `pubsub.topics.list`
* `pubsub.subscriptions.list`
Use the default filter to exclude auto-generated per-pod subscriptions, or customize the filter patterns:
```yaml theme={null}
filter:
subscriptions:
exclude:
- '-[a-z0-9]{9,10}-[a-z0-9]{5}\.subscription$'
- 'test-.*'
```
If running behind a firewall, verify that outbound connections to the API endpoint are allowed. Check your network configuration and firewall rules.
## Support
For issues or questions:
* GitHub Issues: [github.com/getsynq/synq-google-cloud-pubsub/issues](https://github.com/getsynq/synq-google-cloud-pubsub/issues)
* Coalesce Quality Support: [support](/support/support)
# Incidents overview
Source: https://docs.synq.io/incidents/incident-overview
Incident management helps you manage the issue resolution from start to finish and avoid anything getting lost when the stakes are high.
Incident management is a helpful way for your entire team to stay on top of important issues and collaborate on resolving them. Incidents can be declared across issues monitored by Coalesce Quality, such as anomaly monitors, transformation layer tests (dbt, SQLMesh, Coalesce Transform), and failing Airflow tasks.
Benefits of declaring incidents
* Collaborate with your team on resolving issues keeping comments and status changes in one overview.
* Track and monitor ongoing incidents and who’s working on them.
* Review past incidents.
## Open incidents
The platform gives an [overview](https://app.synq.io/incident/open) of open, closed, and untriaged incidents to easily track what’s being worked on and by whom.
## Declaring an incident
Incidents can be declared through Slack alerts or directly in the UI. When you declare an incident, name it so it's easy for everyone to understand (*"duplication error from prod services impacting the ad-bidding ML model"* is better than *"issue with transformation model"*).
*Declaring an incident from a Slack alert*
*Declaring an incident from the UI*
### When to declare an incident?
There’s no one-fit-all solution for what makes an incident. We’ve seen two approaches work well.
1. For teams with few issues, all issues are declared as incidents
2. For teams with many ongoing issues, only P1 issues are declared as incidents (read more about how to assess the [cost of incidents here](https://www.synq.io/blog/cost-of-data-incidents))
## Prioritising an incident
Not all issues are equal. Some require that you drop everything and fix it, while others can wait until the end of the week. Use the impact assessment to get an overview, including `affected products`, `downstream products`, `downstream owners`, and `affected & downstream assets`. Clicking any group will show you the specific assets that are impacted.
You can also use the in-built lineage to narrow down impacted assets. For example, use the column-level lineage filter to narrow down the range of impacted assets.
## Collaborating on issues
To indicate you’re working on an issue within an incident, change the status to `Investigating`. This lets everyone else see you’re on it. The activity overview shows how the status of the incident has changed over its lifetime. This is particularly helpful when an incident spans multiple issues, as not everyone may work on the same things.
Use the comment section to make updates as you progress on investigating the incident.
If you use Slack, you can add a comment about the internal incident channel (e.g., #inc-user-stats-12-03-2024). This makes it easier to keep communication in one place and helps other people get up to speed if they return to the incident without having all the context.
## Closing or canceling an incident
Incidents self-resolve if the issue on the underlying asset is solved. This is visible in the UI, with the following banner on the incident. You still have to close the incident to move it to *closed incidents*.
You can close or cancel an incident using the Close incident button in the top right corner or Cancel incident behind the three dots. You should close the incident once it’s been resolved, and you want to keep track of it and use cancel in situations where the issue didn’t justify an incident.
## Reviewing past incidents
The [Past Incidents screen](https://app.synq.io/incident/past-incidents) lets you see all past incidents and filter by a date range. This is helpful if you want an overview of the number of incidents you declared in a time frame or if you’re looking back to investigate what happened at a specific time.
## Bringing incidents across the platform
We’re continuously integrating incidents into core platform workflows. One example is showing ongoing incidents for data products so everyone can immediately see that their data may be impacted.
# Introduction
Source: https://docs.synq.io/introduction
How to set up and get the most out of Coalesce Quality
Coalesce Quality is a data observability platform designed for model and metric-centric data stacks with a strong emphasis on data products and ownership. It’s built for teams that power business-critical use cases to detect issues in near real-time without needing a full-time data engineer to manage and set up the platform.
The platform is simple on the surface, but complex under the hood. This means it’s simple to set up and get going—most customers are up and running in less than 30 minutes. But simultaneously, it’s powerful and flexible enough to support advanced use cases.
### Getting started
After you’ve been assigned a workspace, follow these steps for the optimal setup.
1. [Set up the relevant integrations](https://app.synq.io/settings/integrations)
2. [Create your first data product](/data-products/creating-a-data-product)
3. [Set up monitors](/monitors/setting-up-monitors)
4. [Invite your team members](/admin/invite_user)
5. [Set up owners and alerts](/ownership/creating-an-owner)
### Using the platform
Group related data assets to build reliability with end-end monitoring and ownership.
Proactively detect data issues with self-learning and powerful anomaly monitors.
Declare, track, and resolve incidents to stay on top of all business-critical issues.
Clarify ownership of data assets and activate workflows that help owners stay informed about the health and status of their data.
Notify impacted owners by tagging or routing highly configurable Slack alerts or sending them directly to the inbox.
Performant and automated lineage that spans your data warehouse and BI tool at a column level.
### Not yet using Coalesce Quality?
Read some of our [customer stories](https://www.synq.io/customers) or book a demo at [synq.io](https://www.synq.io)
# Column-level lineage
Source: https://docs.synq.io/lineage/column-level-lineage
## Supported sources
Column-level lineage is supported in all supported data warehouses and relational databases. In addition to that it also works down to Looker and Tableau.
## Visibility into issues
There are two possible when column-level lineage might not be accurate and we clearly indicate that.
### Parsing of SQL failed
In case our parser is unable to understand the SQL query, we indicate that both on the `Code & Changes` of an asset and on the lineage graph.
### Extraction of dependencies failed
In case when SQL contains edge case constructs, we might not correctly resolve how data in the columns flows. To prevent such issues, we do post-validation of our SQL understanding and expose those validation results both in `Code & Changes` tab of an asset and on the lineage graph.
## Limitations
We do our best to improve support for all different syntaxes and constructs available in different SQL dialects. If any feature needed is not supported please report that to us.
### BigQuery `STRUCT` literal lineage
We track lineage of individual `STRUCT` fields and `RECORD` column itself, so lineage will work when using them in CTEs and record simplified lineage as part of single SQL. When going from one asset to another we expose only information about columns and not the `RECORD` fields.
Consider this example:
```sql theme={null}
WITH c AS (
SELECT STRUCT (c1 AS a, c2 AS b) AS field FROM `prj`.`ds`.`tbl`),
d AS (SELECT STRUCT (field.a as d) double_nested
FROM c)
SELECT double_nested.d
FROM d
```
In this case we will correctly track simplified lineage from output column `d` to column `c1` in `prj`.`ds`.`tbl`.
When we have two assets, one defined as
```sql theme={null}
CREATE VIEW ds.rec_tbl(r) AS
SELECT STRUCT (c1 AS a, c2 AS b) AS r FROM `prj`.`ds`.`tbl`)
```
Second defined by query
```sql theme={null}
SELECT r.c1 AS r FROM `prj`.`ds`.`rec_tbl`
```
We show that column `r` depends on both `c1` and `c2`. We might consider changing that behaviour later.
# Lineage overview
Source: https://docs.synq.io/lineage/lineage
Our lineage is built to be performant and work out of the box. This means you’ll automatically get column-level lineage from BigQuery, Snowflake, Redshift, and ClickHouse to Looker and Tableau with the ability to explore thousands of assets with sub-second latency. The lineage is helpful for core workflows such as
* Understand the downstream impact of an issue across your transformation layers (dbt, SQLMesh, Coalesce Transform) and BI tools to decide the urgency at which you resolve it.
* Understand the downstream implications of making a change to a column upstream.
* Debugging a data issue to find upstream dependencies.
The lineage is automatically extracted from your data warehouse and BI tool several times daily, ensuring you always have an up-to-date view.
### Understanding the downstream impact of an issue
1. Alerts show the number of impacted assets. Clicking on the impacted assets brings you to the lineage view with these assets pre-filtered
2. Use the sidebar to quickly filter down to specific assets downstream, such as a Looker dashboard.
### Assessing the impact of making a change
1. Navigate to the lineage for the table you’re about to change and click on the table name in the lineage to toggle `Filter by column`
2. Filtering by a column lets you see all downstream assets where the column is being used. Click `X` to remove the column selection or `+` to expand the lineage.
3. Click on a column in one of the downstream assets to see how the column was derived in code
### Upstream lineage to trace down the issue's root cause
1. Navigate to the most downstream asset, such as a Looker dashboard you’re debugging.
2. To trace upstream issues, use the left side menu bar to filter down on, e.g., sources or transformation models with status errors.
3. Click the data asset and select `Filter by column` to trace where a specific column is used upstream.
# Custom SQL monitor
Source: https://docs.synq.io/monitor-types/custom-sql-monitor
Custom SQL monitors are flexible monitors that let you express the SQL of your choice and automatically learn a time series around it. For example
* Ensure the accuracy of a key ML input numeric feature by creating a monitor to track the feature average over time
* Set up a monitor on average revenue grouped by geography to learn about sudden increases or drops for a specific region
* Detect unexpected patterns in the number of unique users created at the source level to prevent downstream impact
*A custom SQL monitor detecting an anomaly in the average sales price for one region*
### Setting up a custom SQL monitor
1. Navigate to the table or transformation model (dbt model, SQLMesh model, Coalesce node) where you want to set up the monitor and click `Add Monitor`
2. Select `Custom SQL` to start creating a custom SQL monitor
3. Configure the monitor with the relevant settings
* **SQL metric**—any SQL expression that specifies the metric to track (e.g., `avg(revenue)`). *This must be an expression that results in a metric*
* **Time partition**—the time partition you want your data segmented by (e.g., creation\_date)
* **Days to delay**—days to ignore if you have a delay in when you expect fresh data
* **Sensitivity**-see [Configuring sensitivity](/monitors/monitor-sensitivity)
* **Custom filter**-specify filters using SQL
4. Select a `variable` to segment by (*optional*). This will create multiple time series for each segment you select to include
* To create a monitor for specific segments, toggle `Selected values` and select the desired values.
* If you select `All values`, new values are automatically added.
Be cautious of including segments with only a few data points, as the model may not be able to confidently learn a reliable confidence interval for these segments, which can lead to many false/positive alerts
5. Click `continue` to set up the monitor with the specified configurations
The monitor will appear shortly and can be found directly under the table you created it for and on the [Health page](https://app.synq.io/healthz/overview)
Custom monitors partition your data into time intervals based on the timestamp value of a selected column. It will construct a historical time series, with each time partition representing one data point. Monitor bootstraps on the past 30 days and then continue to query only the most recent time partition (to minimize query cost). This means the monitor can detect anomalies right after setting it up.
**Resetting a monitor**
If you want to rerun predictions for the past 30 days in case you made historical updates on the data, you can go to the monitor, click `Settings`, and press `Reset monitor`. This step is not reversible to only proceed if you're certain you want to reset the monitor.
# Field stats monitor
Source: https://docs.synq.io/monitor-types/fieldstats
Field stats monitors automatically track key statistical properties of one or more fields in a table and learn a time-series pattern for each metric. These monitors help you detect unexpected changes in distribution, null rates, or value ranges without writing any SQL.
Examples of what you can detect with field stats monitors:
* Sudden spikes in null or empty values after a pipeline change
* Drops in the number of unique IDs, indicating upstream duplication issues
* Unusual shifts in a numeric metric such as fare amount, order value, lead time, etc.
* Outliers in mean, max, or standard deviation that may indicate data corruption
### Metrics tracked automatically
Each selected field will automatically generate a time-series for the following metrics (depending on data type):
| Metric | Description |
| ------------------------ | -------------------------------------------------- |
| **Number of rows** | Total number of rows in the dataset |
| **Number of null** | Count of null values |
| **Percentage of Null** | Percentage of null values |
| **Number of empty** | Count of empty string values |
| **Percentage of Empty** | Percentage of empty string values |
| **Number of unique** | Count of unique values |
| **Percentage of Unique** | Percentage of unique values relative to total rows |
| **Mean** | Average value of the field |
| **Median** | Median value |
| **Min** | Minimum value |
| **Max** | Maximum value |
| **Standard deviation** | Statistical standard deviation |
### Setting up a field stats monitor
1. Navigate to the table where you want to create the monitor and click `Add Monitor`
2. Select `Field stats` and choose the fields you want to monitor\
You can monitor one or multiple fields at once.
3. Configure time partitioning. A time-series will be learned per metric per field, using the timestamp column you select.
4. Set sensitivity, and severity (optional)
Once confirmed, the monitor will appear under the table and on the [Health page](https://app.synq.io/healthz/overview)
Field stats monitors bootstrap the past 30 days of history, then only query new partitions going forward to reduce cost. Anomaly detection begins immediately after setup.
### Resetting a monitor
If you modify historical data and want to re-learn the 30-day baseline, open the monitor, go to `Settings`, and click `Reset monitor`.
This action is not reversible — only reset if you are certain the historical values have changed.
# Freshness monitor
Source: https://docs.synq.io/monitor-types/freshness-monitor
The default freshness and volume monitors have been merged into the Table stats monitor. You can see more on the [Table stats monitor page](/monitor-types/table-stats-monitor).
The freshness monitor looks at a table's timestamp and alerts you if it’s been too long since the last update.
Freshness monitors rely on your data warehouse metadata tables for timestamp information (e.g., Snowflake table [information schema](https://docs.snowflake.com/en/sql-reference/info-schema/tables)). As the monitor queries the information schema, you only incur minimal additional costs even when they are run frequently. The monitor works out of the box, which makes it easy to deploy at scale.
In most cases, we recommend combining freshness monitors with default [Volume monitor](/monitor-types/volume-monitor#default-volume-monitor) to detect when data is flowing but at a reduced rate. Read more about best practices for deploying these at [Setting up monitors](/monitors/setting-up-monitors)
Default freshness monitors are run every 60 minutes.
### Setting up a freshness monitor
1. Navigate to `Health` → `Manage monitors`
2. Click `Create monitor group` to define the tables you want to monitor
3. Use the browser to narrow down the tables you want to monitor
* **Browser**—select specific schemas or search for tables to monitor (your data warehouse tables and transformation models from dbt, SQLMesh, and Coalesce Transform are automatically mapped)
* **Annotation**—select assets with metadata definitions such as tags defined in your transformation layer (dbt, SQLMesh, or Coalesce Transform)
* **Important**—select assets that you’ve marked as important
* **Query**—advanced selection. E.g., search for specific keyword matches
To deploy freshness monitors on all sources automatically, filter by `Type: Source` (works with dbt sources, Coalesce sources, and SQLMesh external models)
4. Check `Freshness` to set up a freshness monitor group
5. Name the monitor (e.g., *freshness on all sources*).
6. Click `continue` to set up the monitor
You’ll be able to see the monitors on the [Health overview page](https://app.synq.io/healthz/overview) and adjust the monitor sensitivity.
As soon as you’ve set the monitor up, it will start learning the behaviors of your data every hour. You should expect \~10 days before the monitor has built an understanding of the seasonality and patterns in your data and is confidently able to predict anomalies
# Table stats monitor
Source: https://docs.synq.io/monitor-types/table-stats-monitor
The table stats monitor is an all-in-one monitor to detect if data is not flowing or flowing at a reduced rate. This can help you be the first to know about issues without having to maintain manual thresholds for freshness or volume
* A source that’s entirely stopped sending data
* A source that’s sending significantly fewer/more rows
* A join that causes a spike in duplicate values
*A table stats monitor highlighting a row count anomaly that’s been marked as expected*
To best possibly be able to catch different types of issues, the table stats monitor looks at three different signals
* **Row count** — the count of rows in the dataset
* **Delay** — the delay since the last time data was loaded
* **Change delay** — the delay since the last data load when at least one row was loaded
By combining the three, you’ll be more likely to detect different types of issues. For example, if an analytics engineer makes a join that creates a set of duplicate rows, the row count monitor can catch that. If an upstream source stops writing new data, the change delay monitor can catch that.
Unlike manual freshness checks (e.g., dbt source freshness or Coalesce freshness tests), all table stats are self-learning and automatically adjust to the patterns of your data. This reduces the workload on your end on defining specific thresholds.
Table stats monitors rely on your data warehouse metadata tables, such as the `row_count` from the Snowflake table [information schema](https://docs.snowflake.com/en/sql-reference/info-schema/tables). As the monitor queries the information schema, you only incur minimal additional costs even when they are run frequently. The monitor works out of the box, which makes it easy to deploy at scale.
**Setting up a table stats monitor**
1. Navigate to `Health` → `Manage monitors`
2. Click `Create monitor group` to define the tables you want to monitor
3. Use the browser to narrow down the tables you want to monitor
* **Browser**—select specific schemas or search for tables to monitor (your data warehouse tables and transformation models from dbt, SQLMesh, and Coalesce Transform are automatically mapped)
* **Type**—data asset type such as dbt source, Coalesce source, or SQLMesh external model
* **Annotation**—select assets with metadata definitions such as tags defined in your transformation layer (dbt, SQLMesh, or Coalesce Transform)
* **Important**—select assets that you’ve marked as important
* **Product**—select a data product to place monitor on or upstream of
* **SynQL**—advanced selection. E.g., search for specific keyword matches
4. Check `Table Stats` to set up a table stats monitor group
5. Name the monitor (e.g., *important sources*).
6. Click `continue` to set up the monitor
You’ll be able to see all monitors on the [Health overview page](https://app.synq.io/healthz/overview) and adjust the monitor sensitivity.
Metadata from your tables is automatically stored, so the anomaly monitor will learn the expected thresholds as soon as you set it up. If you’re just getting started or creating a new table that we don’t yet have metadata for, you should expect \~10 days before the monitor has built an understanding of the seasonality and patterns in your data and is confidently able to detect anomalies
**How frequently do the monitors run**
The table stats monitor is run every 30 minutes by default
# Volume monitor
Source: https://docs.synq.io/monitor-types/volume-monitor
The volume monitor looks at the number of rows in a table to detect how much data is added or removed and alerts you of abnormal increases or decreases. Among others, this can help you identify.
* A sudden jump in duplicate rows due to a faulty join
* A decrease in a data source due to an upstream error
* A system failure caused no new records to be inserted
*A volume monitor highlighting a sudden drop in the row count*
There are two different kinds of volume monitors. (1) [Default volume monitor](/monitor-types/volume-monitor#default-volume-monitor) and (2) [custom volume monitor](/monitor-types/volume-monitor#custom-volume-monitor). Read more about best practices for deploying these at [Setting up monitors](/monitors/setting-up-monitors)
## Default volume monitor
The default freshness and volume monitors have been merged into the Table stats monitor. You can see more on the [Table stats monitor page](/monitor-types/table-stats-monitor).
Default volume monitors rely on your data warehouse metadata tables, such as the `row_count` from the Snowflake table [information schema](https://docs.snowflake.com/en/sql-reference/info-schema/tables). As the monitor queries the information schema, you only incur minimal additional costs even when they are run frequently. The monitor works out of the box, which makes it easy to deploy at scale.
Unless you need custom functionality, such as grouping by a different time field, we recommend you use default volume monitors.
Default volume monitors are run every 60 minutes.
### Setting up a default volume monitor
1. Navigate to `Health` → `Manage monitors`
2. Click `Create monitor group` to define the tables you want to monitor
3. Use the browser to narrow down the tables you want to monitor
* **Browser**—select specific schemas or search for tables to monitor (your data warehouse tables and transformation models from dbt, SQLMesh, and Coalesce Transform are automatically mapped)
* **Annotation**—select assets with metadata definitions such as tags defined in your transformation layer (dbt, SQLMesh, or Coalesce Transform)
* **Important**—select assets that you’ve marked as important
* **Query**—advanced selection. E.g., search for specific keyword matches
4. Check `Volume` to set up a volume monitor group
5. Name the monitor (e.g., *important tables volume monitor*).
6. Click `continue` to set up the monitor
You’ll be able to see all monitors on the [Health overview page](https://app.synq.io/healthz/overview) and adjust the monitor sensitivity.
As soon as you’ve set the monitor up, it will start learning the behaviors of your data every hour. You should expect \~10 days before the monitor has built an understanding of the seasonality and patterns in your data and is confidently able to detect anomalies
## Custom volume monitor
Unlike the default volume monitor, the custom volume monitor queries your raw data. This gives you more configuration options, such as specifying a time dimension or automatically grouping by a segment. However, it also means that each monitor must be configured individually and that you may incur additional costs from running it.
Custom volume monitors are designed as *growth monitors* meaning that they look at the growth or shrink in the data relative to the previous period as specified by the time partition. This makes them suitable for detecting subtle changes or if no new data starts arriving, even for a short period.
### Setting up a custom volume monitor
1. Navigate to the table or transformation model (dbt model, SQLMesh model, Coalesce node) where you want to set up the monitor and click `Add Monitor`
2. Select `Volume` to start creating a custom volume monitor
3. Configure the monitor with the relevant settings
* **Time partition**—the time partition you want your data segmented by (e.g., *creation\_date*)
* **Days to delay**—days to ignore if you have a delay in when you expect fresh data
* **Sensitivity**—see [Configuring model sensitivity](/monitors/monitor-sensitivity)
* **Custom filter**—specify custom SQL to filter by
4. Select a `variable` to segment by (*optional*). This will create multiple time series for each segment you select to include
* If you only want to create a monitor for specific segments, toggle `Selected values` and select the desired values
* If you select `All values`, new values are automatically added.
Be cautious of including segments with only a few data points, as the model may not be able to confidently learn a reliable confidence interval for these segments, which can lead to many false/positive alerts
5. Click `continue` to set up the monitor with the specified configurations
The monitor will appear shortly and can be found directly under the table you created it for and on the [Health page](https://app.synq.io/healthz/overview)
Custom monitors partition your data into time intervals based on the timestamp value of a selected column. It will construct a historical time series, each time partition representing one data point. Monitor bootstraps on the past 30 days and then continue to query only the most recent time partition (to minimize query cost). This means that the monitor will be able to detect anomalies right after you’ve set it up
**Resetting a monitor**
If you want to rerun predictions for the past 30 days in case you made historical updates on the data, you can go to the monitor, click Settings, and press Reset monitor. This step is not reversible to only proceed if you’re certain you want to reset the monitor.
# Agent workflow
Source: https://docs.synq.io/monitors/agent-workflow
The operating guide for a coding agent driving the synqcli CLI
This page is the published copy of the operating guide that ships with the tool
as `AGENTS.md` — in the release archive and in
[getsynq/synqcli](https://github.com/getsynq/synqcli). It is deliberately
denser than the rest of this section. Start at
[Monitors as code](/monitors/monitors-as-code) for what the YAML declares, and
see the [CLI reference](/monitors/cli) for every flag.
This is the operating guide for a coding agent using `synqcli` to declare data
quality monitors, SQL tests and deployment rules as code: the loop to follow, the
mistakes that cost real time, and what each command does to a workspace. It is
written to be acted on top-down.
**`synqcli` reconciles a workspace with a YAML file.** You declare which monitors
and tests belong on which assets; `deploy` makes the workspace match. That means it
creates, it updates, and **it deletes** — anything in the file's namespace that is
no longer declared goes away. Understanding that one sentence prevents most of the
damage this tool can do.
## 1. The loop
**1. See what already exists — `export`**
Never start from a blank file against a workspace that already has monitors.
`export` writes the current state back out as YAML:
```bash theme={null}
synqcli export --namespace my_namespace current.yaml
```
That gives you the real shape of what is deployed, in the format `deploy` accepts.
Edit *that* rather than authoring from scratch, and you will not silently delete
someone's monitors.
**2. Get the schema into your editor**
```bash theme={null}
synqcli schema > schema.json
```
Then put this at the top of every config file, which gives completion and
validation as you type:
```yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-monitors/v1/config.schema.json
```
**3. Preview — `deploy --dry-run`**
```bash theme={null}
synqcli deploy config.yaml --dry-run
```
Prints the create / update / delete plan and touches nothing. **Read the delete
list every time.** This is the step that catches a wrong `namespace`, a mistyped
asset path, or a file that is missing half of what the workspace has.
**4. Deploy**
```bash theme={null}
synqcli deploy config.yaml
```
Interactive by default: it shows the plan and asks. In CI, add `--auto-confirm`,
but only once the same config has been through `--dry-run` at least once.
**5. Iterate on the diff, not the file**
Re-run `--dry-run` after every edit. An empty plan is the goal — it means the
workspace matches your file, so the config is now the source of truth.
***
## 2. Never do these
* **Never run `deploy` without `--dry-run` first** on a workspace you did not
author the config for. Deploy is a reconcile, so an incomplete file is a delete.
* **Never guess a `namespace`.** It is the grouping key: everything under one
namespace is reconciled together, and a typo means "this namespace has nothing
declared, so delete everything in it". Get it from `export`.
* **Never hand-assign monitor ids.** They are derived deterministically from the
monitor's identity, which is what makes a re-deploy an update instead of a
duplicate. Let the tool compute them.
* **Never edit the published docs or the schema by hand.** Both are generated.
* **Never assume a rename is a rename.** Changing something in a monitor's
identity produces a *new* monitor and deletes the old one — with its history.
`--dry-run` shows that as a delete plus a create; look for it.
* **Never point a config at a workspace you have not confirmed.** See below.
***
## 3. Confirm the target
Credentials resolve in this order:
1. `--client-id` / `--client-secret` flags
2. `QUALITY_CLIENT_ID` / `QUALITY_CLIENT_SECRET`
3. A `.env` file in the working directory
4. A browser login, cached and shared with the other Coalesce Quality CLIs
```bash theme={null}
synqcli auth login # browser flow
synqcli auth status # every stored credential, every region
```
Deployments are named, not spelled out: `--region eu|us|au`, or `--endpoint` for a
self-hosted deployment. `auth login` remembers the choice, so later commands need
no flag. **A wrong region is the most expensive mistake available here** — it
reconciles the wrong workspace, deleting what it does not find declared.
***
## 4. What goes in the YAML
One file declares monitors and tests per asset:
* **Monitors** watch an asset over time: `volume`, `freshness`, `field_stats`,
`custom_numeric`.
* **SQL tests** assert something is true right now: `not_null`, `unique`, `empty`,
`accepted_values`, `rejected_values`, `min_max`, `min_value`, `max_value`,
`freshness`, `relative_time`, `business_rule`, `business_query`.
* **Deployment rules** apply monitors by *query* rather than by listing assets, so
new matching assets are covered without editing the file.
Asset paths can be written in a simplified form and are resolved against the
workspace, so you do not need to spell out full warehouse coordinates.
The field-by-field reference is
[the published schema](https://schemas.synq.io/synq-monitors/v1/config.schema.json),
and it is authoritative in a way prose is not. Read it rather than inferring field
names.
***
## 5. `advisor` — propose tests for an asset
`advisor` asks the model to suggest tests for an entity, and can write them
straight into a config:
```bash theme={null}
synqcli advisor \
--entity-id "::::::
" \
--instructions "Suggest data quality tests for this table" \
--output suggested.yaml
```
Useful flags: `--columns` to narrow the scope, `--instructions-file` for a long
prompt, `--severity` for the default it assigns, `--namespace` for the group it
writes into, and `--deploy` to deploy immediately.
**Review what it writes before deploying it.** `--output` then read then `deploy --dry-run` is the safe order; `--deploy` skips your review, not the reconcile.
Instructions steer it, and being specific pays. Some that work:
```
Suggest comprehensive data quality tests for this table. Focus on:
- Primary key uniqueness
- Required fields (NOT NULL constraints)
- Data freshness monitoring
- Volume anomaly detection
```
```
This is an orders table. Suggest tests for:
- Order ID uniqueness
- Required fields: customer_id, order_date, total_amount
- Amount validation (total_amount >= 0)
- Date consistency (order_date <= ship_date)
- Status values should be: pending, processing, shipped, delivered, cancelled
```
```
This is financial transaction data. Suggest tests for:
- Transaction ID must be unique
- Amount must be non-negative
- Currency code should be valid ISO 4217
- Created timestamp must not be in the future
- Account IDs must not be null
```
```
This is time series data. Suggest tests for:
- Timestamp freshness, within the expected arrival interval
- Volume monitoring, to detect missing periods
- Metric value ranges
- No duplicate timestamps per entity
```
***
## 6. What each command costs
* `schema` — free, offline. No credentials, no API call.
* `export` — reads the workspace. Cheap.
* `deploy --dry-run` — resolves asset paths and diffs against the workspace.
Cheap, and always worth it.
* `deploy` — writes. The cost is the blast radius, not the runtime: creates,
updates and **deletes** in one pass.
* `advisor` — a model call per entity, plus warehouse metadata reads. The only
command here with a per-run cost worth thinking about; scope it with
`--entity-id` and `--columns` rather than pointing it at everything.
***
## 7. When something fails
| Symptom | Cause |
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| The plan deletes monitors you did not expect | Wrong `namespace`, or a config missing what the workspace has — `export` first |
| A monitor was recreated instead of updated | Something in its identity changed, so it is a different monitor |
| "Breaking change" refuses to deploy | Deliberate: the change would reset a monitor's baseline or a test's history |
| An asset path does not resolve | It is resolved against the workspace, so the asset must be known to Coalesce Quality first |
| Deploying to the wrong workspace | `auth status`, and check `--region` |
| A field is rejected | Check it against the published schema; strict decoding rejects unknown fields rather than ignoring them |
The full command and flag reference is generated from the CLI itself and published
as the [CLI reference](https://docs.synq.io/monitors/cli). For what the YAML
declares and why, start at
[Monitors as code](https://docs.synq.io/monitors/monitors-as-code).
# Monitors CLI reference
Source: https://docs.synq.io/monitors/cli
Every synqcli command, argument and flag, generated from the CLI itself.
This page is generated from the `synqcli` command tree, so it always matches
the released binary. For what the YAML declares and how to structure it, see
[Defining monitors in code](/monitors/monitors-as-code); the field-by-field
format is the [configuration reference](https://schemas.synq.io/synq-monitors/v1/config.html).
Manage Coalesce Quality monitors, SQL tests and deployment rules as code.
A YAML configuration declares which monitors and tests belong on which assets.
The deploy command reconciles a workspace with that configuration, export writes
what a workspace already has back out as YAML, and advisor proposes tests for an
asset. The schema command writes the JSON schema out for editor completion.
## Global flags
These apply to every command.
| Flag | Type | Default | Description |
| ----------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------ |
| `--client-id` | `string` | — | Coalesce Quality API client ID (overrides .env and environment variables) |
| `--client-secret` | `string` | — | Coalesce Quality API client secret (overrides .env and environment variables) |
| `--endpoint` | `string` | — | Coalesce Quality API endpoint, for staging or a self-hosted deployment; overrides --region (or \$QUALITY\_API\_ENDPOINT) |
| `--region` | `region` | — | Coalesce Quality deployment to use: au, eu, us (or \$QUALITY\_REGION) |
## Commands
### `synqcli advisor`
Suggest data quality tests for one or more entities
```bash theme={null}
synqcli advisor [flags]
```
The advisor command uses AI to suggest appropriate data quality tests and monitors
for one or more entities (tables) based on provided instructions.
Example (single entity, JSON output):
```bash theme={null}
synqcli advisor \
--entity-id "postgres::public::users" \
--instructions "Suggest basic data quality tests"
```
Example (single entity with YAML file output):
```bash theme={null}
synqcli advisor \
--entity-id "postgres::public::users" \
--instructions "Suggest basic data quality tests" \
--output ./tests
```
Example (multiple entities):
```bash theme={null}
synqcli advisor \
--entity-id "postgres::public::users" \
--entity-id "postgres::public::orders" \
--entity-id "postgres::public::products" \
--instructions "Suggest basic data quality tests" \
--output ./tests
```
Example (with DWH connection for data profiling):
```bash theme={null}
synqcli advisor \
--entity-id "postgres::public::users" \
--instructions "Suggest accepted_values tests for enum columns" \
--connections ./connections.yaml
```
Example (filter to specific columns):
```bash theme={null}
synqcli advisor \
--entity-id "postgres::public::users" \
--columns "status,email,role" \
--instructions "Suggest tests for these columns"
```
This will create separate YAML files for each entity in the output directory.
When --deploy is specified, all YAML files in the output directory will be deployed.
DWH CONNECTIONS:
When --connections is specified, the advisor can profile columns to:
* Discover actual values for accepted\_values tests
* Determine min/max bounds for range tests
* Check null rates and distinct counts
Connection file format (connections.yaml):
```bash theme={null}
- id: my-postgres
type: postgres
host: localhost
port: 5432
database: mydb
username: user
password: pass
```
Alternatively, configure a single connection via environment variables:
```bash theme={null}
DWH_TYPE, DWH_HOST, DWH_PORT, DWH_DATABASE, DWH_USERNAME, DWH_PASSWORD
```
Supported types: postgres, mysql, bigquery, snowflake, clickhouse, redshift, databricks
| Flag | Type | Default | Description |
| --------------------------- | ------------- | ------- | ------------------------------------------------------------------------------------------------ |
| `--auto-confirm` | `bool` | — | Automatically confirm deployment prompts (only used with --deploy) |
| `-C`, `--columns` | `stringSlice` | — | Filter test suggestions to specific columns (can be comma-separated or specified multiple times) |
| `-c`, `--connections` | `string` | — | Path to DWH connections YAML file for data profiling |
| `--deploy` | `bool` | — | Deploy generated YAML files after creation (requires --output) |
| `-e`, `--entity-id` | `stringSlice` | — | Entity ID(s) (table FQN) to suggest tests for (can be specified multiple times, required) |
| `-f`, `--force` | `bool` | — | Force overwrite existing YAML files (default: skip if exists) |
| `-i`, `--instructions` | `string` | — | Instructions for what tests/monitors to suggest (required if --instructions-file not provided) |
| `-I`, `--instructions-file` | `string` | — | Path to file containing instructions (required if --instructions not provided) |
| `-n`, `--namespace` | `string` | — | Namespace for generated YAML (default: synq-advisor) |
| `-o`, `--output` | `string` | — | Output directory path for YAML files (required if --deploy is used) |
| `-p`, `--print-protobuf` | `bool` | — | Print protobuf messages in JSON format during deployment |
| `-s`, `--severity` | `string` | — | Default severity for tests/monitors (INFO, WARNING, ERROR) |
| `-v`, `--verbose` | `bool` | — | Show verbose output including loaded schema and LLM interactions |
### `synqcli auth`
Manage Coalesce Quality API authentication
```bash theme={null}
synqcli auth [flags]
```
Manage authentication for the Coalesce Quality API.
synqcli can authenticate as a human in a browser, not only with client
credentials. Credentials are cached under \~/.synq/oauth/, partitioned by region,
and shared with the other Coalesce Quality CLIs by default.
Client credentials (--client-id / --client-secret or QUALITY\_CLIENT\_ID /
QUALITY\_CLIENT\_SECRET) and a pre-issued QUALITY\_TOKEN still take precedence over
a browser login, so CI is unaffected.
Pick a deployment with --region, or point at a staging or self-hosted deployment
with --endpoint. Both work on every command, and a successful login is
remembered — so after logging in to one deployment, later commands need neither
flag.
Examples:
```bash theme={null}
synqcli auth login
synqcli auth login --region us
synqcli auth status
synqcli auth use au
synqcli auth logout --region us
```
| Flag | Type | Default | Description |
| ---------------- | -------- | ------- | ----------------------------------------------------------------- |
| `--auth-profile` | `string` | — | Credential profile to read or write (default: the shared profile) |
#### `synqcli auth login`
Authenticate with Coalesce Quality in a browser
```bash theme={null}
synqcli auth login [flags]
```
Authenticate using the OAuth2 authorization code flow with PKCE.
Opens a browser, then caches the resulting credential under \~/.synq/oauth/. The
login asks for only the permissions synqcli needs — managing monitors, SQL tests
and query-based deployment rules, plus the reads required to resolve the assets a
check targets.
By default the credential goes to the shared slot, so one login serves every
Coalesce Quality CLI on this machine. Pass --isolated to keep it to synqcli.
| Flag | Type | Default | Description |
| ------------ | ------ | ------- | -------------------------------------------------------------- |
| `--isolated` | `bool` | — | Store a credential for synqcli alone instead of the shared one |
#### `synqcli auth logout`
Remove the stored credential for a region
```bash theme={null}
synqcli auth logout
```
Delete the cached credential for one region, leaving credentials for other
regions in place. The OAuth client registration is kept, so logging back in does
not create another connected app.
#### `synqcli auth status`
Show every stored credential, for every region
```bash theme={null}
synqcli auth status
```
List the cached credentials across all regions, with the workspace, granted
permissions and expiry of each. Reads local files only — no network calls.
Pass --region or --endpoint to show one deployment instead of all of them.
#### `synqcli auth token`
Print the access token, refreshing it if needed
```bash theme={null}
synqcli auth token
```
Print the current access token to stdout, refreshing it first if it has expired
or is close to expiring.
Useful for scripting:
```bash theme={null}
curl -H "Authorization: Bearer $(synqcli auth token)" ...
```
#### `synqcli auth use`
Show or set the deployment commands use by default
```bash theme={null}
synqcli auth use [region|endpoint] [flags]
```
Record which deployment a command talks to when it is given neither --region
nor --endpoint.
A successful login already records the deployment it authenticated against, so
this is only needed to switch between two deployments you are logged in to. An
explicit --region or --endpoint, QUALITY\_API\_ENDPOINT and QUALITY\_REGION all
still win over what is recorded here.
Called with no argument it prints the current setting.
Examples:
```bash theme={null}
synqcli auth use
synqcli auth use au
synqcli auth use developer.synq.dev:443
synqcli auth use --clear
```
| Flag | Type | Default | Description |
| --------- | ------ | ------- | ------------------------------------------------------------------ |
| `--clear` | `bool` | — | Forget the recorded deployment and fall back to the default region |
### `synqcli deploy`
Deploy custom monitors from YAML configuration
```bash theme={null}
synqcli deploy [FILES...] [flags]
```
Deploy custom monitors by parsing YAML configuration files.
Before deploying, it prints what changes will be made and prompts for confirmation,
unless --auto-confirm is set.
If no files are provided, it will recursively search for YAML files from the working directory.
| Flag | Type | Default | Description |
| ------------------------ | ------------- | ------- | ------------------------------------------------------------------------------------ |
| `--auto-confirm` | `bool` | — | Automatically confirm all prompts (skip interactive confirmations) |
| `--dry-run` | `bool` | — | Show what would be deployed without actually deploying |
| `--log-file` | `string` | — | Path to write execution log in JSONL format (or \$QUALITY\_LOG\_FILE) |
| `--namespace` | `stringSlice` | — | If set, will only make changes to the included namespaces |
| `-p`, `--print-protobuf` | `bool` | — | Print protobuf messages in JSON format |
| `--verbose` | `bool` | — | List every affected asset in the deployment-rule preview instead of capping the list |
### `synqcli export`
Export custom monitors, SQL tests, and deployment rules to YAML
```bash theme={null}
synqcli export [output-file] [flags]
```
Export custom monitors, SQL tests, and deployment rules as YAML.
By default all three resource types are exported. Use --type to narrow:
```bash theme={null}
synqcli export out.yaml # everything
synqcli export out.yaml --type=sql-tests # only SQL tests
synqcli export out.yaml --sql-test= # auto-narrows to that one test
synqcli export out.yaml --type=monitors --sql-test= # all monitors + that test
```
ID-scoped flags (--monitor, --sql-test, --deployment-rule) implicitly add
their owning type to the selection, so you rarely need --type explicitly.
| Flag | Type | Default | Description |
| ------------------- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--deployment-rule` | `stringArray` | — | Limit exported deployment rules by rule IDs. AND'ed with other scopes. |
| `--integration` | `stringArray` | — | Limit exported monitors by integration IDs. AND'ed with other scopes. |
| `--monitor` | `stringArray` | — | Limit exported monitors by monitor IDs. AND'ed with other scopes. |
| `--monitored` | `stringArray` | — | Limit exported monitors by monitored asset paths. AND'ed with other scopes. |
| `--namespace` | `string` | — | Namespace for generated YAML config |
| `--source` | `string` | `app` | Limit exported monitors by source. One of \[app api all]. Defaults to "app". AND'ed with other scopes. |
| `--sql-test` | `stringArray` | — | Limit exported SQL tests by test IDs. AND'ed with other scopes. |
| `--type` | `stringArray` | — | Limit exported resource types. Repeatable; accepted values: \[monitors sql-tests deployment-rules]. Unset = all. ID-scoped flags auto-include their type. |
### `synqcli schema`
```bash theme={null}
synqcli schema
```
Generate JSON schema.
The schema can be used in IDEs for autocomplete and validation.
# Setting up deployment rules
Source: https://docs.synq.io/monitors/deployment-rules
Deployment Rules define where and how monitors apply across your data stack. Instead of manually adding individual monitors, you can set up rules that dynamically apply the right monitors based on your data source, Data Product, or specific table groups.
**Key Benefits**:
* Faster setup – Apply monitoring in bulk instead of configuring each asset manually
* Better control – Adjust sensitivity and thresholds across multiple monitors at once
* More flexibility – Define and manage exclusions and overrides
## Setting Up Deployment Rules
* Navigate to `Deployment Rules` under `Health`
* Click **Create Deployment Rule**
* Choose the `Sensitivity` ([read more](/monitors/monitor-sensitivity)), `Severity`, and `Metrics` ([read more](/monitors/monitors-overview))
* Select the assets you want to monitor
Avoid applying rules too broadly—too many alerts can lead to noise. Use exclusions and overrides to refine rule coverage.
* You can also set up Exclusion rules to exclude specific assets from a rule under the `Deployment Rules` page.
## Adjusting & Managing Deployment Rules
Once configured, Deployment Rules will automatically apply monitoring. However, you can still refine them. On the `Deployment rules` page:
* **Edit a rule** to add/remove assets
* **Change sensitivity settings** if alerts are too frequent or too infrequent
* **Disable a rule** if it no longer applies
## Best Practices for Deployment Rules
See [Monitors overview](/monitors/monitors-overview) for best practices when setting up monitors. Specifically for deployment rules, we recommend you consider:
* **Use exclusions to reduce noise** - remove temporary tables, or datasets where fluctuations are expected.
* **Override sensitivity** - for example, for financial data configure tighter alert thresholds to detect even small anomalies. For less important data set a looser threshold to only get alerted on significant deviations.
# Monitor feedback
Source: https://docs.synq.io/monitors/monitor-feedback
Monitor feedback allows you to provide input on detected anomalies so our model can learn from your business context and reduce false positives over time.
When you update the status of an issue, you can choose from five available statuses. Only **Expected** changes the behavior of the model; the other statuses are primarily informational for cross-team communication.
## Status Types
### **Investigating** (Informational)
Use when you or your team are actively looking into the issue.
* **Effect:** No change to the model.
* **Example:** You want to communicate that the issue is being worked on to avoid duplicate investigations by other team members.
### **Expected** (Model-Affecting)
Use when the new value was expected and should no longer be flagged as an anomaly.
* **Effect:** The anomaly will be added to the model's training dataset during the next update, and thresholds will adjust to prevent similar false positives in the future.
* **Example:** You increased a metric intentionally (e.g., a new product launch spiked signups).
### **Fixed** (Informational)
Use when you have taken action to resolve the underlying issue and expect the monitor to succeed on the next run.
* **Effect:** No change to the model. By default, the issue will remain flagged until it passes at the infrastructure level (monitor falls back within threshold, transformation layer test passes, etc.).
* **Example:** Missing events in a table were restored and you expect the next run to succeed.
> **Workspace Settings:**\
> If **Fixed** is enabled under *Workspace Settings → Resolved Issue Statuses*, the issue will be immediately removed from triage and moved to a non-error state — even if it is not yet resolved at the infrastructure level.\
> **Recommended:** Keep this **unchecked** so the issue stays in error state until technically resolved.
### **No Action Needed** (Informational)
Use when no action is required and the issue will resolve itself on the next run.
* **Effect:** No change to the model.
* **Example:** A temporary data delay that you know will catch up in the next scheduled run.
### **Reset**
Use to revert a previously set status (especially *Expected*) so that the issue returns to triage and can be investigated again.
* **Effect:** Any model adjustments made due to marking as *Expected* will be undone, ensuring the monitor continues to flag this type of anomaly.
* **Example:** You initially marked an anomaly as expected, but later discovered it was a genuine issue and want the monitor to detect it again.
## Marking Statuses
You can set or change a status directly from the monitor view:
* **Investigating** – Marks the issue as being worked on.
* **Mark as Expected** – Flags the anomaly as expected and updates thresholds.
* **Mark as Fixed** – Indicates the issue has been resolved manually.
* **Mark as No Action Needed** – Indicates the issue requires no action and will self-resolve.
* **Reset Status** – Clears any previously set status so the issue is treated as new.
## Workspace Settings: Resolved Issue Statuses
Under **Workspace Settings → Resolved Issue Statuses**, you can configure which statuses automatically remove issues from triage.
* **If checked:** The issue is immediately cleared from triage and marked non-error, regardless of whether the underlying infrastructure is still failing.
* **If unchecked (recommended for Fixed):** The issue will remain in error state until technically resolved (e.g., monitor passes, transformation layer test succeeds).
By combining **Expected** for model training with careful use of **Fixed**, **No Action Needed**, and **Investigating** for team communication, you can keep noise low while ensuring genuine issues are surfaced.
# Configuring monitor sensitivity
Source: https://docs.synq.io/monitors/monitor-sensitivity
You can adjust each monitor's sensitivity to best fit your risk tolerance for the underlying data. We recommend you only adjust monitors up front if you have preconditioned expectations for your data (e.g., a monitor on a financial metric may need to detect even small changes) or adjust if a monitor triggers too often/not often enough. Monitors are set to *balanced* by default.
* **Precise**—this setting raises an anomaly even on subtle changes. It should be used when you want to detect issues with high precision (e.g., on a financial metric) and is the best fit for stable time series. Precise monitors will alert you more quickly, and won’t be able to check if the monitors return to normal in the next measurement.
* **Balanced (default)**—the default setting that raises anomalies based on a balanced threshold. The model will wait to see if the monitor returns to normal on the next measurement before alerting. Recommended for most monitors.
* **Relaxed**—this setting raises an anomaly only on significant changes. It should be used when you’re less sensitive to small changes but still want to know about significant changes. Relaxed monitors will check if the monitor returns to normal in the next two measurements before alerting you.
**Best practices for configuring sensitivity:**
Unless you have clear expectations for your data, we recommend you start with a *balanced* monitor and see how that performs on the first predictions. If the monitor is not precise enough to catch anomalies, adjust the sensitivity to *precise*. On the other hand, if you find yourself receiving too many alerts, consider changing the sensitivity to *relaxed* or rethink if you need the monitor in the first place.
## Configuring the sensitivity of one monitor
Select a monitor, and under `Settings`, select a sensitivity level. The monitor will be updated immediately to reflect the selected sensitivity level.
## Configuring the sensitivity of multiple monitors
You can adjust the sensitivity of multiple monitors in one go if you have multiple tables with similar expectations for what constitutes an anomaly.
In the [health section](https://app.synq.io/healthz/monitors), select all the monitors you want to bulk edit, click `Select action`, and `Change sensitivity` to the updated sensitivity level. All selected monitors will have their sensitivity level updated immediately.
In cases where you have many monitors, you can use the filter menu at the top to narrow down your selection. If you want to search for monitors that match a specific string, use the `Query` option.
# Defining monitors in code
Source: https://docs.synq.io/monitors/monitors-as-code
Instead of defining your monitor placement specifications in the UI, you can also provide a YML file to specify where to place monitors programmatically. This is beneficial if you prefer to manage monitor placement through code, e.g., enforce it through your CI/CD development process.
## Getting started
1. Install `synqcli` from the [releases page](https://github.com/getsynq/synqcli/releases), or follow the [installation instructions](https://github.com/getsynq/synqcli#installation) for your platform
2. Authenticate. For interactive use, `synqcli auth login` opens a browser; for CI, set up an [API Client](https://app.synq.io/settings/api) by clicking `Add client` with the following scopes
* `Edit SQL Tests`
* `Edit Automatic Monitors`
* `Edit Custom Monitors`
and pass them as `QUALITY_CLIENT_ID` / `QUALITY_CLIENT_SECRET`
3. Run `synqcli deploy` against your YAML
Every command and flag is in the [CLI reference](/monitors/cli).
## Defining monitors in code
Create a YAML file where you'll be managing the monitor setup, for example, `synq_monitors.yml`. You can split your configuration up into multiple files and use namespaces to manage individual domains or data products independently.
**Using Namespaces**
Monitors in one namespace are isolated from those in another, which helps you:
* Avoid conflicts when multiple teams manage monitors in parallel.
* Keep different pipelines or environments separate (e.g., transformation models in CI vs. external tables in prod).
* Apply ownership, defaults, and alerts consistently within a group.
You can define a `namespace` at the top of your YAML file, or override it inside individual monitor definitions when needed.
Example content of the file
This example uses the original flat `monitors:` layout, which is still accepted and is
what a file with no `version:` key is read as. New configurations should declare
`version: v1beta2` and group monitors and tests under `entities:` — see the
[examples](https://github.com/getsynq/synqcli/tree/main/examples/v1beta2).
```
namespace: "data-team-pipeline"
defaults:
severity: ERROR
monitors:
- name: freshness_on_orders
time_partitioning: created_at
type: freshness
expression: "created_at"
monitored_ids:
- orders_table_eu
- orders_table_us
- name: volume_on_logs
time_partitioning: at
type: volume
monitored_id: log_table
segmentation: "country"
filter: "country IN ('US', 'CA')"
- name: stats_on_user_fields
type: field_stats
time_partitioning: registered_at
fields:
- age
- signup_method
monitored_id: users_table
mode:
anomaly_engine:
sensitivity: BALANCED
schedule:
daily: 0
- name: custom_numeric_active_users
time_partitioning: registered_at
type: custom_numeric
metric_aggregation: "COUNT(DISTINCT user_id)"
monitored_ids:
- active_users_table
mode:
fixed_thresholds:
min: 100
max: 10000
schedule:
hourly: 15
```
## Configuring a monitor
You can define all custom monitor types as code (`freshness`, `volume`, `custom_numeric`, and `field_stats`). [Read more about each monitor type](https://docs.synq.io/monitors/monitors-overview).
### Obtaining IDs from the UI
When configuring a monitor, `monitored_id` is the full table identifier as represented in the platform. You can locate this ID by navigating to a table in the UI (using the catalog or search functionality) and copying the ID from the URL.
In the example below, `bq-synq-demo::nyc_taxi::financial_statement` will be the ID.
### Understanding the configurable parameters
Every configurable parameter, with its type and validation rules, is in the [configuration reference](https://schemas.synq.io/synq-monitors/v1/config.html). The same schema drives editor autocompletion — put this line at the top of your YAML file:
```yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-monitors/v1/config.schema.json
```
For more examples of configuring individual monitors, see the [examples directory](https://github.com/getsynq/synqcli/tree/main/examples/v1beta2).
## Verifying monitors in the UI
If you navigate to the `Settings` menu for a monitor, you can verify that it's created by code by seeing the `Monitor was created via API and can't be managed in APP` label.
# Monitors overview
Source: https://docs.synq.io/monitors/monitors-overview
Monitors are a core concept in Coalesce Quality, helping you proactively detect issues through self-learning and powerful anomaly detection
Monitors help you proactively detect issues such as missing or stale data, a change in a segment within your data, or a drop in a metric. The platform supports multiple monitor types, but it’s helpful to distinguish them by
* **Automatic monitors**—queries your metadata and can be set up with little configuration.
* **Custom monitors**—queries your raw data and requires a more custom implementation to support advanced use cases.
External tests (e.g. from dbt, SQLMesh, or Coalesce Transform) don't count toward your monitor limit. Integrate them to get a complete 360° view of your data health.
### Automatic monitors
Automatic monitor queries your metadata such as the [Snowflake Information Schema](https://docs.snowflake.com/en/sql-reference/info-schema). This means they’re easy to configure as you don’t have to define a custom time dimension. As automatic monitors only query metadata, they incur minimal additional processing costs.
The table stats monitor is an all-in-one monitor for row count, freshness, and delay. It's out recommended automatic monitor.
The freshness monitor looks at a table's timestamp and alerts you if it’s been too long since the last update.
The volume monitor looks at the number of rows in a table to detect how much data is added or removed and alerts you of abnormal increases or decreases.
The schema monitor detects changes in your environment and alerts you of added, removed, or updated fields.
### Custom monitors
Custom monitors can help detect issues more nuanced to your business, such as a custom monitor detecting a change in business metrics or a drop in one segment. Custom monitors query your raw data and should be used selectively to avoid incurring unnecessary costs. Custom monitors have to be configured individually by, e.g., specifying a time dimension, a field to group the monitor by, and custom SQL for an aggregate metric (e.g., `avg(revenue)`)
The custom volume monitor detects issues in the volume of data in a time series and is highly configurable.
The custom monitor detects issues in a time series, as represented by your specific SQL statement.
The field stats monitor detects issues in the health of a specific field (e.g., %, not null or % empty values).
### How monitors work
Most monitors are based on a time series model to predict the expected value of, e.g., the number of rows or a business metric you specified as an SQL statement. If a new data point falls significantly outside our prediction confidence interval, we alert you of an anomaly. Our model uses seasonal decomposition to build the most robust anomaly detection.
* **Seasonality**—our models account for intraday seasonality. This helps us learn if patterns, such as a spike by the start of the business day, are expected behavior.
* **Trend**—many datasets have a trend - e.g., a transactions table that’s always increasing as the business acquires more users. We detrend the data to ensure we only alert you of abnormal behaviors.
* **Sensitivity**—the algorithm looks at the past few days to understand the volatility of the data. If data changes a lot, it accepts a broader range of values. If the values are stable, they tighten the range and become more sensitive.
* **Trigger thresholds**—we detect patterns of anomalies. In case of a sharp change, we alert immediately. If we detect smaller anomalies, we wait for confirmation by the next observation to avoid triggering temporary small deviations.
### Monitor severity
Each monitor has a severity that helps you understand the current state.
* **OK**—the monitor is active, and no issues have been detected
* **Error**—the monitor is active, and an unresolved issue has been detected
* **Fatal**—the monitor is not functioning as expected (e.g., due to insufficient permissions to the data warehouse).
* **Inactive**—the monitor hasn’t yet finished learning the historical patterns of your data, or there’s not sufficient data for us to train the monitor
*Selecting a monitor shows you the current severity*
*See all monitors by type and their severity in the [Health overview](https://app.synq.io/healthz/overview)*
# Muting monitors
Source: https://docs.synq.io/monitors/muting-monitors
If you get alerted about an issue you cannot address immediately, you can snooze the alert. Snooze will suppress new alerts for the next 7 days, which gives you time to fix the underlying issue.
Both Coalesce Quality monitors and transformation layer tests (from dbt, SQLMesh, or Coalesce Transform) can be snoozed.
## Muting or unmuting a monitor
Open a monitor, click `Settings`, and toggle `Snooze all alerts` to mute the monitor for 7 days.
## Muting or unmuting multiple monitors
You can mute multiple monitors in one go.
In the [health section](https://app.synq.io/healthz/monitors), select all the monitors that you want to bulk edit, click `Select action`, and `Mute (7 Days)` to snooze the selected monitors for 7 days.
In cases where you have many monitors, you can use the filter menu at the top to narrow down your selection. If you want to search for monitors that match a specific string, use the `Query` option
# Setting up monitors
Source: https://docs.synq.io/monitors/setting-up-monitors
Anomaly monitors can help you catch important issues you may otherwise not have caught and are a core component of building reliability in business-critical data products.
## Monitor setup considerations
It’s essential to balance coverage and signal-to-noise ratio. While maximal monitoring across the stack may be appealing, it is not always the best option. It can cause alert fatigue and wear out your data team, causing important issues to be overlooked. The right monitor placement strategy can help with this.
While there’s no one-fit-all monitoring strategy, here are our recommendations for how to approach setting up monitors. Reach out to [support@coalesce.io](mailto:support@coalesce.io) to schedule a chat if you want advice on setting up monitors for your specific situation.
We've written extensively about how to best set up your monitoring in the [Data Product's guide](https://www.synq.io/guide). Here are a few guidelines.
#### Designing a Testing Strategy
A well-structured testing strategy ensures comprehensive coverage across the data platform while minimizing redundancy. This involves defining testing approaches for each layer—sources, transformations, and data products—and considering how transformation layer tests (from dbt, SQLMesh, or Coalesce Transform) complement anomaly monitors to avoid redundant testing.
#### Testing Sources
Testing at the source layer is critical because errors propagate downstream. Since this layer has the most dependencies, a strong foundation reduces the need for excessive testing further down the pipeline. See more in the [Testing sources](https://www.synq.io/guide/4-proactive-testing-and-monitoring#testing-sources) section of our guide.
#### Testing Transformations
Once sources are well-tested, transformation testing can focus on verifying changes rather than duplicating checks already performed upstream. This includes validating logic and aggregations after joins. A targeted approach ensures transformations produce accurate and reliable results without unnecessary overhead. See more in the [Testing transformations](https://www.synq.io/guide/4-proactive-testing-and-monitoring#testing-transformations) section in our guide
#### Testing Data Products
Data product testing should be targeted and ideally done by data people with the relevant domain expertise. Instead of focusing on technical aspects of data, when testing data products, you should verify the logic encoded in SQL transformations. See more in the [Testing products](https://www.synq.io/guide/4-proactive-testing-and-monitoring#testing-products) section of our guide.
## Setting up monitors
There are two ways to set up monitors.
### 1. Add a monitor to an individual table
Set up monitors one table at a time. This is great for targeted monitoring where you just want to monitor specific tables. It's also the only way to define custom monitors.
1. Navigate to the table or data model (e.g., by using the Catalog or Search functionality)
2. Click the `+Add` button and select a monitor type
### 2. Deploy monitors at scale
Use deployment rules to deploy monitors to many tables at once. For example, you can automatically add monitors to all sources upstream of a data product - the rule will also ensure that new sources added automatically will have monitors deployed.
See [Setting up deployment rules](/monitors/deployment-rules) for how to get started
# SQL Tests
Source: https://docs.synq.io/monitors/sql-tests
SQL tests let you write bespoke tests that fit your business circumstances and can be run on any table tracked in the platform through a unified workflow.
### Creating a SQL test
* Head to the [Health overview](https://app.synq.io/healthz/overview)
* In the SQL tests section, click [`Add sql test`](https://app.synq.io/healthz/sql-tests/create)
* Select the connection to execute your SQL query
* Specify a SQL query. The test is considered a success if it returns zero records. If any records are returned, the test will trigger an error, and the failed records will be stored in an [audit table](#audit-table-schema) for investigation.
* Choose a schedule (`hourly/daily`) and a time (`hh: mm`) when you want the test to run.
Running an excessive amount of tests or running a test too often will impact your data warehouse costs. Avoid running tests more often than needed
* The confirmation page will show you a summary of the setup. To make it easier to locate in the UI, you can give the test a human-friendly name.
### Editing a SQL test
* Head to the [Health overview](https://app.synq.io/healthz/overview)
* Click on [SQL tests](https://app.synq.io/healthz/monitors?filters=%5B%5B%7B%22kind%22%3A%22Type%22%2C%22types%22%3A%5B1421%5D%7D%5D%5D) to see all your SQL tests
* Select the SQL test you want to edit by clicking on it
* In the popout, navigate to the `settings` tab. Click `Edit` under SQL test configurations to edit the name, run schedule, or SQL code. To delete the test, click `Delete SQL test`
### Audit table schema
When a SQL test fails, the failed records are stored in an audit table in your data warehouse for investigation and troubleshooting. The platform automatically creates this table in your data warehouse when you configure a SQL test with `saveFailures=true`.
#### Default table name
By default, the audit table is named `synq_sql_test__audit`. The table location can be configured per integration.
#### Schema by data warehouse
The audit table schema varies slightly by data warehouse. Below are the CREATE TABLE statements for each supported platform:
```sql theme={null}
CREATE TABLE IF NOT EXISTS synq_sql_test__audit (
integration_id STRING
, sql_test_path STRING
, execution_id STRING
, rows_count INTEGER
, result STRING
, created_at TIMESTAMP
);
```
```sql theme={null}
CREATE TABLE IF NOT EXISTS synq_sql_test__audit (
integration_id STRING
, sql_test_path STRING
, execution_id STRING
, rows_count INTEGER
, result STRING
, created_at TIMESTAMP
);
```
```sql theme={null}
CREATE TABLE IF NOT EXISTS synq_sql_test__audit (
integration_id VARCHAR
, sql_test_path VARCHAR
, execution_id VARCHAR
, rows_count INTEGER
, result VARCHAR
, created_at TIMESTAMP
)
```
```sql theme={null}
CREATE TABLE IF NOT EXISTS "synq_sql_test__audit" (
integration_id TEXT
, sql_test_path TEXT
, execution_id TEXT
, rows_count INTEGER
, result TEXT
, created_at TIMESTAMPTZ
);
```
```sql theme={null}
CREATE TABLE IF NOT EXISTS "synq_sql_test__audit" (
integration_id VARCHAR
, sql_test_path VARCHAR
, execution_id VARCHAR
, rows_count INTEGER
, result VARCHAR
, created_at TIMESTAMP
);
```
```sql theme={null}
CREATE TABLE IF NOT EXISTS synq_sql_test__audit (
integration_id String
, sql_test_path String
, execution_id String
, rows_count Int32
, result String
, created_at DateTime64(8, 'UTC')
) Engine = MergeTree()
ORDER BY (integration_id, sql_test_path, execution_id, created_at)
;
```
#### Column descriptions
| Column | Description |
| ---------------- | --------------------------------------------------- |
| `integration_id` | Unique identifier of the data warehouse integration |
| `sql_test_path` | Path or identifier of the SQL test |
| `execution_id` | Unique identifier for each test execution |
| `rows_count` | Number of rows that failed the test |
| `result` | The failed records in JSON format |
| `created_at` | Timestamp when the audit record was created |
The audit table is created automatically when you run your first SQL test. Ensure the platform has the necessary permissions to create tables in your configured schema or database.
# Working with time dimensions and scheduling for monitors
Source: https://docs.synq.io/monitors/time-dimensions
When defining scheduled monitors, you can control **when** and **how** your data is evaluated through *time partitioning* and *scheduling*. These settings determine both the time window a monitor measures (e.g. “yesterday’s data”) and when the measurement occurs (e.g. “4 AM New York time”).
This guide explains how scheduling and time partitioning interact, the available configurations, and how to visualize them using the [Partition Timeline Tool](https://app.synq.io/partition-timeline-test).
## Understanding time partitioning
Every monitor requires a **time partition field**, such as `created_at` or `date`. This field defines how data is grouped over time and is used to determine which records belong to a given measurement window.
You can then choose how frequently to measure the data — daily, hourly, or down to minutes — and optionally define a delay to account for late-arriving data.
## Scheduling options
Each monitor run is defined by three parameters:
1. **Frequency** – how often the monitor runs (e.g. daily, hourly).
2. **Partition time** – the timestamp field used to group data.
3. **Time zone and offset** – when in the day the monitor executes.
By default, all monitors execute internally in **UTC** for consistency and easier debugging. You can still define schedules in your local time zone — the platform automatically converts this to the correct UTC schedule under the hood.
### Common scheduling examples
* **Daily at midnight UTC**
Measures data for the previous calendar day.
* **Daily at 2 AM UTC**
Measures data for the previous calendar day at 2AM (useful for delayed ETL jobs).
* **Daily at midnight New York**
Runs at 5 AM UTC but measures midnight → midnight in the New York time zone.
These combinations allow teams to align monitoring with pipeline completion times and business-day boundaries.
## Handling data delays
Many teams have ETL pipelines that complete several hours after midnight. In these cases, you can configure monitors to **delay execution** (for example, run at 4 AM but still measure the previous day’s partition).
This ensures freshness or volume checks evaluate complete data instead of partially loaded partitions.
## Advanced configurations
The platform supports advanced scheduling behaviors to cover all data-readiness scenarios:
* **Ignore last partition** – Skip the most recent day/hour if data isn’t yet ready (useful for delayed ingestion).
These options allow you to model both CRON-style schedules and dynamic, event-driven monitoring.
## Visualizing your configuration
You can preview how your scheduling and partitioning settings interact using the interactive partition timeline tool below. It helps you confirm exactly what data window each run will measure and when it will execute.
# Airflow
Source: https://docs.synq.io/orchestration-integrations/airflow
Integrating Airflow with Coalesce Quality
This guide will show you how to securely connect your Airflow setup to Coalesce Quality.
This integration extracts metadata about Airflow. By default, all tasks and all DAGs are reported.
To be able to finish this guide, you’ll need the following:
→ Access to modify your Airflow configuration code
⏱️ Estimated time to finish: 10 minutes.
## Setup with OpenLineage
1. In the app, create a new Airflow integration. Make sure that you select `OpenLineage` as the processing mode.
2. Once the integration has been created, use the generated token to configure Airflow to securely forward your events to the ingestion service.
Airflow uses a `transport` configuration option to define how to forward these events.
* **URL**: `https://developer.synq.io`
* **Endpoint**: `/api/ingest/openlineage/v1`
* **API Key**: Generated by the Airflow integration.
With that information, you can follow the [Airflow OpenLineage documentation](https://airflow.apache.org/docs/apache-airflow-providers-openlineage/stable/guides/user.html) to configure your Airflow instance.
### Example OpenLineage Transport Value
```json theme={null}
{
"type": "http",
"url": "https://developer.synq.io",
"endpoint": "/api/ingest/openlineage/v1",
"auth": {
"type": "api_key",
"api_key": "st-***" // redacted
}
}
```
## Setup with DataHub
1. Install the required dependencies in your Airflow
```
pip install 'acryl-datahub-airflow-plugin>=1.1.0.4' apache-airflow-providers-openlineage
```
For detailed installation instructions and compatibility information, see the [DataHub Airflow documentation](https://docs.datahub.com/docs/lineage/airflow).
3. Setup the REST hook
* `conn-host`: `https://datahubapi.synq.io/datahub/v1/`
* `conn-password`: Token you obtain when you click 'Create' on this page
```
airflow connections add --conn-type 'datahub_rest' 'datahub_rest_default' --conn-host '' --conn-password ''
```
### Airflow 2.7+ with OpenLineage Provider
If you're using Airflow 2.7+, the native Airflow OpenLineage provider will improve the quality of lineage and metadata information obtained from your Airflow setup. The OpenLineage provider package is already included in the installation above since the DataHub plugin requires it.
For AWS MWAA, add both `acryl-datahub-airflow-plugin` and `apache-airflow-providers-openlineage` to your `requirements.txt` file.
## Log Forwarding
Log forwarding is required to include full task failure logs in alerts. Multiple methods are supported:
### AWS MWAA CloudWatch Logs
For AWS Managed Workflows for Apache Airflow (MWAA), you can forward logs from CloudWatch using the `synq-aws-cloudwatch` Lambda function:
1. **Deploy the Lambda function**: Use the [synq-aws-cloudwatch](https://github.com/getsynq/synq-aws-cloudwatch) repository to deploy a Lambda function that forwards CloudWatch logs to Coalesce Quality.
2. **Configure log forwarding**: The Lambda automatically forwards Airflow logs from CloudWatch when properly configured with your credentials.
3. **Set up log group subscription**: Configure CloudWatch to trigger the Lambda when new Airflow logs are available.
### API Endpoint
You can also send logs directly using the [API endpoint](/api-reference/synqingestairflowv1airflowlogsservice/ingestlog). This endpoint accepts Airflow log data for processing and analysis.
### Remote Logging (S3/GCS)
You can also upload logs after files are created on S3 or GCS using Airflow's Remote Logging feature. For assistance with this setup, please reach out to our support team.
## Read more
For more information about the plugins used to collect task execution and lineage data:
* [DataHub documentation on the Airflow plugin](https://datahubproject.io/docs/lineage/airflow/)
* [DataHub source code](https://github.com/datahub-project/datahub/blob/master/metadata-ingestion/src/datahub_provider/client/airflow_generator.py)
* [OpenLineage documentation](https://openlineage.io/docs/)
* [Airflow OpenLineage source code](https://github.com/apache/airflow/tree/main/providers/openlineage)
# Airflow + dbt Core Linking
Source: https://docs.synq.io/orchestration-integrations/airflow-dbt-core
Link dbt models to Airflow tasks and view orchestration context
This guide explains how Coalesce Quality automatically links your dbt models with the Airflow tasks that execute them, providing end-to-end visibility from orchestration to data models.
**Prerequisites:**
* [Airflow integration](/orchestration-integrations/airflow) configured
* [dbt Core integration](/dbt-integrations/dbt-core) with `synq-dbt` v2.0.0+ installed
* `synq-dbt` running within Airflow tasks
* Valid integration token
⏱️ **Estimated time:** Already works automatically if prerequisites are met
# How it works
When you run dbt Core commands using `synq-dbt` inside Airflow tasks, the Airflow execution context is automatically captured and linked to your dbt models. This creates a bidirectional connection between your orchestration layer and data models.
**What you get:**
* **Model → Airflow**: See which Airflow tasks executed each dbt model, with DAG and task information on model pages
* **Airflow → Models**: View all dbt models executed by an Airflow task, with run status and metrics
* Visualize orchestration in the lineage view (Orchestration mode)
* Historical tracking of model executions (last 30 days)
* **Airflow context in issues**: When a model fails, the specific Airflow DAG and task information is included in the issue, making it easier to identify and troubleshoot failures
# Automatic context collection
When `synq-dbt` uploads your dbt artifacts (`run_results.json`), it automatically detects and collects Airflow-specific environment variables:
**Required variables** (for linking to work):
* `AIRFLOW_CTX_DAG_ID` — DAG identifier
* `AIRFLOW_CTX_TASK_ID` — Task identifier
* `AIRFLOW_CTX_DAG_RUN_ID` — Unique run identifier
* `AIRFLOW_CTX_TRY_NUMBER` — Retry attempt number
**Optional variables** (enhance tracking and context):
* `AIRFLOW_CTX_DAG_OWNER` — DAG owner
* `AIRFLOW_CTX_EXECUTION_DATE` — Execution timestamp
These environment variables are automatically set by Airflow in your task execution context. You don't need to manually configure them — they're available in the task environment. However, when using operators like `KubernetesPodOperator`, you need to explicitly pass them using Jinja templating as shown in the setup examples below.
# Setup verification
If you've already set up both integrations, the linking is already active. To verify:
## 1. Check your Airflow setup
Ensure you're using `synq-dbt` to execute dbt commands in your Airflow tasks:
**Example with KubernetesPodOperator:**
```python theme={null}
KubernetesPodOperator(
env_vars={
"SYNQ_TOKEN": Variable.get("SYNQ_TOKEN"),
# Required: Airflow context for linking
"AIRFLOW_CTX_DAG_ID": "{{ dag.dag_id }}",
"AIRFLOW_CTX_TASK_ID": "{{ task.task_id }}",
"AIRFLOW_CTX_DAG_RUN_ID": "{{ dag_run.run_id }}",
"AIRFLOW_CTX_TRY_NUMBER": "{{ task_instance.try_number }}",
# Optional: Additional context
"AIRFLOW_CTX_EXECUTION_DATE": "{{ execution_date }}",
"AIRFLOW_CTX_DAG_OWNER": "{{ dag.owner }}",
# Non-EU workspaces only:
# "SYNQ_API_ENDPOINT": "https://api.us.synq.io" # or https://api.au.synq.io
},
cmds=["synq-dbt"],
arguments=["build"],
# ... other configuration
)
```
**Regional Configuration:** EU region customers (default) don't need to set `SYNQ_API_ENDPOINT`. US and AU region customers must add it to `env_vars` — `"https://api.us.synq.io"` or `"https://api.au.synq.io"`.
**Example with DbtRunOperator:**
```python theme={null}
dbt_run = DbtRunOperator(
dbt_bin='synq-dbt',
env={
"SYNQ_TOKEN": Variable.get("SYNQ_TOKEN"),
# Required: Airflow context for linking
"AIRFLOW_CTX_DAG_ID": "{{ dag.dag_id }}",
"AIRFLOW_CTX_TASK_ID": "{{ task.task_id }}",
"AIRFLOW_CTX_DAG_RUN_ID": "{{ dag_run.run_id }}",
"AIRFLOW_CTX_TRY_NUMBER": "{{ task_instance.try_number }}",
# Optional: Additional context
"AIRFLOW_CTX_EXECUTION_DATE": "{{ execution_date }}",
"AIRFLOW_CTX_DAG_OWNER": "{{ dag.owner }}",
# US: "SYNQ_API_ENDPOINT": "https://api.us.synq.io"; AU: "https://api.au.synq.io"
},
# ... other configuration
)
```
## 2. Run a dbt task in Airflow
Execute any DAG that runs dbt models using `synq-dbt`.
Artifacts and linking data typically appear within minutes of upload under normal conditions. Wait 5-10 minutes after your first execution for metadata to sync before checking.
## 3. View linked data
### On model pages
Navigate to any dbt model page to see:
* **Airflow Execution History**: Recent task executions that ran this model
* **DAG Information**: Which DAG and task executed the model
* **Execution Timestamps**: When the model was last executed via Airflow
### On Airflow execution pages
Navigate to any Airflow task execution page to see:
* **Executed dbt Models**: Complete list of all dbt models that ran in this task
* **Model Run Status**: Success/failure status for each model
* **Execution Details**: Runtime, rows affected, and other metrics per model
* **Direct Links**: Quick navigation to individual model pages
### In lineage view
1. Open **Lineage**
2. Switch to **Orchestration mode** (toggle in the view settings)
3. View your complete data pipeline including:
* Airflow DAGs and tasks
* dbt models executed by each task
* Connections between orchestration and data layers
# Airflow context in issues
When a dbt model fails during execution in an Airflow task, the issue is automatically enriched with Airflow execution context. This helps you quickly identify which specific DAG and task encountered the failure.
**Information included:**
* **DAG ID**: The Airflow DAG that was running
* **Task ID**: The specific task within the DAG that executed the failed model
* **Execution Date**: When the failure occurred
* **DAG Run ID**: Unique identifier for the DAG run
* **Owner**: DAG owner for faster escalation
This context appears directly in the issue details, allowing you to:
* Jump directly to the relevant Airflow task logs
* Identify if the failure is specific to a particular orchestration path
* Correlate model failures with DAG execution patterns
* Route issues more effectively based on DAG ownership
The Airflow context is captured at the time of execution and remains associated with the issue, even if you investigate it later.
# Troubleshooting
## Models not showing Airflow context
**Check the following:**
1. **Using synq-dbt**: Verify you're running `synq-dbt` instead of `dbt` in your Airflow tasks
2. **synq-dbt version**: Ensure you're using v2.0.0 or later (run `synq-dbt --version`)
3. **Environment variables passed**: Verify that required Airflow context variables (`AIRFLOW_CTX_DAG_ID`, `AIRFLOW_CTX_TASK_ID`, `AIRFLOW_CTX_DAG_RUN_ID`) are being passed to your operator
4. **Regional endpoint**: US region customers must set `SYNQ_API_ENDPOINT=https://api.us.synq.io`, AU customers `https://api.au.synq.io`
5. **Recent execution**: Linking shows executions from the last 30 days
6. **Airflow version**: Ensure your Airflow version sets the context variables (supported in Airflow 1.10+)
7. **Upload success**: Check that `synq-dbt` successfully uploaded artifacts (check task logs for upload confirmation)
8. **Network connectivity**: Verify outbound HTTPS access to `developer.synq.io:443` (EU), `api.us.synq.io:443` (US) or `api.au.synq.io:443` (AU)
## Lineage not showing orchestration
1. **Orchestration mode enabled**: In Lineage view, ensure "Orchestration mode" is toggled on
2. **Airflow integration active**: Verify your [Airflow integration](/orchestration-integrations/airflow) is properly configured
3. **Metadata sync**: Wait 5-10 minutes after first execution for metadata to sync
# Learn more
* [Airflow integration guide](/orchestration-integrations/airflow) — Connect Airflow to Coalesce Quality
* [dbt Core integration guide](/dbt-integrations/dbt-core) — Install and configure synq-dbt
* [synq-dbt GitHub repository](https://github.com/getsynq/synq-dbt) — Source code and advanced configuration
# Creating an owner
Source: https://docs.synq.io/ownership/creating-an-owner
### Create an owner
1. Navigate to `Owners` and `Create an owner`
2. Name the owner (e.g., `product analytics`)
### Link ownership with Slack
Linking an owner to Slack enables you to send notifications to a dedicated Slack channel and tag the relevant owner(s) in Slack based on their Slack handle.
1. Click `@Add Slack`
1. If it’s your first time setting up Slack, click `Connect to Slack` to grant the necessary permissions. See more in [Slack integration](/slack/slack)
2. Select a Slack channel from the drop-down list to send notifications.
3. Select one or multiple Slack user handles or Slack user groups to be notified of issues on assets owned by them (optional).
If you want to send alerts to a private Slack channel, you must first type `@Coalesce Quality` in the private channel and invite the app.
### Link ownership with email
Linking an owner with one or multiple email addresses lets you notify the relevant owner(s) via email.
1. Click `Add Email` to link an owner to an email address.
2. Click `Add Another email` to link an owner to another email address (optional).
### Add assets to an owner
There are three ways to assign assets to an owner: (1) Data product, (2) Custom query, and (3) All assets.
1. Click `Add owned assets` and select one of the three options to add assets to the owner.
1. Data product—use this to attach an existing data product to the owner
2. Custom query—use this to specify assets using the browser or one of the other filter options
3. All assets—use this if you want to be notified of any issue in your workspace (e.g. if the owner is `data team`)
### Set alerts for an owner (optional)
By setting alerts on an owner, the owner will automatically be notified in the specified Slack channel or email address(es) you specified
1. To enable alerts for the assets you selected for the owner, toggle `Setup alerts`
2. Set the options based on your preference and click `continue` to set up the owner
# Domains
Source: https://docs.synq.io/ownership/domains
Domains help you organize your data assets by letting people see only the data they should care about. Domains can be set to fit existing definitions (e.g., using metadata from dbt, SQLMesh, or Coalesce Transform), or can have custom definitions built with the UI drop-down menu.
*Quickly filter down key data assets by domain to see what matters to you. Members of your workspace can only see data that belongs to domains they’re in, helping you keep things simple as you scale.*
### Setting up a Domain
1. Navigate to `Settings` → `Domains` and click `Create`
2. Give your Domain a name and a description
3. Click the newly created domain and select data assets that belong to the domain. This can be Data Products or individual data assets
4. Add members to the domain by clicking `Add Member`. These members will belong to the domain and be able to see all the data assets you selected above. The member must already exist in the workspace for you to be able to add them.
### Working with subdomains
Subdomains are helpful if you have larger domains (e.g., Marketing) with clearly distinguishable areas (e.g., performance marketing, brand marketing).
To set up one or more subdomains:
1. Navigate to a domain
2. Click `Add sub-domain`
3. Name your subdomain, and select relevant assets and members.
### Member roles in domains
* Admin users can toggle between all domains, as well as see data across domains using the default `ALL` domain selector.
* All other user roles will only see data for domains they belong to. Read more about [user roles](https://docs.synq.io/admin/user_roles). In cases where no domain has been set, all users will be able to see all data.
You can select a member in the workspace, and click the three dots to set a domain as their default, which will make it their default data access each time they open the platform.
### How does the domain impact access to data
Domains provide a limited view into the data ecosystem for a user. While the limits are intended to help them focus on the data they are interested in, they will still be able to access any data asset, including the lineage in and out of their domain of interest. Domains are not meant to implement data access controls. We recommend that these controls should be put directly in your data storage (e.g., your data warehouse).
# Ownership overview
Source: https://docs.synq.io/ownership/ownership-overview
Owners clarify ownership of data assets and active workflows that help owners stay informed about the health and status of their data
Ownership can be set up both within and outside the data team to, e.g., notify an upstream engineering team of issues on a data source created by them.
Defining ownership lets you.
* Group related data assets and their health by owner group to make it easier to take action.
* Alert or tag the relevant people in Slack based on the status of assets they own.
* Assign owners to a data product to foster a sense of responsibility within the data stack.
*An overview of example owners and their associated ownerships. You can create an unlimited number of owners*
### Create an owner
1. See [Creating an owner](/ownership/creating-an-owner)
### Editing or deleting an owner
1. Navigate to `Owners` and click the three dots to `Edit` or `Delete` an owner
### Ownership best practices
While there’s no one-fit-answer to ownership, we’ve seen these approaches work well.
[We’re always up for a chat](https://calendly.com/d/yvm-cdr-r3z/synq-intro) if you want advice on setting up ownership for your specific situation.
* **Start small and don’t overthink it**—if you’re just getting started, you don’t have to define owners for all your data assets. Instead, start by defining the smallest possible amount of data assets that are most critical for your business. Data Products ([Data products overview](/data-products/data-products-overview)) is a good starting point.
* **Beware of individual ownership**—use existing groups to define ownership that already represents how your company works. Beware of defining owners as individuals (e.g., `John Doe`). Instead, use a group that represents their function (e.g., `product analytics`) even if there’s only one person in the group. This makes it easier to manage if people move around or leave your company.
* **Get buy-in outside the data team**—before you start routing alerts to upstream teams, ensure that you clearly agree on what’s expected when they receive an alert.
* **Integrate ownership into your existing workflows**—for example, integrating ownership into your Slack or email alerting is a great way to drive accountability and see action from the work you put into defining owners.
* **Be consistent**—be consistent in how you define ownership and at what level so different teams don’t make their own interpretations.
# Agent workflow
Source: https://docs.synq.io/reconciliation/agent-workflow
The operating guide for a coding agent driving the synq-recon CLI
This page is the published copy of the operating guide that ships with the tool
as `AGENTS.md` — in the release archive, in
[getsynq/synq-recon](https://github.com/getsynq/synq-recon), and at
`/opt/synq-recon/AGENTS.md` inside the Docker image. It is deliberately denser
than the rest of this section. Start at
[Getting started](/reconciliation/getting-started) if you want the guided
version, and see the [CLI reference](/reconciliation/cli) for every flag.
This is the operating guide for a coding agent using `synq-recon` to author,
validate, run, promote and investigate a reconciliation suite: the loop to
follow, the mistakes that cost real time, how to read the output, and what each
command spends. It is written to be acted on top-down.
A **reconciliation** compares one dataset in a source database against one in a
target database and reports whether they agree. A **suite** is a YAML file
holding several reconciliations plus the connections they use. Only counts and
checksums leave the database by default — no row values.
## 1. The loop
Work through these in order. Each step has a condition for moving on; do not
skip ahead, because every later step is more expensive than the one before it.
**1. Validate offline — `check-config suite.yaml`**
Parses the YAML, checks required fields, and warns about time-dependent SQL.
Costs nothing, touches no database.
> Move on when it prints `Configuration check passed!`. Fix errors here rather
> than discovering them mid-run. Warnings about `NOW()` / `CURRENT_DATE` are
> real — see [Never do these](#2-never-do-these).
**2. Validate against the databases — `check-config suite.yaml --db`**
Connects to every connection, runs each query through the database's query
planner (`LIMIT 0`), and reports the resolved columns. It also reports table
size, primary/partition keys, a suggested key column, and warns when the key
column you chose is not indexed.
> Move on when every connection is `OK` and every query validates. A failure
> here is a wrong table name, a missing grant, or a column that does not exist —
> all of which would otherwise surface as a confusing mid-run error.
>
> `--db` does **not** run the suite's `setup:` SQL, so a suite whose tables are
> created by `setup` will report every query as failed. That is expected; skip
> to step 3 for such suites.
**3. Compare — `run-check suite.yaml`**
One query per side: total row count and checksum. Fast and cheap regardless of
table size.
> If it reports `MATCH`, the datasets agree and you are done.
> If it reports `MISMATCH`, go to step 4. Exit code 1 means "differences found",
> which is a result, not a failure.
**4. Locate — `run suite.yaml --auto-drill`**
Runs the quick check, then bisects the key space on whatever mismatched to
narrow the difference to specific key ranges. `run-drill` does the same without
re-running the quick check.
> Move on when the drill reports mismatch leaves with usable key ranges. If it
> reports thousands of leaves, stop and read
> [Never do these](#2-never-do-these) — you are drilling something that should
> be localised with an aggregate comparison first.
**5. Save to the workspace — `upload-config suite.yaml`**
Stores and versions the suite in your Coalesce Quality workspace, where it
appears under **Development**. Requires `SCOPE_RECON_EDIT`.
> Run `auth whoami` first. Move on when it prints the suite id.
**6. Run it on the backend — `run-remote --wait`**
Executes the suite in Coalesce Quality against workspace integrations rather
than against databases this machine can reach. Connections bind to integrations
by name; override with `--map connection=integration_id`.
> Move on when the run completes. `--wait` exits `0` if everything passed, `1`
> if a `--fail-on` condition was hit, `2` if execution itself failed.
> **Pass `--drill=false` explicitly if you do not want a drill** — omitting the
> flag does not mean "off".
**7. Publish to production — `promote `**
Creates a deployment: an immutable snapshot of the suite plus an optional
schedule, so it runs on its own and its results become platform assets, checks
and issues. Requires `SCOPE_RECON_PROMOTE`.
> A deployment is a snapshot, not a pointer: editing the suite afterwards
> changes nothing in production until you re-promote. Re-promoting preserves
> settings you omit; a *fresh* promote applies defaults, and the drill default
> on a fresh promote is **on**.
**Any time after a run:** `recheck ` re-executes what it ran and reports
what moved; `drill-deeper ` continues its drill from where it stopped. Both
take a local audit-log file or the invocation id of a stored run. See
[Investigating a finished run](#7-investigating-a-finished-run).
***
## 2. Never do these
Each of these has already cost someone real time.
**Do not hand-query the warehouse to "check something first."** Express the
question as a reconciliation and let `synq-recon` run it — that way the result
is recorded, reproducible, and comparable to the next run. If the tool cannot
express what you need, that is a bug worth reporting, not a reason to open a SQL
client.
**Do not commit `.connections.yaml`, or any credential, ever.** Keep the real
file git-ignored and commit only a `.connections.yaml.example` whose values are
`${ENV_VAR}` placeholders. A suite YAML with a literal secret in it is also a
suite you cannot safely `upload-config`.
**Do not run a threshold-1 drill over a table with tens of thousands of genuine
differences.** Bisection is O(log n) when the data is *mostly* identical; when
most rows differ it cannot halve, and it degenerates into thousands of queries
that each rescan a large slice of the table. Localise first: an aggregate
comparison (`mode: aggregate`, a `COUNT` measure grouped by the natural
partition) tells you *which* groups diverge in roughly one query per side. Then
drill a query narrowed to those groups.
**Do not omit `--drill` on `run-remote` and expect no drill.** Unlike `promote`,
where an omitted flag preserves the stored setting, an ad-hoc run has no
deployment to inherit from, so an omitted `--drill` falls through to each
reconciliation's own `bisection.enabled` in the YAML. Pass `--drill=false`.
**Do not put `NOW()`, `CURRENT_DATE` or `GETDATE()` in a query.** They evaluate
at slightly different instants on the two sides, which manufactures differences
that are not there. Use a template variable, resolved once and interpolated into
both sides:
```yaml theme={null}
variables:
start_date: "{{ today - 7d }}"
end_date: "{{ today }}"
```
`check-config` warns about this; `strict_time_references: true` makes it an
error.
**Do not synthesise a concatenated key.** For a multi-column natural key, declare
`key_columns: [workspace, path]`. Bisection then orders and range-filters on the
column *tuple*, so a matching primary key or index still prunes each segment. A
synthetic `a || '|' || b` key cannot use the index and forces a full scan per
segment.
**Do not compare a lagging replica without a cutoff.** If the target trails the
source, rows still in flight look like missing rows. A `cutoff:` derives a
watermark from the data itself and filters both sides to at-or-below it. See
[Cutoffs](#avoiding-false-differences).
***
## 3. Confirm the target before any mutation
Every command that writes to a workspace — `upload-config`, `promote`,
`unpromote`, `trigger`, `run-remote`, `deployment …`, `suite delete`,
`runs cancel` — acts on whichever workspace your credential resolves to.
```bash theme={null}
synq-recon auth whoami
```
Read the `workspace:` line and confirm it is the one you mean **before** the
mutation, not after. There is deliberately no `--workspace` override: your
credential determines the target, so the way to change it is to change the
credential.
Credentials resolve in a fixed order, so an automated pipeline never silently
picks up a developer's browser login:
1. Client credentials — `--client-id` / `--client-secret`, or
`QUALITY_CLIENT_ID` / `QUALITY_CLIENT_SECRET`, or the `synq:` block in the suite.
2. An API token — `QUALITY_TOKEN`.
3. The browser login cached by `synq-recon auth login`, refreshed automatically.
`--region eu|us|au` selects the deployment, and `--endpoint` (or
`QUALITY_API_ENDPOINT`) points at a staging or self-hosted one. Both are root
flags, so they work on every command. Whichever you use also selects *which
region's* stored credential is used — a token minted for one region is never
sent to another.
You rarely need either: `synq-recon auth login --region au` records the
deployment, and later commands resolve to it. `synq-recon auth use `
switches between deployments you are already logged in to, and
`auth use --clear` goes back to the default (`eu`). Resolution order is
`--endpoint` > `--region` > the suite's `synq.endpoint` > `QUALITY_API_ENDPOINT`
> `QUALITY_REGION` > the last login > `eu`.
The `--synq-`-prefixed flags and `SYNQ_`-prefixed variables are the previous
spellings and still work.
Permissions: `SCOPE_RECON_READ` to inspect, `SCOPE_RECON_EDIT` for
`upload-config`, suite edits and reporting a locally executed run's results,
`SCOPE_RECON_PROMOTE` to promote or trigger. All three can be granted to a
workspace API client, so every command works unattended.
***
## 4. Authoring a suite
The smallest useful suite is a connection pair and one reconciliation:
```yaml theme={null}
name: orders-consistency
title: "Orders consistency"
connections:
gateway:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
warehouse:
snowflake:
account: myorg.us-east-1
warehouse: COMPUTE_WH
role: ANALYST
username: ${SF_USER}
password: ${SF_PASSWORD}
databases: [ANALYTICS]
reconciliations:
orders-daily:
source:
connection: gateway
table: public.orders
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
mode: row_checksum
```
Points that decide whether it works:
* **`table:` beats `query:` when you can use it.** With `table:` the tool
resolves the columns for you and you can narrow with `columns:`,
`exclude_columns:` and `where:`. Reach for `query:` only when the comparison
genuinely needs SQL.
* **Key columns drive everything.** Bisection orders and range-filters on them,
so they must be unique and, ideally, indexed. `check-config --db` suggests one
and warns if yours is not indexed.
* **Modes.** `row_count` compares counts only (fastest, misses modified values);
`row_checksum` compares counts and a checksum of every column (the default,
catches any difference); `aggregate` compares grouped measures like `SUM` and
`COUNT` with a tolerance, and drills down through a `group_columns` hierarchy.
`full` is an accepted legacy spelling of `row_checksum`; write `row_checksum`.
* **Column names differing only in case match automatically.** For genuinely
different names use `column_mapping`.
* **Keep credentials out of the suite.** Put them in a git-ignored
`.connections.yaml` (auto-discovered, or passed with `--connections`) keyed by
the same connection names. This is also what lets the same suite run locally
and in the workspace, where the names bind to integrations instead.
The exhaustive field list is the published schema, at a stable versioned URL:
* [Configuration reference](https://schemas.synq.io/synq-recon/v1/config.html) —
every field, type, constraint and default, rendered.
* [`config.schema.json`](https://schemas.synq.io/synq-recon/v1/config.schema.json)
— the machine-readable form. Point your editor at it for completion and
validation:
```yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-recon/v1/config.schema.json
```
One field there is not yours to set: `motherduck_account` appears under the
DuckDB connection because the loader populates it internally. Write `database:`
with the MotherDuck account name, and pass `motherduck_token`.
### Avoiding false differences
Comparing two live systems is a moving target, and most "the data is wrong"
findings are really a comparison window problem. Reach for these first.
| Symptom | Use | What it does |
| ------------------------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Target lags the source; the tail looks "missing" | `cutoff:` | Derives a watermark from the data on each side, combines them (`min` by default — the point both sides have certainly reached), optionally truncates and offsets it, and filters both sides to at-or-below it. |
| Only the recent window matters | `window:` | Restricts the comparison to a lookback period. |
| Queries need a date or an id boundary | `variables:` | Resolved once, interpolated into both sides, recorded in the audit log. Override per run with `--var key=value`. |
| Comparing against a point-in-time snapshot | `as_of:` | Time-travel query on platforms that support it. |
***
## 5. Reading the output
**Pick your format explicitly.** `-o` defaults to `table` for a human terminal
and to `toon` when an AI-agent environment marker is present — so as an agent
you will get `toon` unless you say otherwise. Anything parsing output must pass
`-o json`.
**`run`, `run-check` and `run-drill` render only two shapes:** `-o json`, and a
text report for every other value. `--jq`, `--columns`, `--no-headers` and
`--wide` do not apply to them; pipe their `-o json` through `jq` yourself. The
workspace commands (`suite`, `deployment`, `runs`, `audit-logs`, `connections`,
`auth`) honour all six formats and all four flags.
**`run --auto-drill -o json` is not a single JSON document.** It emits the
quick-check document, then a plain-text banner, then one drill document per
drilled reconciliation. To parse the results, run the two stages separately —
`run-check -o json` then `run-drill -o json` — each of which is one valid
document.
```bash theme={null}
# names that differ
synq-recon run-check suite.yaml -o json | jq -r '.results[] | select(.match == false) | .name'
# key ranges where the difference lives
synq-recon run-drill suite.yaml --include orders-daily -o json \
| jq -r '.mismatch_leaves[] | "\(.segment.min_key) .. \(.segment.max_key)"'
# ready-to-run SQL for one difference, both sides
synq-recon run-drill suite.yaml --include orders-daily -o json \
| jq -r '.investigation_queries[0] | .source_query, .target_query'
```
**Logs go to stderr, results to stdout.** Redirect with `2>/dev/null`, never
`2>&1`, when piping `-o json`.
**Exit codes.** Locally executed commands: `0` everything matched, `1`
differences were found *or* the command failed. For `run-remote --wait` and
`trigger --wait` the codes are data-driven and finer: `0` passed, `1` a
`--fail-on` condition was met (default `mismatched,failed`), `2` the run itself
failed. A run can succeed and still report a mismatch — that is the normal case.
`--fail-on=passed` inverts the test for a "these should differ" canary.
**Audit logs.** `--audit-log ` writes the full record of a run — every
query, timing, count, checksum and mismatch leaf — as JSON. Pass a directory
(trailing `/`) for an auto-named file. Its shape is the published AuditLog
schema — [rendered](https://schemas.synq.io/synq-recon/v1/audit-log.html), or
[`audit-log.schema.json`](https://schemas.synq.io/synq-recon/v1/audit-log.schema.json)
to validate against.
Useful paths, using the local file's casing:
```bash theme={null}
jq -r '.reconciliations[].reconciliation.name' audit.json
jq -r '.reconciliations[].stages[].quick_check_result? | select(.) | "\(.source_count) vs \(.target_count)"' audit.json
jq -r '.reconciliations[].stages[].bisection_result?.mismatch_leaves[]?.segment | "\(.min_key)..\(.max_key)"' audit.json
```
Each mismatch leaf also carries a `drill_stop_reason` saying why drilling stopped
there, `diff_queries` with ready-to-run SQL for both sides, and every
`mismatch_types` that applies — so a segment differing in both size and content
reports two:
| Value | Meaning |
| ----------------------------------------- | ------------------------------------------------------------------ |
| `SEGMENT_MISMATCH_TYPE_MISSING_IN_TARGET` | Rows on the source side, none on the target — a real gap. |
| `SEGMENT_MISMATCH_TYPE_MISSING_IN_SOURCE` | Rows on the target side, none on the source — usually an orphan. |
| `SEGMENT_MISMATCH_TYPE_COUNT_MISMATCH` | Both sides have rows, but not the same number. |
| `SEGMENT_MISMATCH_TYPE_DATA_MISMATCH` | Both sides have rows and the checksums disagree — a value changed. |
Count direction alone does not classify a difference: a target with one row *more*
can still be missing a live row and carrying two orphans. Read the types.
Two traps in the same file:
> **Casing.** The local `--audit-log` file is snake\_case (`bisection_result`,
> `mismatch_leaves`). The same log fetched from the workspace with
> `audit-logs get -o json` is camelCase (`bisectionResult`,
> `mismatchLeaves`). A `jq` path written for one source silently returns `null`
> against the other.
> **Counts are strings.** Row counts and checksums are 64-bit integers, which
> JSON encodes as quoted strings in the audit log (`"source_count": "10"`) —
> unlike `run-check -o json`, where they are numbers. Compare with `tonumber`.
***
## 6. What each command costs
Reconciliation runs real queries against real warehouses, and on a
consumption-priced warehouse those queries cost money. Know which commands spend
before you put one in a loop.
| Command | Warehouse cost |
| ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `check-config` | None. Never connects. |
| `check-config --db` | One planner call per query (`LIMIT 0`, no scan) plus a table-metadata sweep. |
| `run-check` | One aggregate query per side. Scans the compared columns once. |
| `run-drill`, `run --auto-drill` | One bucketed query per bisection level per side. Cheap on mostly-identical data, expensive when most rows differ. |
| `recheck`, `drill-deeper` | Same as the stage they replay, but scoped to what the previous run left open — usually much cheaper than starting over. |
| `upload-config`, `promote`, `suite …`, `deployment …`, `runs …`, `audit-logs …` | None. Workspace API only. |
| `run-remote`, `trigger` | The run's cost, spent by the backend against workspace integrations. |
Two things worth knowing specifically:
**`check-config --db`'s table analysis can scale with warehouse size, not suite
size.** On platforms with no table-scoped metadata API — BigQuery in particular —
enumerating table metadata walks the datasets rather than jumping straight to
the tables your suite names. On a large warehouse that is slow and not free.
This is why the analysis is confined to the interactive `check-config --db` and
does not run before every reconciliation.
**Gate a large run before it happens.** `--max-table-rows` and
`--max-table-bytes` make `run`, `run-check` and `run-drill` estimate each
reconciliation's scan first — a dry run or `EXPLAIN`, not a scan — and warn when
an estimate exceeds the threshold. Both default to `0` (off) so automated runs
incur no extra queries. BigQuery and Snowflake report bytes; ClickHouse and
PostgreSQL report planner rows; DuckDB, Athena and Databricks advertise no
estimate support, so a gated run there simply emits no warnings.
**Keep a local run local.** With a stored credential present, a locally executed
run reports its results to Coalesce Quality so they appear in the workspace
alongside backend runs — even when every database in the suite is local. It says
so at `INFO`, naming the endpoint. Pass `--no-report` (or set `RECON_NO_REPORT`)
to resolve no credential and open no connection at all.
***
## 7. Investigating a finished run
`recheck` and `drill-deeper` take a finished run instead of a suite — either a
local audit-log file or, for a run stored in the workspace, its invocation id.
```bash theme={null}
# Did the difference go away? (e.g. after a backfill)
synq-recon recheck audit.json --connections .connections.yaml
# Narrow every still-open segment to 100-row ranges
synq-recon drill-deeper audit.json --connections .connections.yaml --threshold 100
# Break each divergent aggregate group down by another column
synq-recon drill-deeper audit.json --add-group-column region
```
Four things govern how they behave:
* **Queries are replayed, not re-derived.** The audit log holds each query after
variable interpolation and cutoff resolution, so a re-check compares the same
window the original run did — which is what makes "did the gap move?" a
meaningful question. It also means a replay will not pick up an edited query
or variable until you pass `--reresolve`. `--reresolve` is required for an
`as_of` snapshot, which can otherwise never turn green.
* **Only what was left open resumes.** `drill-deeper` picks up the segments the
previous run stopped at on its row threshold or depth limit; `--depth` counts
from the depth they already reached, so it means "this many more levels".
Segments that could not be split further, and aggregate groups present on only
one side, are reported and skipped rather than silently dropped. An aggregate
drill already visits every configured group column, so resuming one needs at
least one `--add-group-column`.
* **`recheck` re-runs only the reconciliations that did not pass.** `--all`
re-runs every one.
* **Credentials never come from an audit log** — it records connection *names*
only. Pass `--connections`, exactly as for a normal run.
Add `--remote` to either command to hand the replay to the backend instead,
running it against workspace integrations. `--remote` needs a stored run's
invocation id (a local file has nothing server-side to reference) and accepts
`--include` but not `--exclude`.
***
## 8. Command reference
`synq-recon --help` is authoritative. This is the map.
### Local
| Command | What it does |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| `check-config ` | Validate a suite. `--db` also connects, validates every query, and analyses tables. |
| `run-check ` | Stage 1: counts and checksums. |
| `run-drill ` | Stage 2: bisect to locate differences. `--depth`, `--threshold`. |
| `run ` | Stage 1, then stage 2 on whatever mismatched with `--auto-drill`. |
| `recheck ` | Re-execute a finished run's queries and report what changed. `--all`, `--drill`, `--reresolve`. |
| `drill-deeper ` | Continue a finished run's drill. `--threshold`, `--depth`, `--add-group-column`. |
| `dump-suite ` | Print the parsed suite as protojson. Debugging aid. |
### Workspace
| Command | What it does |
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auth login` / `logout` / `status` / `token` / `whoami` | Browser login and credential inspection. `--region` picks the deployment; `--auth-profile` picks which credential profile to read or write; `--isolated` stores a credential for `synq-recon` alone rather than sharing it with the other Coalesce Quality CLIs. |
| `upload-config ` | Save a suite to the workspace (Development). `--change-summary`. |
| `suite list` / `get` / `yaml` / `versions` / `delete` / `bootstrap` | Manage stored suites. `yaml` renders one back to editable YAML; `bootstrap` prints a skeleton. `list` takes `--connection`, `--include-adhoc`, `--limit`. |
| `connections remote list` / `bootstrap` | Inspect workspace integrations; generate a matching `.connections.yaml`. |
| `run-remote ` | Ad-hoc backend run. `--drill`, `--map`, `--execution-timeout`, `--invocation-id`, `--wait`, `--fail-on`, `--wait-timeout`, `--poll-interval`. |
| `promote ` | Publish to Production. `--schedule` (cron) or `--ical` (RFC 5545) with `--timezone` and optional `--dtstart`, plus `--triggerable-by-api`, `--drill`, `--execution-timeout`, `--map`, `--annotation`, `--clear-schedule`, `--deployment-id`, `--change-summary`. |
| `trigger ` | Run a promoted deployment on demand. `--drill`, `--execution-timeout`, `--wait`, `--fail-on`, `--deployment-id`. |
| `unpromote ` | Deactivate a deployment; history is kept. `--reason`. |
| `deployment list` / `get` / `history` / `update` / `pause` / `resume` / `set-annotations` | Inspect and edit deployments in place. `update` takes the same schedule and run-setting flags as `promote`, plus `--clear`; `pause` takes `--until`. |
| `runs list` / `cancel` | Inspect and cancel run state. `list` filters on `--status`, `--trigger`, `--suite`, `--deployment`, `--actor`, `--limit`. |
| `audit-logs list` / `get ` | Inspect stored run results. `list` filters on `--status`, `--suite`, `--limit`. |
**Deployment edits preserve what you omit.** `promote` on a re-promote, and
`deployment update` always, change only the settings you actually pass — so
refreshing a suite snapshot never silently unschedules the deployment or
disables API triggers. Removing a schedule is therefore explicit:
`deployment update --clear` or `promote --clear-schedule`. A *fresh* promote
applies defaults instead: no schedule, not triggerable, drill on.
**A deployment's id is part of every reconciliation's asset path**, so it is
worth keeping stable — rebuilding a deployment from scratch under a new id
re-homes its checks and drops their history. Re-promoting the same suite reuses
its id automatically; `promote --deployment-id ` pins one explicitly when
you are rebuilding.
### Flags accepted by every command
| Flag | Notes |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `-o, --output` | `table`, `json`, `yaml`, `toon`, `tsv`, `wide`. See [Reading the output](#5-reading-the-output). |
| `--jq`, `--columns`, `--no-headers`, `--wide` | Shape structured output. Not honoured by `run`/`run-check`/`run-drill`. |
| `-v, --verbose` | Verbose logging, to stderr. |
| `--include`, `--exclude` | Select reconciliations by name; repeatable. Default is all. |
| `--var key=value` | Set or override a template variable; repeatable. |
| `--connections` | Connections file. Auto-discovers `.connections.yaml` / `connections.yaml` in the working directory. |
| `--dbt-profiles` | Resolve connections from a dbt `profiles.yml` as a fallback. |
| `-e, --environment`, `--env-file` | Apply a named set of overrides at load time. **Local only** — the workspace does not apply them. |
| `--timeout` | Per-query timeout for locally executed commands, default `5m`. Not the server-side run budget — that is `--execution-timeout`. |
| `--concurrency` | Reconciliations to run in parallel, default `1`. |
| `--max-table-rows`, `--max-table-bytes` | Pre-run scan estimate gate; `0` = off. |
| `--audit-log` | Write the run's audit log JSON to a file, or to a directory for an auto-named one. |
| `--no-report` | Keep the run local (or `RECON_NO_REPORT`). |
| `--actor-email` | Attribute write operations to this address (or `RECON_ACTOR_EMAIL`). |
| `--client-id`, `--client-secret` | Client credentials, overriding environment and YAML. |
| `--region`, `--endpoint` | Which deployment to talk to; see § 3. `--region` tab-completes. |
| `-y, --yes`, `--force` | Skip confirmation prompts; `--force` also bypasses safety checks. |
***
## 9. Worked example
Runnable end to end against the DuckDB fixtures shipped in this repository — no
warehouse, no credentials, no network. The suite deliberately contains a
difference: one missing order and one with a wrong amount.
```bash theme={null}
cd synq-recon
go build -o synq-recon ./cmd/synq-recon # needs CGO for DuckDB
```
**1. Validate.**
```bash theme={null}
./synq-recon check-config examples/ecommerce.yaml
# Configuration check passed!
```
**2. Compare.**
```bash theme={null}
./synq-recon run-check examples/ecommerce.yaml --include ecommerce-orders --no-report
```
```
Reconciliation: E-Commerce Orders (Payment Gateway vs Warehouse) (ecommerce-orders)
Mode: row_checksum
Source Target
Row Count 10 9
Status: MISMATCH
- Source has 1 more rows than target
Hint: Run 'synq-recon run-drill --include ecommerce-orders' to locate differences.
```
Exit code 1 — differences found, as intended.
**3. Locate them, keeping the audit log.**
```bash theme={null}
./synq-recon run examples/ecommerce.yaml --include ecommerce-orders \
--auto-drill --no-report --audit-log /tmp/orders.json
```
```
Depth 0: Segment [*, *)
Source: 10 rows, checksum: -139824023944409
Target: 9 rows, checksum: -144133400916972
Status: MISMATCH -> drilling down (2/10 rows in mismatched segments)
Depth 1: Segment [1,005, 1,006)
Source: 1 rows, checksum: 53805022444628
Target: 0 rows, checksum: 0
Status: MISMATCH (leaf: threshold_reached)
Depth 1: Segment [1,010, 1,011)
Source: 1 rows, checksum: 20466544489071
Target: 1 rows, checksum: 69962189961136
Status: MISMATCH (leaf: threshold_reached)
```
Order 1005 is missing from the target; order 1010 exists on both sides but its
checksum differs, so a column value changed. Two rows out of ten needed looking
at — that is the whole point of the bisection.
**4. Get the SQL that shows the actual rows.**
```bash theme={null}
./synq-recon run-drill examples/ecommerce.yaml --include ecommerce-orders \
--no-report -o json 2>/dev/null \
| jq -r '.investigation_queries[] | .source_query, .target_query, "--"'
```
Run those against the two connections to see the differing rows themselves.
**5. Re-check after a fix.** The example's connection is defined in the suite,
so replaying it needs a connections file naming it:
```bash theme={null}
printf 'connections:\n test-db:\n duckdb:\n database: ":memory:"\n' > /tmp/conn.yaml
./synq-recon recheck /tmp/orders.json --connections /tmp/conn.yaml --no-report
```
```
RECONCILIATION BEFORE AFTER CHANGE
---------------- ----------- ----------- ------------------------------------------
ecommerce-orders mismatched mismatched still mismatched (row gap unchanged at -1)
```
Nothing changed because nothing was fixed — but that line is the shape of the
answer you are looking for after a real remediation.
**6. Try the aggregate mode** on the same suite, which localises a difference
by group rather than by key range:
```bash theme={null}
./synq-recon run examples/ecommerce.yaml --include inventory-reconciliation \
--auto-drill --no-report
```
More scenarios live in `examples/`, one per business case.
`./examples/test-all-examples.sh` runs every one.
***
## 10. When something goes wrong
| What you see | What it means |
| ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Validation failed: no connections defined` from offline `check-config` | The suite's `connection:` fields are workspace integration ids, not local definitions. Pass `--connections ` to validate the wiring, add `--db` to connect. |
| Every query fails `check-config --db` with "table does not exist" | `--db` does not run the suite's `setup:` SQL. Expected for a suite whose tables are created by setup. |
| `no connections available to replay run …` | `recheck` / `drill-deeper` need `--connections`: an audit log records connection names, never credentials. |
| `accepts 1 arg(s), received 2` | A reconciliation name was passed positionally. Use `--include `. |
| A drill produces thousands of leaves and takes minutes | The data is not mostly-identical. Localise with an aggregate comparison first — see [Never do these](#2-never-do-these). |
| A warning that the stored credential is missing a scope | The command still works if the scope it needs is present. A credential without the reporting scope only means a local run's results are not reported; the comparison is unaffected. |
| `deployment is not active; re-promote to modify` | The deployment was unpromoted. Re-promote before changing or tearing it down. |
| `N connection(s) could not be bound to an integration` | A suite connection has no matching workspace integration, or the integration is not permitted for reconciliation. Check names with `connections remote list`, or bind explicitly with `--map name=integration_id`. |
| `-o json` output will not parse | Either logs were merged into stdout (`2>&1`), or it was `run --auto-drill`, which emits more than one document. See [Reading the output](#5-reading-the-output). |
| A promoted suite still runs the old comparison | A deployment is a snapshot. Re-promote after editing the suite. |
| `type: duckdb` fails inside the Docker image | That image was built without CGO. Current images support DuckDB — pull `:latest`, or use a locally built binary. |
# Authoring suites
Source: https://docs.synq.io/reconciliation/authoring-suites
The YAML anatomy of a suite, choosing key columns, and validating before you spend a query
A **suite** is a YAML file. It declares the connections available and the reconciliations to run, and it is the same file whether it runs on your laptop or on a schedule in production.
**YAML is the primary surface.** The app's wizard is a fast path to a common shape, and the app can also take a suite as pasted YAML — but everything the product can do is expressible in the file, and some things are only expressible there. [What needs YAML](#what-the-wizard-covers-and-what-needs-yaml) is the honest map.
## Anatomy of a suite
```yaml suite.yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-recon/v1/config.schema.json
name: orders-consistency # short machine identifier
title: "Orders consistency" # what people see
description: "Payment gateway vs warehouse"
connections: {} # named databases (or, in a workspace, integration names)
reconciliations: {} # the comparisons themselves
variables: {} # values interpolated into queries, resolved once per run
annotations: {} # labels that follow the suite into the platform
setup: {} # SQL to run before, and after, the comparisons
teardown: {}
strict_time_references: false # turn NOW()/CURRENT_DATE warnings into errors
```
Keep that `yaml-language-server` line at the top of every suite. It points your editor at the published JSON Schema, which gives you field completion, type checking and inline docs as you type — and it is the same schema our loader validates against.
The exhaustive field list — every field, type, default and constraint — is generated from the code and published:
Every field, rendered and browsable.
The machine-readable schema, for editors and validators.
This page explains the shape and the decisions. It deliberately does not restate the field list.
## The smallest useful suite
A connection pair and one reconciliation:
```yaml suite.yaml theme={null}
name: orders-consistency
title: "Orders consistency"
connections:
gateway:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
warehouse:
snowflake:
account: myorg.us-east-1
warehouse: COMPUTE_WH
role: ANALYST
username: ${SF_USER}
password: ${SF_PASSWORD}
databases: [ANALYTICS]
reconciliations:
orders-daily:
title: "Daily orders"
source:
connection: gateway
table: public.orders
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
mode: row_checksum
```
Thirteen databases are supported, each with its own connection block: PostgreSQL, MySQL, MSSQL, Oracle, Snowflake, BigQuery, Redshift, Databricks, ClickHouse, Trino, Athena, Microsoft Fabric and DuckDB (local files and MotherDuck). Source and target need not be the same platform — that is the point.
## Choosing the dataset
Each side of a reconciliation is a **dataset**: a connection plus what to read.
```yaml theme={null}
source:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
columns: [order_id, customer_id, order_date, total_amount]
where: "region = 'EU'"
```
With `table:` the tool resolves the column list for you, which means it can compare columns you did not have to enumerate, warn when the two sides disagree on shape, and narrow the comparison without you writing SQL:
| Field | What it does |
| ----------------- | -------------------------------------------------------------------------------------------------- |
| `columns` | Compare only these columns. |
| `exclude_columns` | Compare everything except these. Resolved at run time, so a new column is picked up automatically. |
| `where` | Filter, applied as `WHERE (condition)`. Supports `{{ variable }}` interpolation. |
`columns` and `exclude_columns` are mutually exclusive. The table reference accepts a dotted string (`db.schema.table`) or a structured object with `database`, `schema` and `name`.
```yaml theme={null}
source:
connection: gateway
query: |
SELECT order_id, customer_id, order_date, total_amount
FROM public.orders
WHERE created_at >= '{{ start_date }}'
```
Reach for `query:` when the comparison genuinely needs SQL — a join, a union, a computed column, a platform-specific function. You give up the automatic column resolution, and `columns`, `exclude_columns` and `where` are not accepted alongside it (put the predicate in the query).
Never put `NOW()`, `CURRENT_DATE` or `GETDATE()` in a query. The two sides evaluate them at slightly different instants, which manufactures differences that are not there. Use a [template variable](/reconciliation/time-windows-and-cutoffs#template-variables) instead — `check-config` warns about this, and `strict_time_references: true` makes it an error.
## Key columns decide everything
`key_columns:` (or `key_column:` — both accept a string or a list) names the column tuple that identifies a row. It is the single most consequential choice in a suite, because the drill-down orders and range-filters on it.
Two rules:
1. **It must be unique.** A non-unique key makes segment boundaries ambiguous and the drill-down unreliable.
2. **It should be indexed.** Each drill-down level range-filters on the key. With a matching primary key or index, the database prunes; without one, every segment is a full scan. `check-config --db` tells you which you have.
**Declare a composite key; never synthesise one.** For a multi-column natural key, write the columns out:
```yaml theme={null}
key_columns: [workspace, path] # ✓ orders and filters on the column tuple
```
not
```yaml theme={null}
key_column: "workspace || '|' || path" # ✗ forces a full scan per segment
```
The composite form expands to a lexicographic, dialect-portable range filter over the real columns, so an index on `(workspace, path)` still prunes. A concatenated expression cannot use that index, and a drill that would have taken seconds takes minutes.
A single key column is written back as the scalar `key_column`; several as a `key_columns` list. That is only a formatting detail of `synq-recon suite yaml` output — write whichever you prefer.
## Matching columns across the two sides
Column names that differ only in case match automatically, so `user_id` on Postgres lines up with `USER_ID` on Snowflake with no configuration. For genuinely different names, map them:
```yaml theme={null}
column_mapping:
invoice_amount: total_payment
order_id: transaction_number
```
An explicit mapping overrides the automatic case matching. Set `case_insensitive: false` to turn the automatic behaviour off entirely.
## Keep credentials out of the suite
Move the whole `connections:` block into a separate file, git-ignored, keyed by the same connection names:
```yaml .connections.yaml theme={null}
connections:
gateway:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
```
The CLI auto-discovers `.connections.yaml` or `connections.yaml` in the working directory; `--connections ` points at one explicitly. Commit a `.connections.yaml.example` with `${ENV_VAR}` placeholders so the next person knows which names to fill in.
This is not only hygiene. A suite with no credentials in it is a suite you can safely `upload-config` to your workspace, and the *same file* then runs on our backend, where the connection names bind to workspace integrations instead. Generate a matching skeleton from the integrations you already have:
```bash theme={null}
synq-recon connections remote bootstrap --recon-deployable > .connections.yaml
```
Values come out as `${ENV}` placeholders — no secrets are fetched or written.
Anywhere in a suite, `${VAR}` reads an environment variable and `${VAR:-default}` supplies a fallback.
## Setup and teardown
SQL to run before and after the comparisons, per connection. Useful for staging a snapshot, materialising a view, or building fixtures in a test suite:
```yaml theme={null}
setup:
gateway:
- CREATE TEMP TABLE staging AS SELECT * FROM raw_data
teardown:
gateway:
- DROP TABLE IF EXISTS staging
teardown_on_failure: true # run teardown even when a comparison fails
ignore_setup_errors: false # log setup errors as warnings and keep going
```
`setup_file` and `teardown_file` take a path per connection instead of inline statements. Both blocks also exist per reconciliation, where `teardown_on_failure` and `ignore_setup_errors` inherit the suite's value unless you set them.
`ignore_setup_errors: true` is right for idempotent bootstrap SQL (`CREATE TABLE IF NOT EXISTS`) and wrong when the setup is what produces the data being compared — you would be comparing two empty tables and calling it a match.
## Annotations
Name/value labels on a suite or a single reconciliation. Reconciliation-level annotations merge with the suite's, and they follow a promoted suite into the platform, where they annotate the resulting assets and checks.
```yaml theme={null}
annotations:
team: data-platform
domain: [revenue, billing]
critical:
```
The map shorthand above, and the canonical list form, are equivalent — the loader normalises to a sorted list, so version-history diffs never show order-only churn. Names and values cap at 50 characters, with at most 20 values per name.
## Validate before you spend a query
Three steps, cheapest first. Do not skip ahead; each one catches a class of problem the next would surface as a confusing mid-run error.
```bash theme={null}
synq-recon check-config suite.yaml
```
Parses the YAML, checks required fields, and warns about time-dependent SQL. Never connects to a database. Move on when it prints `Configuration check passed!`.
```bash theme={null}
synq-recon check-config suite.yaml --connections .connections.yaml
```
Confirms every connection a reconciliation refers to actually resolves. If your suite's `connection:` values are workspace integration ids rather than local definitions, offline validation reports `no connections defined` — this is the step that tells you why.
```bash theme={null}
synq-recon check-config suite.yaml --db
```
Connects to every connection and runs each query through the database's planner with `LIMIT 0` — no scan, no rows. It reports the resolved columns, table size, primary and partition keys, a suggested key column, and **a warning when the key column you chose is not indexed**.
Move on when every connection is `OK` and every query validates. A failure here is a wrong table name, a missing grant, or a column that does not exist.
`--db` does not run the suite's `setup:` SQL, so a suite whose tables are created by setup will report every query as failed. That is expected — go straight to a run.
On BigQuery, the table analysis in `--db` enumerates dataset metadata rather than jumping to the tables you named, so its cost scales with the size of the warehouse rather than the size of your suite. That is why the analysis is confined to this interactive command and does not run before every comparison.
## What the wizard covers and what needs YAML
In the app, **Health → Reconciliations → Development** has a new-suite wizard with four steps — **Data Sources**, **Comparison**, **Suite Info**, **Review** — and an **Upload Suite Config** dialog that takes a suite as pasted or uploaded YAML.
The wizard is quicker for a first suite and better at discovery: it searches your catalog, so you can pick a table you already have rather than typing warehouse coordinates, and it shows which columns are keys or indexed while you choose. It covers a deliberate subset of the format:
| Setting | Wizard | YAML |
| ------------------------------------------------------------------------------------ | ------ | -------------------- |
| Source and target, by catalog entity or typed table | ✓ | ✓ (coordinates only) |
| Raw SQL query as a dataset | ✓ | ✓ |
| `where` on a table dataset | ✓ | ✓ |
| Key columns, including composite | ✓ | ✓ |
| Mode — `row_count`, `row_checksum`, `aggregate` | ✓ | ✓ |
| Compared columns and `column_mapping` | ✓ | ✓ |
| Bisection: `enabled`, `factor`, `threshold`, `strategy`, time column and granularity | ✓ | ✓ |
| Aggregate `measures` and `group_columns` | ✓ | ✓ |
| `cutoff` — column, per-side columns, `truncate`, `combine`, `offset` | ✓ | ✓ |
| Annotations, on the suite and per reconciliation | ✓ | ✓ |
| Aggregate `thresholds` — absolute, percentage, per-column, per-measure | — | ✓ |
| `variables` (the app displays them read-only) | — | ✓ |
| `window` — sliding or fixed lookback | — | ✓ |
| `as_of` time travel | — | ✓ |
| `exclude_columns` | — | ✓ |
| `reporting` — privacy level, sample limit | — | ✓ |
| `setup` / `teardown` / `*_file` | — | ✓ |
| `hash_algorithm`, `case_insensitive`, `error_handling` | — | ✓ |
| Cutoff `apply`, per-side watermark `query`, `aggregate: MIN` | — | ✓ |
| Connection `parallelism` / `disabled` | — | ✓ |
| `strict_time_references` | — | ✓ |
| Several reconciliations authored in one pass | — | ✓ |
Nothing in the right-hand column is out of reach in the app: paste the YAML into **Upload Suite Config**. The practical workflow for anything past the basics — and the only workflow for an agent — is to author the file, validate it with `check-config`, and [save it to the workspace](/reconciliation/workspace-suites) with `upload-config`.
Two capabilities exist only in the app, and are worth knowing about:
* **Authoring from the catalog.** The entity picker resolves a table you have already catalogued to its warehouse coordinates. From the CLI you supply coordinates yourself.
* **Execution-plan preview.** The app renders the resolved plan for a stored suite before you run it.
## A complete example
Two reconciliations over the same pair of systems, in two different modes — row-level checksums for orders, and grouped totals for inventory, where row-level comparison would be the wrong instrument:
```yaml ecommerce.yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-recon/v1/config.schema.json
name: ecommerce
title: E-commerce order and inventory reconciliation
connections:
gateway:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
warehouse:
snowflake:
account: myorg.us-east-1
warehouse: COMPUTE_WH
role: ANALYST
username: ${SF_USER}
password: ${SF_PASSWORD}
databases: [ANALYTICS]
annotations:
team: data-platform
domain: [revenue]
reconciliations:
ecommerce-orders:
title: Orders (payment gateway vs warehouse)
description: Row-level checksum — catches missing orders and changed amounts.
source:
connection: gateway
table: public.orders
columns: [order_id, customer_id, order_date, total_amount, payment_status]
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
columns: [order_id, customer_id, order_date, total_amount, payment_status]
key_columns: [order_id]
mode: row_checksum
inventory-by-sku:
title: Inventory counts (warehouse vs ERP)
description: Aggregate totals per SKU — no row-level access needed.
source:
connection: warehouse
table: ANALYTICS.PUBLIC.INVENTORY
target:
connection: gateway
table: public.erp_inventory
key_columns: [sku]
mode: aggregate
aggregate:
measures:
- column: quantity
function: [SUM, COUNT]
group_columns: [sku, location]
thresholds:
absolute: 0
```
## Next
Which mode to use, aggregate measures, and threshold resolution.
Comparing two live systems without inventing differences.
Filters, concurrency, JSON output, audit logs and exit codes.
Save it, run it on our backend, promote it to production.
# CI/CD and automation
Source: https://docs.synq.io/reconciliation/cicd-and-automation
Using a reconciliation as a release gate, and the credentials an unattended caller needs
A reconciliation is a fact about your data, which makes it a good thing to block a release on. This page covers wiring one into a pipeline, and the credential constraints that apply when nobody is at the keyboard.
## The shape of a gate
```bash theme={null}
synq-recon trigger --wait --fail-on mismatched,failed
```
`--wait` blocks until the run completes and exits with a code your pipeline can act on:
| Exit | Meaning |
| ---- | -------------------------------------------------------------- |
| `0` | The run finished and no `--fail-on` condition was met. |
| `1` | A `--fail-on` condition was met — the data disagreed. |
| `2` | The run itself failed: a connection, a timeout, a query error. |
These codes are **data-driven and distinct**, which is what makes them usable in a pipeline. Locally executed commands collapse both into `1` — see [exit codes](/reconciliation/running-locally#exit-codes). If you need "the data is wrong" to be a different outcome from "the check could not run", use a backend run.
Two more flags shape the wait:
```bash theme={null}
--wait-timeout 45m # give up waiting (default 30m); the run keeps going
--poll-interval 10s # how often to check (default 5s)
```
### Choosing what fails the build
`--fail-on` takes any combination of the four result statuses. Default: `mismatched,failed`.
| Recipe | `--fail-on` | Use for |
| --------------- | ------------------------------------ | ------------------------------------------------------------------------------------------- |
| Standard gate | `mismatched,failed` | Block on a real difference. Tolerated aggregate drift passes. |
| Strict gate | `mismatched,within_threshold,failed` | Block on any difference at all, even inside thresholds. |
| Data-only gate | `mismatched` | The data must agree, but an infrastructure blip should not fail the build. |
| Inverted canary | `passed` | The two sides are *supposed* to differ. Failing to differ means something is misconfigured. |
The inverted canary is more useful than it sounds. A reconciliation that compares a table against a deliberately-modified copy should always report a mismatch; if it ever passes, your reconciliation is not actually comparing what you think it is. It is a test for the test.
## Where a gate belongs
Migrating a warehouse, or switching a consumer from one table to another. Promote a suite comparing old against new, and make the cutover step depend on it passing. This is the highest-value use: the alternative is a spot check and a hope.
Run the reconciliation as the last step of the backfill job. A backfill that reports a mismatch has not finished, whatever the row count says.
Often the better pattern for a nightly pipeline: let the [schedule](/reconciliation/workspace-suites#schedules) own the run and have your job read the outcome. No coordination, no duplicate runs, and the run appears in the app whether or not the pipeline looked.
For the third pattern, read the result rather than triggering it:
```bash theme={null}
# The most recent run's outcome for one suite
outcome=$(synq-recon audit-logs list --suite --limit 1 \
--columns STATUS --no-headers 2>/dev/null)
case "$outcome" in
*PASSED*) echo "reconciliation passed" ;;
*WITHIN_THRESHOLD*) echo "within tolerance" ;;
*) echo "reconciliation did not pass: $outcome"; exit 1 ;;
esac
```
The outcome is one of `AUDIT_OUTCOME_PASSED`, `AUDIT_OUTCOME_MISMATCHED_WITHIN_THRESHOLD`, `AUDIT_OUTCOME_MISMATCHED` or `AUDIT_OUTCOME_FAILED`. The same names, minus the prefix, are what `--status` and `--fail-on` accept.
## Scopes and credentials
Each operation needs a scope, and each scope is carried by a role:
| Operation | Scope | Role (as labelled in the app) |
| ------------------------------------------------------------- | --------------------- | ----------------------------- |
| View suites, deployments, runs, audit logs | `SCOPE_RECON_READ` | **Business User** and up |
| Save a suite, edit it, run it ad hoc, cancel a run | `SCOPE_RECON_EDIT` | **Developer** and up |
| Promote, unpromote, trigger, pause, resume, edit a deployment | `SCOPE_RECON_PROMOTE` | **Developer** and up |
| Report a locally executed run's results | `SCOPE_RECON_EDIT` | **Developer** and up |
All three scopes are selectable when you create an API client or token, so every command works from an unattended pipeline with client credentials or `QUALITY_TOKEN` — nothing here requires a developer's browser login.
Credentials resolve in a fixed order, so an automated pipeline never silently picks up a developer's browser login:
`--client-id` / `--client-secret`, or `QUALITY_CLIENT_ID` / `QUALITY_CLIENT_SECRET`, or the `synq:` block in the suite.
`QUALITY_TOKEN`. No YAML equivalent, by design — it is a CI credential, not suite configuration.
From `synq-recon auth login`, refreshed automatically.
### Choosing the deployment
`--region` names a deployment; `--endpoint` (or `QUALITY_API_ENDPOINT`) points at a specific host, for a staging or self-hosted one. Both are root flags, so they work on every command.
You rarely need either in CI. `synq-recon auth login --region ` records the deployment and later commands resolve to it; `synq-recon auth use ` switches between deployments you are already logged in to, and `auth use --clear` returns to the default.
Whichever you set also selects **which region's stored credential is used** — a token minted for one region is never sent to another. The full resolution order:
```
--endpoint > --region > the suite's synq.endpoint > QUALITY_API_ENDPOINT
> QUALITY_REGION > the last login > the default region
```
The `--synq-`-prefixed flags and `SYNQ_`-prefixed variables are the previous spellings. They still work, so nothing in an existing pipeline has to change, but the names above are the ones every Coalesce Quality CLI now shares.
Give a pipeline the narrowest set that covers what it does. A CI gate that only reads results needs `SCOPE_RECON_READ` alone; one that uploads a suite and triggers it needs `SCOPE_RECON_EDIT` and `SCOPE_RECON_PROMOTE` as well.
## Running in a container
The published image is the artifact available without monorepo access:
```bash theme={null}
docker run --rm \
-v "$PWD:/work" -w /work \
-e QUALITY_CLIENT_ID -e QUALITY_CLIENT_SECRET \
-e PG_USER -e PG_PASSWORD \
europe-docker.pkg.dev/synq-cicd-public/synq-public/synq-recon:latest \
run-check suite.yaml -o json
```
Notes for a pipeline:
* **Pass secrets as environment variables**, and reference them in the suite as `${VAR}`. Never bake a credentials file into an image.
* **Pin the tag.** `:latest` moves; a pipeline should name a version.
* **`type: duckdb` works in the image**, so a pipeline can validate against DuckDB fixtures with no warehouse. If it fails with a driver error, the image predates DuckDB support — pull a newer tag.
* **`AGENTS.md` ships inside the image** at `/opt/synq-recon/AGENTS.md`, so an agent working in a container has the operating guide without fetching anything.
## Validating a suite in CI
Cheapest useful check, and the one to add first — it costs nothing and catches a renamed column before a scheduled run does:
```bash theme={null}
synq-recon check-config suite.yaml # syntax and semantics, no network
synq-recon check-config suite.yaml --db # ...and every query, against the databases
```
Set `strict_time_references: true` in suites you validate in CI. It turns the `NOW()` / `CURRENT_DATE` warning into an error, so the class of bug that produces phantom mismatches [cannot reach production](/reconciliation/time-windows-and-cutoffs#template-variables).
## Triggering without the CLI
`trigger` is a thin wrapper over the public API, so any HTTP or gRPC client can do the same thing. The deployment must be active, **triggerable by API**, and not paused.
The relevant service is `synq.agent.recon.v1.SuiteDeploymentService` — `TriggerDeployment` to start a run, `GetSuiteDeployment` to inspect one — with `AuditLogService` and `RunStateService` for the results. See the [gRPC API reference](/api-reference/api) and [scopes](/api-reference/scopes).
Make submissions idempotent by supplying your own invocation id, so a retried pipeline step does not start a second run:
```bash theme={null}
synq-recon run-remote --invocation-id "$CI_PIPELINE_ID" --wait
```
## Next
Schedules, deployments, and what an edit preserves.
The same operations, as an operating procedure for a coding agent.
# Reconciliation CLI reference
Source: https://docs.synq.io/reconciliation/cli
Every synq-recon command, argument and flag, generated from the CLI itself.
This page is generated from the `synq-recon` command tree, so it always matches
the released binary. The YAML suite format is documented separately in the
[configuration reference](https://schemas.synq.io/synq-recon/v1/config.html).
synq-recon is a database reconciliation tool that uses hierarchical
checksum bisection to efficiently detect data differences between
source and target databases.
It supports multiple database types including PostgreSQL, MySQL,
Snowflake, BigQuery, and DuckDB.
Example usage:
```bash theme={null}
# Check configuration (offline)
synq-recon check-config config.yaml
# Check configuration with live database validation
synq-recon check-config config.yaml --db
# Quick check for differences (Stage 1)
synq-recon run-check config.yaml
synq-recon run-check config.yaml --include orders-daily
# Drill down to locate differences (Stage 2)
synq-recon run-drill config.yaml --include orders-daily
# Combined check and optional drill
synq-recon run config.yaml --auto-drill
# Filter reconciliations with --include/--exclude
synq-recon run config.yaml --include orders-daily --include users-sync
synq-recon run config.yaml --exclude slow-check
```
## Global flags
These apply to every command.
`--output` defaults to `table` for a human terminal and to `toon` when an
AI-agent environment marker is present. Anything parsing the output should
pass `--output json` explicitly rather than relying on the default.
| Flag | Type | Default | Description |
| --------------------- | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--actor-email` | `string` | — | Email to attribute write operations to (or RECON\_ACTOR\_EMAIL) |
| `--audit-log` | `string` | — | Write audit log JSON to this path (file or directory) |
| `--client-id` | `string` | — | Coalesce Quality API client ID (overrides env/YAML) |
| `--client-secret` | `string` | — | Coalesce Quality API client secret (overrides env/YAML) |
| `--columns` | `stringSlice` | — | Comma-separated list of columns to display (table/tsv mode) |
| `--concurrency` | `int` | `1` | Max reconciliations to run in parallel (1 = sequential) |
| `--connections` | `string` | — | External connections file with credentials kept out of the suite (default: auto-discover .connections.yaml) |
| `--dbt-profiles` | `string` | — | Resolve connections from a dbt profiles.yml file (fallback after YAML config) |
| `--endpoint` | `string` | — | Coalesce Quality API endpoint, for staging or a self-hosted deployment; overrides --region (or \$QUALITY\_API\_ENDPOINT) |
| `--env-file` | `string` | — | Path to environments YAML file (auto-discovered if omitted) |
| `-e`, `--environment` | `string` | — | Apply named environment overrides from environment file |
| `--exclude` | `stringArray` | — | Exclude these reconciliations (can be repeated) |
| `--force` | `bool` | — | Force destructive actions, bypassing safety checks (implies --yes) |
| `--include` | `stringArray` | — | Include only these reconciliations (can be repeated) |
| `--jq` | `string` | — | jq expression to filter JSON output |
| `--max-table-bytes` | `int64` | — | Warn before running when a reconciliation's estimated scan exceeds this size in bytes, via dry-run/EXPLAIN (0 = disabled) |
| `--max-table-rows` | `int64` | — | Warn before running when a reconciliation's estimated scan exceeds this row count, via dry-run/EXPLAIN (0 = disabled; check-config --db always reports table sizes) |
| `--no-headers` | `bool` | — | Omit the header row (table/tsv mode) |
| `--no-report` | `bool` | — | Keep the run local: do not send its audit log to Coalesce Quality (or RECON\_NO\_REPORT) |
| `-o`, `--output` | `string` | `table` | Output format: table, json, yaml, toon, tsv, wide |
| `--region` | `region` | — | Coalesce Quality deployment to use: au, eu, us (or \$QUALITY\_REGION) |
| `--timeout` | `duration` | `5m0s` | Query timeout |
| `--var` | `stringArray` | — | Set or override a template variable (can be repeated): --var start\_date=2026-01-01 |
| `-v`, `--verbose` | `bool` | — | Verbose logging |
| `--wide` | `bool` | — | Show all columns in table mode |
| `-y`, `--yes` | `bool` | — | Assume yes to confirmation prompts (for non-interactive use) |
## Commands
### `synq-recon audit-logs`
Inspect reconciliation run results (audit logs)
```bash theme={null}
synq-recon audit-logs
```
Inspect reconciliation run results stored in the workspace. Each audit log is
the recorded outcome of one reconciliation run (counts, checksums, mismatches).
#### `synq-recon audit-logs get`
Get a single audit log by invocation id
```bash theme={null}
synq-recon audit-logs get
```
Fetch a single audit log by invocation id.
Use -o json or -o yaml to see the full run result including every
reconciliation's counts, checksums, and mismatches.
#### `synq-recon audit-logs list`
List audit logs (newest first)
```bash theme={null}
synq-recon audit-logs list [flags]
```
| Flag | Type | Default | Description |
| ---------- | ------------- | ------- | ---------------------------------------------------------------------------------------- |
| `--limit` | `int` | — | Maximum number of audit logs to return (0 = all) |
| `--status` | `stringArray` | — | Filter by status: passed, mismatched, mismatched\_within\_threshold, failed (repeatable) |
| `--suite` | `string` | — | Filter by suite name |
### `synq-recon auth`
Manage Coalesce Quality API authentication
```bash theme={null}
synq-recon auth [flags]
```
Manage authentication for the Coalesce Quality API using OAuth2 authorization
code flow with PKCE. Credentials are cached under \~/.synq/oauth/, partitioned by
region, and shared with the other Coalesce Quality CLIs by default.
Pick a deployment with --region, or point at a staging or self-hosted deployment
with --endpoint. Both work on every command, not just under auth, and a
successful login is remembered — so after logging in to one deployment, later
commands need neither flag.
Examples:
```bash theme={null}
synq-recon auth login
synq-recon auth login --region us
synq-recon auth login --isolated
synq-recon auth status
synq-recon auth use au
synq-recon auth logout --region us
```
| Flag | Type | Default | Description |
| ---------------- | -------- | ------- | ----------------------------------------------------------------- |
| `--auth-profile` | `string` | — | Credential profile to read or write (default: the shared profile) |
#### `synq-recon auth login`
Authenticate with Coalesce Quality in a browser
```bash theme={null}
synq-recon auth login [flags]
```
Authenticate using the OAuth2 authorization code flow with PKCE.
Opens a browser, then caches the resulting credential under \~/.synq/oauth/. The
login asks for only the permissions synq-recon needs, not everything your
account could grant.
By default the credential goes to the shared slot, so one login serves every
Coalesce Quality CLI on this machine. Pass --isolated to give synq-recon its own
credential instead — useful when you want one tool to hold a read-only token
while another holds an ingest token.
Examples:
```bash theme={null}
synq-recon auth login
synq-recon auth login --region us
synq-recon auth login --endpoint developer.synq.dev:443
```
| Flag | Type | Default | Description |
| ------------ | ------ | ------- | ----------------------------------------------------------------- |
| `--isolated` | `bool` | — | Store a credential for synq-recon alone instead of the shared one |
#### `synq-recon auth logout`
Remove the stored credential for a region
```bash theme={null}
synq-recon auth logout
```
Delete the cached credential for one region, leaving credentials for other
regions in place. The OAuth client registration is kept, so logging back in does
not create another connected app.
#### `synq-recon auth status`
Show every stored credential, for every region
```bash theme={null}
synq-recon auth status
```
List the cached credentials across all regions, with the workspace, granted
permissions and expiry of each. Reads local files only — no network calls.
Pass --region or --endpoint to show one deployment instead of all of them.
#### `synq-recon auth token`
Print the access token, refreshing it if needed
```bash theme={null}
synq-recon auth token
```
Print the current access token to stdout, refreshing it first if it has
expired or is close to expiring.
Useful for scripting:
```bash theme={null}
curl -H "Authorization: Bearer $(synq-recon auth token)" ...
```
#### `synq-recon auth use`
Show or set the deployment commands use by default
```bash theme={null}
synq-recon auth use [region|endpoint] [flags]
```
Record which deployment a command talks to when it is given neither --region
nor --endpoint.
A successful login already records the deployment it authenticated against, so
this is only needed to switch between two deployments you are logged in to. An
explicit --region or --endpoint, QUALITY\_API\_ENDPOINT and QUALITY\_REGION all
still win over what is recorded here.
Called with no argument it prints the current setting.
Examples:
```bash theme={null}
synq-recon auth use
synq-recon auth use au
synq-recon auth use developer.synq.dev:443
synq-recon auth use --clear
```
| Flag | Type | Default | Description |
| --------- | ------ | ------- | ------------------------------------------------------------------ |
| `--clear` | `bool` | — | Forget the recorded deployment and fall back to the default region |
#### `synq-recon auth whoami`
Show who you are authenticated as and what permissions you hold
```bash theme={null}
synq-recon auth whoami
```
Call the Coalesce Quality IAM API and print the current identity, workspace
and granted permissions. Uses the same credential resolution as every other
command (client credentials, then a pre-issued token, then the browser login).
### `synq-recon check-config`
```bash theme={null}
synq-recon check-config [flags]
```
Check a configuration file for syntax and semantic correctness.
This command parses the YAML configuration, checks for required fields,
validates connection parameters, verifies reconciliation definitions,
and detects potential issues like time-dependent SQL references.
Use --db to also connect to databases and validate SQL queries.
Examples:
```bash theme={null}
synq-recon check-config config.yaml
synq-recon check-config config.yaml --db
```
| Flag | Type | Default | Description |
| ------ | ------ | ------- | --------------------------------------------- |
| `--db` | `bool` | — | Connect to databases and validate SQL queries |
### `synq-recon connections`
Work with reconciliation connections (data warehouses / databases)
```bash theme={null}
synq-recon connections
```
Work with reconciliation connections — the data warehouses / databases recon
runs against. A connection id is what a suite's source/target `connection:` refers
to. The `remote` subcommands operate on the connections defined in the cloud
workspace.
#### `synq-recon connections remote`
Inspect DWH connections defined in the cloud workspace
```bash theme={null}
synq-recon connections remote
```
##### `synq-recon connections remote bootstrap`
Print a .connections.yaml for selected cloud DWH connections
```bash theme={null}
synq-recon connections remote bootstrap [flags]
```
Print a .connections.yaml skeleton for the selected cloud DWH connections,
ready to redirect to a file. Credentials are left as \$\{ENV} placeholders —
nothing is written to disk and no secrets are fetched.
Select non-interactively with --connection (repeatable), --all, or
\--recon-deployable:
```bash theme={null}
synq-recon connections remote bootstrap --recon-deployable > .connections.yaml
```
| Flag | Type | Default | Description |
| -------------------- | ------------- | ------- | --------------------------------------------------------------- |
| `--all` | `bool` | — | Bootstrap all DWH connections |
| `--connection` | `stringArray` | — | Connection id to bootstrap (repeatable) |
| `--out` | `string` | — | Write to this file instead of stdout (use --force to overwrite) |
| `--recon-deployable` | `bool` | — | Bootstrap all recon-deployable connections |
##### `synq-recon connections remote list`
List DWH connections in the cloud workspace
```bash theme={null}
synq-recon connections remote list [flags]
```
| Flag | Type | Default | Description |
| -------------------- | ------ | ------- | -------------------------------------------------- |
| `--include-disabled` | `bool` | — | Include disabled connections |
| `--limit` | `int` | — | Maximum number of connections to return (0 = all) |
| `--recon-deployable` | `bool` | — | Only connections reconciliation can deploy against |
### `synq-recon deployment`
```bash theme={null}
synq-recon deployment
```
Inspect promoted reconciliation deployments (the operations side of recon):
the scheduled/triggerable instances of a suite running against workspace
integrations. Use the subcommands to list deployments, fetch one, and view
its append-only change history.
#### `synq-recon deployment get`
Get a single deployment by suite id (or --deployment-id)
```bash theme={null}
synq-recon deployment get [suite-id] [flags]
```
Fetch a single deployment. By default the positional argument is the
suite id; pass --deployment-id to look up by deployment id instead.
Use -o json or -o yaml to see the full deployment including schedule,
connection mappings, and case-failure impacts.
| Flag | Type | Default | Description |
| ----------------- | -------- | ------- | -------------------------------------------- |
| `--deployment-id` | `string` | — | Look up by deployment id instead of suite id |
#### `synq-recon deployment history`
Show the change history of a deployment
```bash theme={null}
synq-recon deployment history [suite-id] [flags]
```
Show the append-only change history of a deployment (promote, unpromote,
schedule/mapping/annotation changes, pause, resume). By default the positional
argument is the suite id; pass --deployment-id to look up by deployment id.
| Flag | Type | Default | Description |
| ----------------- | -------- | ------- | -------------------------------------------- |
| `--deployment-id` | `string` | — | Look up by deployment id instead of suite id |
#### `synq-recon deployment list`
List promoted deployments in the workspace
```bash theme={null}
synq-recon deployment list [flags]
```
| Flag | Type | Default | Description |
| ---------------------- | -------- | ------- | -------------------------------------------------- |
| `--active-only` | `bool` | — | Only currently-active deployments |
| `--include-paused` | `bool` | — | Include paused deployments |
| `--integration` | `string` | — | Filter to deployments bound to this integration id |
| `--limit` | `int` | — | Maximum number of deployments to return (0 = all) |
| `--triggerable-by-api` | `bool` | — | Only deployments that can be triggered via the API |
#### `synq-recon deployment pause`
Pause a deployment (suppress scheduled and API-triggered runs)
```bash theme={null}
synq-recon deployment pause [flags]
```
Pause a deployment so it stops running on its schedule and via the API.
Without --until the pause is indefinite (until 'deployment resume').
| Flag | Type | Default | Description |
| ---------- | -------- | ------- | ----------------------------------------------------- |
| `--reason` | `string` | — | Reason recorded in the deployment history |
| `--until` | `string` | — | Pause until this RFC3339 time (default: indefinitely) |
#### `synq-recon deployment resume`
Resume a paused deployment
```bash theme={null}
synq-recon deployment resume
```
#### `synq-recon deployment set-annotations`
Replace a deployment's annotations
```bash theme={null}
synq-recon deployment set-annotations [flags]
```
| Flag | Type | Default | Description |
| ------------------ | ------------- | ------- | ------------------------------------------------------------------- |
| `--annotation` | `stringArray` | — | Annotation: name=value\[,value...] (repeatable); pass none to clear |
| `--change-summary` | `string` | — | Audit log summary for this change |
#### `synq-recon deployment update`
Update a deployment's schedule, API-triggering, drill, or execution-timeout setting
```bash theme={null}
synq-recon deployment update [flags]
```
Partially update a deployment without re-promoting its config. Every flag
is independent: omit one and its current value is preserved. Pass --schedule
with a cron expression (or --ical with an RFC 5545 recurrence rule, optionally
anchored with --dtstart) to set it, --clear to remove it, --drill /
\--drill=false to toggle bisection drill-down, --triggerable-by-api / =false
to toggle on-demand API triggers, and --execution-timeout to set the per-run
wall-clock budget (e.g. 20m; the server clamps it to its supported range).
Use 'deployment set-annotations' to change a deployment's annotations.
| Flag | Type | Default | Description |
| ---------------------- | ---------- | ------- | ------------------------------------------------------------------------------------------------------------- |
| `--change-summary` | `string` | — | Audit log summary for this change |
| `--clear` | `bool` | — | Clear the schedule |
| `--drill` | `bool` | — | Enable (--drill) or disable (=false) bisection drill-down on each run; omit to preserve |
| `--dtstart` | `string` | — | Anchor time for --ical (RFC3339, e.g. 2026-01-02T15:04:05Z) |
| `--execution-timeout` | `duration` | `0s` | Maximum wall-clock budget for a single run, e.g. 20m (server clamps to its supported range); omit to preserve |
| `--ical` | `string` | — | iCal RFC 5545 recurrence rule, e.g. 'FREQ=MONTHLY;BYDAY=TH;BYSETPOS=-1' (mutually exclusive with --schedule) |
| `--schedule` | `string` | — | Cron schedule, e.g. '0 \* \* \* \*' (mutually exclusive with --ical) |
| `--timezone` | `string` | — | Timezone for the schedule |
| `--triggerable-by-api` | `bool` | — | Allow (--triggerable-by-api) or disallow (=false) on-demand API triggers; omit to preserve |
### `synq-recon drill-deeper`
Continue a previous run's drill-down from where it stopped
```bash theme={null}
synq-recon drill-deeper [flags]
```
Resume a drill from where a previous run stopped, instead of re-drilling
the whole dataset. Bisection and aggregate reconciliations both resume, each
picking up where it left off.
Bisection resumes from the mismatch segments the previous run left open — the
ones it stopped at because it hit its row threshold or its depth limit. Segments
it could not split further, or that errored, are reported and skipped: drilling
deeper cannot narrow those. Lowering --threshold is the usual reason to resume;
\--depth is counted from the depth the resumed segments already reached, so it
means "this many more levels".
Aggregate resumes from the divergent groups the previous run found. An aggregate
drill already visits every configured group column, so resuming needs at least
one more via --add-group-column: each divergent group is then broken down by the
extra columns. Groups present on only one side are reported and skipped.
Queries are replayed from the audit log for the same reason as recheck: the
recorded ranges and group keys were computed against that data, so re-deriving
the queries would drill scopes that no longer line up.
Examples:
```bash theme={null}
# Narrow every open bisection mismatch to 100-row segments
synq-recon drill-deeper audit.json --threshold 100
# Two more levels of detail on one bisection reconciliation
synq-recon drill-deeper audit.json --include orders-daily --depth 2
# Break each divergent aggregate group down by region, then by product
synq-recon drill-deeper audit.json --add-group-column region --add-group-column product
# Have the backend drill a stored run deeper against workspace integrations
synq-recon drill-deeper 3f7c1e28-5a1b-4c9e-9f10-2b7d8e6a4c53 --remote --threshold 100
```
| Flag | Type | Default | Description |
| -------------------- | ------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| `--add-group-column` | `stringArray` | — | Extra group column to break divergent aggregate groups down by (repeatable); required to resume an aggregate drill |
| `--depth` | `int` | — | Levels to drill below the resumed segments (0 = unlimited) |
| `--invocation-id` | `string` | — | Client-supplied invocation id for idempotency (with --remote; default: generated) |
| `--map` | `stringArray` | — | Map a connection the run recorded to an integration: connection=integration\_id (repeatable, with --remote) |
| `--remote` | `bool` | — | Run the replay on the Coalesce Quality backend against workspace integrations instead of locally |
| `--reresolve` | `bool` | — | Re-derive queries against current data instead of replaying the previous run's resolved SQL |
| `--threshold` | `int` | — | Row count at which to stop drilling (overrides the reconciliation's own) |
### `synq-recon dump-suite`
Parse a YAML config and dump the proto Suite as JSON
```bash theme={null}
synq-recon dump-suite
```
Parse a YAML configuration file and output the reconciliation suite
as a protojson-encoded message. This is useful for inspecting the
parsed configuration and for integration with other tools.
Examples:
```bash theme={null}
synq-recon dump-suite config.yaml
synq-recon dump-suite config.yaml | jq .
```
### `synq-recon promote`
Promote a suite config to a scheduled/triggerable deployment
```bash theme={null}
synq-recon promote [flags]
```
Promote a suite config to production: create (or update) a deployment that can
run on a schedule and/or be triggered via the API. Re-promoting the same suite
reuses its deployment id, so this is safe to repeat.
On a re-promote, omitted flags are preserved: leaving out --schedule,
\--triggerable-by-api, --drill or --execution-timeout keeps the existing
deployment's value rather than resetting it, so refreshing the suite snapshot
won't unschedule the deployment or disable API triggers. (A fresh promote
defaults to no schedule, not triggerable, bisection on, and the server-default
execution timeout.) Pass --clear-schedule to actively remove an existing
schedule on re-promote.
Wire the suite's connections to workspace integrations with --map; discover
integration ids with 'synq-recon connections remote list'.
The deployment id is part of every promoted reconciliation's asset path, so it
is worth keeping stable. Pass --deployment-id to promote under a specific id:
it is adopted when no deployment holds it yet, and is an idempotent retry when
the deployment already exists for this suite. Promoting a suite that already
has a deployment keeps that id whether or not the flag is passed.
| Flag | Type | Default | Description |
| ---------------------- | ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--annotation` | `stringArray` | — | Deployment annotation: name=value\[,value...] (repeatable) |
| `--change-summary` | `string` | — | Audit log summary describing this promotion |
| `--clear-schedule` | `bool` | — | Remove the existing schedule on re-promote (mutually exclusive with --schedule/--ical) |
| `--deployment-id` | `string` | — | Promote under a specific deployment id, adopting it if no deployment holds it yet (default: reuse the suite's deployment, or allocate a new id) |
| `--drill` | `bool` | — | Run hierarchical bisection drill-down on each run |
| `--dtstart` | `string` | — | Anchor time for --ical (RFC3339, e.g. 2026-01-02T15:04:05Z); wall-clock in --timezone |
| `--execution-timeout` | `duration` | `0s` | Maximum wall-clock budget for a single run, e.g. 20m (server clamps to its supported range; omit to preserve on re-promote / use the server default on a fresh promote) |
| `--ical` | `string` | — | iCal RFC 5545 recurrence rule, e.g. 'FREQ=MONTHLY;BYDAY=TH;BYSETPOS=-1' (mutually exclusive with --schedule) |
| `--map` | `stringArray` | — | Map a suite connection to an integration: connection=integration\_id (repeatable) |
| `--schedule` | `string` | — | Cron schedule for recurring runs, e.g. '0 \* \* \* \*' (mutually exclusive with --ical) |
| `--timezone` | `string` | — | Timezone for the schedule (e.g. UTC, Europe/Warsaw) |
| `--triggerable-by-api` | `bool` | — | Allow on-demand triggers via the API |
### `synq-recon recheck`
Re-run a previous run's queries to check whether its differences still exist
```bash theme={null}
synq-recon recheck [flags]
```
Re-execute the queries a previous run ran and report what changed.
The previous run is identified by an audit log file or, for a run stored in
Coalesce Quality, by its invocation id (fetched via the API).
Queries come from the audit log, not from a fresh config load, so the comparison
is against the same data the previous run compared: template variables keep the
values they resolved to, a cutoff keeps the watermark it derived, and a
time-travel snapshot keeps its timestamp. Use --reresolve to re-derive
everything against the current clock instead — necessary for a time-travel
snapshot, which can otherwise never turn green.
By default only the reconciliations that did not pass are re-run, since that is
what needs re-checking. Pass --all to re-run every one.
Credentials are not stored in an audit log. Connections are resolved by name
from --connections or an auto-discovered connections file, exactly as for a
normal run.
Exit code 1 means something still (or newly) mismatches; 0 means everything
re-validated clean.
Examples:
```bash theme={null}
# Re-check whatever the previous run found
synq-recon recheck audit-logs/audit-2026-07-25T10-30-00.json
# Re-check a run stored in Coalesce Quality
synq-recon recheck 3f7c1e28-5a1b-4c9e-9f10-2b7d8e6a4c53
# Re-check one reconciliation, drilling into whatever still differs
synq-recon recheck audit.json --include orders-daily --drill
# Re-run against current data rather than the previous run's window
synq-recon recheck audit.json --reresolve
# Have the backend re-check a stored run against workspace integrations
synq-recon recheck 3f7c1e28-5a1b-4c9e-9f10-2b7d8e6a4c53 --remote
```
| Flag | Type | Default | Description |
| ----------------- | ------------- | ------- | ----------------------------------------------------------------------------------------------------------- |
| `--all` | `bool` | — | Re-run every reconciliation, not only the ones that did not pass |
| `--drill` | `bool` | — | Drill into whatever still mismatches |
| `--invocation-id` | `string` | — | Client-supplied invocation id for idempotency (with --remote; default: generated) |
| `--map` | `stringArray` | — | Map a connection the run recorded to an integration: connection=integration\_id (repeatable, with --remote) |
| `--remote` | `bool` | — | Run the replay on the Coalesce Quality backend against workspace integrations instead of locally |
| `--reresolve` | `bool` | — | Re-derive queries against current data instead of replaying the previous run's resolved SQL |
### `synq-recon run`
Run check and optionally drill on mismatch
```bash theme={null}
synq-recon run [flags]
```
Run quick check and optionally perform bisection drill-down
when mismatches are detected.
This combines Stage 1 (run-check) and Stage 2 (run-drill) into a single command.
By default all reconciliations in the config are run.
Use --include/--exclude to filter which reconciliations to run.
Examples:
```bash theme={null}
# Run all reconciliations, auto-drill on mismatch
synq-recon run config.yaml --auto-drill
# Run only specific reconciliations
synq-recon run config.yaml --include orders-daily --auto-drill
# Run all except one
synq-recon run config.yaml --exclude slow-check --auto-drill
# Run without auto-drill (just check)
synq-recon run config.yaml
```
| Flag | Type | Default | Description |
| -------------- | ------ | ------- | ------------------------------------ |
| `--auto-drill` | `bool` | — | Automatically drill down on mismatch |
### `synq-recon run-check`
Quick check for differences (Stage 1)
```bash theme={null}
synq-recon run-check
```
Perform a quick check to detect differences between source and target.
This is Stage 1 of reconciliation, which compares row counts and checksums
to efficiently detect if any differences exist.
By default all reconciliations in the config are checked.
Use --include/--exclude to filter which reconciliations to run.
Examples:
```bash theme={null}
# Check all reconciliations
synq-recon run-check config.yaml
# Check only specific reconciliations
synq-recon run-check config.yaml --include orders-daily --include users-sync
# Check all except one
synq-recon run-check config.yaml --exclude slow-check
# JSON output
synq-recon run-check config.yaml --output json
```
### `synq-recon run-drill`
Bisection drill-down to locate differences (Stage 2)
```bash theme={null}
synq-recon run-drill [flags]
```
Perform bisection drill-down to locate the specific segments
where data differences exist.
This is Stage 2 of reconciliation, which recursively bisects the data
space to narrow down the location of mismatches.
Use --include/--exclude to filter which reconciliations to drill.
Examples:
```bash theme={null}
# Drill down on all reconciliations
synq-recon run-drill config.yaml
# Drill down on specific reconciliations
synq-recon run-drill config.yaml --include orders-daily
# Drill down on multiple reconciliations
synq-recon run-drill config.yaml --include orders-daily --include users-sync
# Limit the drill depth
synq-recon run-drill config.yaml --include orders-daily --depth 3
# JSON output
synq-recon run-drill config.yaml --include orders-daily --output json
```
| Flag | Type | Default | Description |
| ------------- | ----- | ------- | ------------------------------------------------------- |
| `--depth` | `int` | — | Maximum drill depth (0 for unlimited) |
| `--threshold` | `int` | — | Row count threshold to stop drilling (overrides config) |
### `synq-recon run-remote`
Run a suite on the Coalesce Quality backend (ad-hoc), not locally
```bash theme={null}
synq-recon run-remote [flags]
```
Submit an ad-hoc reconciliation run executed by the Coalesce Quality backend
against workspace integrations — as opposed to run/run-check/run-drill, which
execute locally against databases you can reach.
The run is asynchronous; poll its result with:
```bash theme={null}
synq-recon audit-logs get
```
A client-generated invocation id makes submission idempotent: re-running with
the same --invocation-id will not start a duplicate run.
| Flag | Type | Default | Description |
| --------------------- | ------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `--drill` | `bool` | — | Run hierarchical bisection drill-down to locate mismatches |
| `--execution-timeout` | `duration` | `0s` | Maximum wall-clock budget for this run, e.g. 20m (server clamps to its supported range); omit to use the server default |
| `--fail-on` | `stringArray` | `[mismatched,failed]` | Audit statuses that cause a non-zero exit: passed, within\_threshold, mismatched, failed (with --wait) |
| `--invocation-id` | `string` | — | Client-supplied invocation id for idempotency (default: generated) |
| `--map` | `stringArray` | — | Map a suite connection to an integration: connection=integration\_id (repeatable) |
| `--poll-interval` | `duration` | `5s` | How often to poll for the run result (with --wait) |
| `--wait` | `bool` | — | Block until the run completes and exit non-zero on mismatch (1) or failure (2) |
| `--wait-timeout` | `duration` | `30m0s` | Maximum time to wait for the run to complete (with --wait) |
### `synq-recon runs`
```bash theme={null}
synq-recon runs
```
Inspect reconciliation run state across the workspace: scheduled, in-progress,
and concluded runs, with their trigger, status, and timing.
#### `synq-recon runs cancel`
Cancel a scheduled or in-progress run
```bash theme={null}
synq-recon runs cancel
```
Cancel a stuck or unwanted run by marking it cancelled. An independent
execution job will skip the run when it next checks its state.
Requires confirmation; pass --yes (or --force) for non-interactive use.
#### `synq-recon runs list`
List reconciliation runs (newest first)
```bash theme={null}
synq-recon runs list [flags]
```
| Flag | Type | Default | Description |
| -------------- | ------------- | ------- | --------------------------------------------------------------------------------------------- |
| `--actor` | `stringArray` | — | Filter by actor identity, e.g. email:[user@example.com](mailto:user@example.com) (repeatable) |
| `--deployment` | `stringArray` | — | Filter by deployment id (repeatable) |
| `--limit` | `int` | — | Maximum number of runs to return (0 = all) |
| `--status` | `stringArray` | — | Filter by status: scheduled, in\_progress, succeeded, failed, cancelled (repeatable) |
| `--suite` | `stringArray` | — | Filter by suite id (repeatable) |
| `--trigger` | `stringArray` | — | Filter by trigger: adhoc, scheduled, api (repeatable) |
### `synq-recon suite`
Manage reconciliation suite configs in the Coalesce Quality workspace
```bash theme={null}
synq-recon suite
```
Inspect and manage reconciliation suite configurations stored in the
Coalesce Quality workspace (the authoring side of recon). Use the subcommands
to list suites, fetch a single suite, and view its version history.
#### `synq-recon suite bootstrap`
Print a new suite skeleton (generated id + connection references)
```bash theme={null}
synq-recon suite bootstrap [flags]
```
Print a new reconciliation suite skeleton to stdout, ready to redirect to a
file and edit. The suite gets a generated UUID name and one reconciliation
referencing source/target connections by id (discover ids with
'synq-recon connections remote list'). Nothing is written to disk.
```bash theme={null}
synq-recon suite bootstrap --source --target > my-suite.yaml
```
| Flag | Type | Default | Description |
| -------------- | -------- | --------- | ------------------------------------------------------------------------ |
| `--key-column` | `string` | `id` | Key column for the example reconciliation |
| `--name` | `string` | — | Suite name — the stable identifier (default: generated UUID) |
| `--out` | `string` | — | Write to this file instead of stdout (use --force to overwrite) |
| `--recon-key` | `string` | `example` | Reconciliation key in the generated suite |
| `--source` | `string` | — | Source connection id |
| `--target` | `string` | — | Target connection id |
| `--title` | `string` | — | Suite title — human-friendly label (default: "New Reconciliation Suite") |
#### `synq-recon suite delete`
Delete a suite config (soft delete)
```bash theme={null}
synq-recon suite delete
```
Delete a suite config from the workspace. This is a soft delete: the suite's
version history is preserved.
Requires confirmation; pass --yes (or --force) for non-interactive use.
#### `synq-recon suite get`
Get a single suite config by suite id
```bash theme={null}
synq-recon suite get
```
Fetch a single suite config by its suite id.
Use -o json or -o yaml to see the full suite definition including every
reconciliation, query, and threshold.
#### `synq-recon suite list`
List suite configs in the workspace
```bash theme={null}
synq-recon suite list [flags]
```
List reconciliation suite configs in the workspace.
By default only managed suites are returned. Pass --include-adhoc to also
include one-off ad-hoc submissions (e.g. local test runs uploaded to the API).
| Flag | Type | Default | Description |
| ----------------- | -------- | ------- | --------------------------------------------------------------- |
| `--connection` | `string` | — | Filter suites that use this connection name |
| `--include-adhoc` | `bool` | — | Include ad-hoc (one-off) suite configs, not just managed suites |
| `--limit` | `int` | — | Maximum number of suites to return (0 = all) |
#### `synq-recon suite versions`
List the version history of a suite config
```bash theme={null}
synq-recon suite versions
```
#### `synq-recon suite yaml`
Render a suite config as canonical recon YAML
```bash theme={null}
synq-recon suite yaml
```
Fetch a suite config and render it as canonical reconciliation YAML — the
same shape accepted by check-config and upload-config. Use this to pull a
remote suite down to a local file, edit it, and re-upload:
```bash theme={null}
synq-recon suite yaml my-suite > my-suite.yaml
# edit my-suite.yaml ...
synq-recon upload-config my-suite.yaml
```
### `synq-recon trigger`
Trigger an on-demand run of a promoted deployment
```bash theme={null}
synq-recon trigger [suite-id] [flags]
```
Trigger an immediate run of a promoted deployment. The deployment must be
active, triggerable by API, and not paused. By default the positional argument
is the suite id; pass --deployment-id to target by deployment id.
| Flag | Type | Default | Description |
| --------------------- | ------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `--deployment-id` | `string` | — | Target by deployment id instead of suite id |
| `--drill` | `bool` | — | Run drill-down for this run (--drill) or skip it (=false); omit to inherit the deployment default |
| `--execution-timeout` | `duration` | `0s` | Maximum wall-clock budget for this run, e.g. 20m (server clamps to its supported range); omit to inherit the deployment default |
| `--fail-on` | `stringArray` | `[mismatched,failed]` | Audit statuses that cause a non-zero exit: passed, within\_threshold, mismatched, failed (with --wait) |
| `--poll-interval` | `duration` | `5s` | How often to poll for the run result (with --wait) |
| `--wait` | `bool` | — | Block until the run completes and exit non-zero on mismatch (1) or failure (2) |
| `--wait-timeout` | `duration` | `30m0s` | Maximum time to wait for the run to complete (with --wait) |
### `synq-recon unpromote`
Deactivate a deployment (stop scheduling and API triggers)
```bash theme={null}
synq-recon unpromote [flags]
```
Unpromote a suite: deactivate its deployment so it no longer runs on a schedule
or via the API. The deployment record and its history are retained.
Requires confirmation; pass --yes (or --force) for non-interactive use.
| Flag | Type | Default | Description |
| ---------- | -------- | ------- | ----------------------------------------- |
| `--reason` | `string` | — | Reason recorded in the deployment history |
### `synq-recon upload-config`
Upload reconciliation config to Coalesce Quality
```bash theme={null}
synq-recon upload-config [flags]
```
Parse a YAML configuration file and upload the reconciliation suite
to the Coalesce Quality cloud platform using the UpsertSuiteConfig API.
Authentication (checked in order):
```bash theme={null}
1. Client credentials: --client-id/--client-secret, env vars, or YAML config
2. OAuth token: cached from 'synq-recon auth login' (auto-refreshes if expired)
```
The deployment is controlled by --region, or --endpoint for a staging or
self-hosted one (default: the deployment of the last login, else eu).
Examples:
```bash theme={null}
# Upload using client credentials
synq-recon upload-config config.yaml --client-id=... --client-secret=...
# Upload using OAuth token (after 'synq-recon auth login')
synq-recon upload-config config.yaml
# Upload with a change summary
synq-recon upload-config config.yaml --change-summary "Added new orders reconciliation"
# Upload to a different environment
synq-recon upload-config config.yaml --region us
```
| Flag | Type | Default | Description |
| ------------------ | -------- | ------- | -------------------------------------- |
| `--change-summary` | `string` | — | Human-readable summary of what changed |
# Comparison modes
Source: https://docs.synq.io/reconciliation/comparison-modes
Row counts, row checksums and aggregate measures — which one answers your question
Every reconciliation has a `mode:`, and it decides what "agree" means.
| Mode | Compares | Catches | Misses |
| ---------------------------- | ------------------------------------------------------------------------- | ------------------------------ | ------------------------------------ |
| `row_count` | Row counts | Missing and extra rows | Any change to a value |
| `row_checksum` **(default)** | Row counts and a checksum over the compared columns | Any difference at all | Nothing, within the compared columns |
| `aggregate` | Grouped measures — `SUM`, `COUNT`, `AVG`, `MIN`, `MAX` — with a tolerance | Divergence in totals per group | Offsetting errors within a group |
When in doubt, use `row_checksum`. It is the default, it costs one query per side, and it does not miss anything. Reach for the others when you have a specific reason: `row_count` when only presence matters, `aggregate` when the two sides are not row-for-row comparable in the first place.
## Row count mode
```yaml theme={null}
reconciliations:
orders-present:
source:
connection: gateway
table: public.orders
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
mode: row_count
```
The cheapest possible comparison: `COUNT(*)` per side. Use it when the target is known to transform values — so a checksum would never match — but must not lose or duplicate rows. A drill-down still works, narrowing *which* key ranges have the wrong count.
## Row checksum mode
```yaml theme={null}
reconciliations:
orders-identical:
source:
connection: gateway
table: public.orders
exclude_columns: [synced_at, etl_batch_id]
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
exclude_columns: [synced_at, etl_batch_id]
key_columns: [order_id]
mode: row_checksum
```
Each row is hashed across the compared columns, and the hashes are summed per side. One query per side returns the count and that sum, so a single changed character in a single row changes the total.
The columns you compare are the ones you decide to compare. `columns:` and `exclude_columns:` are how you keep pipeline bookkeeping — load timestamps, batch ids, surrogate keys generated per side — from being reported as a difference for the rest of time.
`full` is an accepted legacy spelling of `row_checksum`. Suites round-tripped through `synq-recon suite yaml` come back written as `row_checksum`.
## Aggregate mode
Row-level comparison is the wrong instrument when the target is a summary of the source, when row identity differs between the two systems, or when you care about the numbers rather than the rows. Aggregate mode compares measures, grouped, with a tolerance.
```yaml theme={null}
reconciliations:
daily-revenue:
title: Daily revenue by store
source:
connection: operational
table: public.sales
columns: [sale_date, store_id, amount, sale_id]
target:
connection: warehouse
table: ANALYTICS.PUBLIC.SALES
columns: [sale_date, store_id, amount, sale_id]
key_columns: [sale_date]
mode: aggregate
aggregate:
measures:
- column: amount
function: [SUM, COUNT]
group_columns: [sale_date, store_id]
thresholds:
absolute: 0.01
percentage: 0.001
```
### Measures
A measure is a column and one or more functions. `function:` takes a single value or a list, so the block above expands to two measures: `SUM(amount)` and `COUNT(amount)`. Available functions are `SUM`, `COUNT`, `AVG`, `MIN` and `MAX`.
Pair a `SUM` with a `COUNT` on the same column. `SUM` alone cannot distinguish "one row is missing" from "one value is wrong" — the total is short either way. With the count beside it, the two are immediately distinguishable, and it costs nothing extra because both are computed in the same query.
### The group hierarchy
`group_columns:` is a hierarchy, evaluated outermost-first. The comparison groups by the first column; only groups that diverge are then broken down by the second, and so on. Groups that agree are never queried again.
With `group_columns: [sale_date, store_id]`, a run over a discrepancy on one store on one day looks like this:
```
Coalesce Quality Reconciliation - Aggregate Check
================================================
Reconciliation: Daily revenue by store (daily-revenue)
Mode: aggregate
Group Columns: sale_date -> store_id
Measures: SUM(amount), COUNT(amount)
Total Groups: 10
Matched Groups: 8
Mismatch Groups: 2
Status: MISMATCH
Drill-Down Tree:
Level 0: GROUP BY sale_date (10 groups, 8 matched)
- [AGGREGATE_DIVERGENCE_TYPE_SUBGROUP_MISMATCH] sale_date=2026-01-08 00:00:00
Source _measure_sum_amount: 6840
Source _measure_count_amount: 30
Target _measure_sum_amount: 6829.5
Target _measure_count_amount: 29
Diff _measure_sum_amount: -10.5
Diff _measure_count_amount: -1
Level 1: GROUP BY store_id (3 groups, 2 matched)
- [AGGREGATE_DIVERGENCE_TYPE_MEASURE_MISMATCH] sale_date=2026-01-08 00:00:00, store_id=STORE-1
Source _measure_sum_amount: 2130
Source _measure_count_amount: 10
Target _measure_sum_amount: 2119.5
Target _measure_count_amount: 9
Diff _measure_sum_amount: -10.5
Diff _measure_count_amount: -1
```
Eight of ten days agreed on the first pass. Reading down the tree: on 8 January the target is one row and 10.5 short on the total, and it is store `STORE-1`'s numbers that are wrong. Two levels, and the finding is specific enough to act on.
Each measure appears as `_measure__` — the alias the generated SQL gives it, which is also what you will find in `-o json` and in the audit log. Each divergent node is labelled with why it is there:
| Divergence type | Meaning |
| ------------------- | ---------------------------------------------------------------------- |
| `MEASURE_MISMATCH` | This group's own measures differ. |
| `SUBGROUP_MISMATCH` | The group differs because something below it does — keep reading down. |
If you omit `group_columns`, the hierarchy falls back to `[key_column]`.
### Thresholds
Floating-point arithmetic, rounding, and currency conversion all produce differences that are not errors. A threshold is what separates them from the ones that are.
```yaml theme={null}
thresholds:
absolute: 0.01 # ignore differences up to this magnitude
percentage: 0.001 # ...or up to 0.1%
percentage_mode: source # percentage of: source (default), target, or symmetric
```
A group passes if it is within *either* limit. `absolute: 0` means exact agreement.
Overrides get more specific from there — per grouping column, and per measure:
```yaml theme={null}
thresholds:
absolute: 0.01
percentage: 0.001
# Looser at the leaf level, where individual values are small
per_column:
product:
absolute: 1.0
per_measure:
"SUM(revenue)":
absolute: 10.0
# An average is noisier than a sum, everywhere
per_measure:
"AVG(revenue)":
percentage: 0.05
```
Resolution order, most specific wins:
The threshold for this measure at this level of the hierarchy.
The threshold for this measure, at every level.
The threshold for every measure at this level.
The suite-wide default.
Measures are keyed by their rendered name, `"FUNC(column)"` — `"SUM(revenue)"`, `"COUNT(amount)"` — and the quotes are needed because of the parentheses.
A run whose only divergences are inside their thresholds reports `within_threshold` rather than `mismatched`. That is a distinct status you can act on separately — see [`--fail-on`](/reconciliation/cicd-and-automation#choosing-what-fails-the-build).
## Hash algorithms
`row_checksum` needs a hash function that both databases compute identically. The tool negotiates the best one available on both sides, so you normally do not think about it:
| Algorithm | Why it might be chosen |
| ------------------ | ------------------------------------------------------- |
| `farm_fingerprint` | Fastest where both sides support it — notably BigQuery. |
| `xxhash64` | Fast, same-platform comparisons (Databricks). |
| `md5` | The universal fallback. Supported everywhere. |
Set `hash_algorithm:` explicitly (`auto`, `md5`, `farm_fingerprint`, `xxhash64`) only when you have a reason to pin it — for example, to keep checksums stable across a platform migration.
## Next
The checksum formula, bisection, segmentation strategies and privacy levels.
Aggregate mode on a lagging target needs a cutoff. Here is why.
Reading a drill tree, and following a finding to the rows.
Every field of `aggregate:` and `thresholds:`, generated.
# Concepts and vocabulary
Source: https://docs.synq.io/reconciliation/concepts
The words used across the CLI, the app and the API — and what each one means
One page, so the rest of this section can use these words without re-explaining them. If you are reading a run, an audit log or an API response and a term is unfamiliar, it is here.
## The building blocks
A YAML file — and, once uploaded, a stored, versioned object in your workspace — holding one or more reconciliations plus the connections they use. A suite is the unit you save, version, run and promote. It has a `name`, a `title`, and optionally a `description`.
One comparison of one dataset against one other dataset. A suite contains reconciliations, keyed by name under `reconciliations:`. This is the unit that passes or fails, that becomes an asset when promoted, and that `--include` / `--exclude` select.
One side of a reconciliation: `source:` or `target:`. A dataset names a connection plus either a `table:` or a `query:`, and optionally narrows it with `columns:`, `exclude_columns:` or `where:`.
The name a dataset refers to when it says which database to read from. Locally, a connection holds credentials. In a workspace suite, the same name binds to an **integration**. See [connection vs integration](#connection-vs-integration) below — this distinction causes more confusion than anything else here.
The column — or tuple of columns — that identifies a row. Declared as `key_column:` or `key_columns:`; both accept a string or a list. Key columns must be unique, and ideally indexed: the drill-down orders and range-filters on them, so a matching index is what keeps a drill cheap.
How the two sides are compared: `row_count`, `row_checksum` or `aggregate`. See [Comparison modes](/reconciliation/comparison-modes).
## Running and inspecting
Stage one of a run: one aggregate query per side returning counts and checksums. Answers "do they agree?" without locating anything. `synq-recon run-check` runs this stage alone.
Stage two: recursively narrowing the difference. In `row_count` and `row_checksum` modes it bisects the key space into segments; in `aggregate` mode it walks down the `group_columns` hierarchy. Only what mismatched is drilled. `synq-recon run-drill` runs this stage, and `synq-recon run --auto-drill` runs both.
A **segment** is a key range the drill-down compared as a unit. A **mismatch leaf** is a segment where the two sides disagree and drilling stopped — because it hit the row threshold, the depth limit, or could not be split further. Leaves are the actionable output of a run: each one carries the key range, why drilling stopped, and SQL that returns the rows.
One execution of a suite. A run has a status, a trigger, timings, and per-reconciliation results. Runs executed by our backend also have an **invocation id**, which is how you fetch the run later.
The full record of a run: every query as it was actually executed, every count, checksum, timing and mismatch leaf. Written locally with `--audit-log `, and stored in the workspace for backend runs. Its shape is published as the [audit-log schema](https://schemas.synq.io/synq-recon/v1/audit-log.html). It records connection *names*, never credentials.
Why a run started: `adhoc` (submitted on demand against a Development suite), `scheduled` (a schedule fired), or `api` (an explicit trigger — which covers both the Run button on a promoted suite and an external caller such as a CI job).
## Development, Production and deployments
The stage a suite lands in when you save it to the workspace with `upload-config`, or create it in the app's new-suite wizard. Stored and versioned, runnable on demand, not scheduled. This is the shared draft.
The stage a suite reaches when you `promote` it. Its results become platform assets and checks, and it can run on a schedule or be triggered through the API.
The object promoting creates: an **immutable snapshot** of the suite, plus its schedule, connection bindings, run settings and annotations. A deployment is a snapshot, not a pointer — editing the suite in Development changes nothing in Production until you re-promote.
Every `upload-config` creates a new version of the stored suite, with an optional `--change-summary`. `synq-recon suite versions ` lists them; the app has a version picker. Promoting captures one specific version into the deployment.
## Connection vs integration
The same YAML key means two different things depending on where the suite runs. This is worth reading once, carefully.
```yaml Local — connection holds credentials theme={null}
connections:
gateway:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
warehouse:
snowflake:
account: myorg.us-east-1
warehouse: COMPUTE_WH
role: ANALYST
username: ${SF_USER}
password: ${SF_PASSWORD}
databases: [ANALYTICS]
reconciliations:
orders-daily:
source:
connection: gateway # ← resolves to a block above
table: public.orders
target:
connection: warehouse # ← resolves to a block above
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
```
```yaml Workspace — connection names an integration theme={null}
# No connections block at all: the names below bind to workspace integrations.
reconciliations:
orders-daily:
source:
connection: gateway # ← binds to a workspace integration
table: public.orders
target:
connection: warehouse # ← binds to a workspace integration
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
```
* A **connection** is the name a reconciliation refers to. It is always just a name.
* An **integration** is a warehouse credential your workspace already manages, with a UUID. Backend runs use integrations; they never see the credentials in your YAML.
When a suite runs on our backend, each connection name is bound to an integration. By default binding is by identity — a connection named `warehouse` binds to the integration whose id is `warehouse`. Override it explicitly:
```bash theme={null}
synq-recon connections remote list # discover integration ids
synq-recon run-remote --map warehouse=
```
The practical consequence: keep credentials out of the suite entirely. Put them in a git-ignored `.connections.yaml` keyed by the same connection names, and the *same* suite file runs locally against your credentials and in the workspace against integrations, with nothing to change between them. [Authoring suites](/reconciliation/authoring-suites#keep-credentials-out-of-the-suite) shows the layout.
## Replaying a finished run
Re-execute a finished run's queries and report what moved. The question it answers is "did the difference go away?" — after a backfill, a pipeline fix, or a redeploy. `synq-recon recheck `; in the app, **Re-check** on the run detail page.
Continue a finished run's drill-down from where it stopped, at a finer threshold or through another grouping column. `synq-recon drill-deeper `; in the app, **Drill deeper**.
Both replay the queries recorded in the audit log rather than re-deriving them, which is what makes "did it move?" a meaningful comparison. [Investigating results](/reconciliation/investigating-results#re-check-and-drill-deeper) covers the consequences.
## You may also see
Older suites, stored YAML and API payloads sometimes use different spellings. All of these still work; the left column is what the documentation uses.
| Canonical | Also appears as | Notes |
| ----------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `row_checksum` | `full` | `full` is an accepted legacy spelling. The YAML writer emits `row_checksum`, so a suite round-tripped through `synq-recon suite yaml` comes back normalised. |
| reconciliation | check, comparison, case | A promoted reconciliation *produces* a platform check, which is exactly why we do not also call the reconciliation itself one. `case` is an internal storage term you may see in asset paths. |
| drill-down | drilldown, bisection drill | "Bisection" is the name of the algorithm, and is reserved for [How comparison works](/reconciliation/how-comparison-works). |
| Re-check / Drill deeper | `revalidate`, `resume-drill` | The old command names. Use `recheck` and `drill-deeper`. |
# Getting started
Source: https://docs.synq.io/reconciliation/getting-started
Install the CLI, write your first suite, and locate a real difference in under ten minutes
By the end of this page you will have run a reconciliation, seen it report a mismatch, and narrowed that mismatch down to the two rows responsible — all from your own machine.
The walkthrough uses a self-contained dataset so you can follow it with no warehouse and no credentials. [Point it at your own databases](#point-it-at-your-own-databases) at the end is a two-line change.
## Install the CLI
Pick a version from the [releases page](https://github.com/getsynq/synq-recon/releases)
— the archive filename carries it, so it has to be named explicitly:
```bash theme={null}
VERSION=0.2.0
OS=$(uname -s | tr '[:upper:]' '[:lower:]') # darwin or linux
ARCH=$(uname -m | sed 's/x86_64/amd64/; s/aarch64/arm64/')
curl -fL "https://github.com/getsynq/synq-recon/releases/download/v${VERSION}/synq-recon_${VERSION}_${OS}_${ARCH}.tar.gz" \
| tar -xz
sudo mv synq-recon /usr/local/bin/
```
Builds are published for macOS and Linux on both amd64 and arm64. Each archive
also carries the operating guide and the example suites, and every release ships
a `checksums.txt` you can verify with
`sha256sum -c checksums.txt --ignore-missing`.
Every published binary runs DuckDB, which is what the walkthrough below uses so
it needs no warehouse and no credentials.
On macOS a downloaded binary may be quarantined. If it refuses to start,
`xattr -d com.apple.quarantine /usr/local/bin/synq-recon` clears the flag.
```bash theme={null}
docker pull europe-docker.pkg.dev/synq-cicd-public/synq-public/synq-recon:latest
```
Run it with your working directory mounted, so it can read your suite file:
```bash theme={null}
docker run --rm -v "$PWD:/work" -w /work \
europe-docker.pkg.dev/synq-cicd-public/synq-public/synq-recon:latest \
check-config suite.yaml
```
The image runs DuckDB, which is what the walkthrough below uses so it needs no warehouse. If a `type: duckdb` connection fails with a driver error, your image predates DuckDB support — pull `:latest`.
Check that it runs:
```bash theme={null}
synq-recon --help
```
## Sign in
Authentication is only needed once you want to save suites to your workspace or run them on our backend. A purely local comparison needs no credentials at all.
```bash theme={null}
synq-recon auth login
synq-recon auth whoami
```
`auth whoami` prints the workspace your credential resolves to. Get into the habit of reading that line — it is the only thing that decides which workspace a command writes to.
## Describe what to compare
A **suite** is a YAML file holding the connections and the comparisons. Save this as `quickstart.yaml`:
```yaml quickstart.yaml theme={null}
# yaml-language-server: $schema=https://schemas.synq.io/synq-recon/v1/config.schema.json
name: quickstart
title: Quickstart
connections:
local:
duckdb:
database: ":memory:"
# Stands in for two real systems: an application database and the warehouse
# copy of it. The copy is missing one order and has the wrong amount on another.
setup:
local:
- |
CREATE TABLE app_orders AS
SELECT i AS order_id, 'CUST-' || (i % 7) AS customer_id, i * 10.0 AS amount
FROM generate_series(1, 1000) AS t(i)
- |
CREATE TABLE warehouse_orders AS
SELECT order_id, customer_id,
CASE WHEN order_id = 617 THEN amount + 5 ELSE amount END AS amount
FROM app_orders
WHERE order_id <> 384
reconciliations:
orders:
title: Orders (application vs warehouse)
source:
connection: local
table: app_orders
target:
connection: local
table: warehouse_orders
key_columns: [order_id]
mode: row_checksum
bisection:
factor: 10
threshold: 10
```
That first line points your editor at the published JSON schema, which gives you completion and inline validation for every field. Keep it at the top of every suite you write.
The `bisection` block is tuned small here so the drill-down has something to do on a thousand rows. On real tables the defaults are the right starting point.
## Validate before you run
```bash theme={null}
synq-recon check-config quickstart.yaml
```
```
Configuration Summary
=====================
Connections (1):
- local (duckdb)
Reconciliations (1):
- orders
Source: local
Target: local
Key Column(s): order_id
Mode: row_checksum
Bisection: factor=10, threshold=10
Configuration check passed!
```
This costs nothing and touches no database. Add `--db` to also connect, run every query through the database's planner, and report table sizes, indexes and a suggested key column:
```bash theme={null}
synq-recon check-config quickstart.yaml --db
```
`--db` does not run the suite's `setup:` SQL, so for this walkthrough it will report that `app_orders` does not exist. That is expected — the tables are created by `setup` when the comparison runs.
## Compare
```bash theme={null}
synq-recon run-check quickstart.yaml --no-report
```
```
Coalesce Quality Reconciliation - Quick Check
============================================
Reconciliation: Orders (application vs warehouse) (orders)
Mode: row_checksum
Duration: 6ms
Source Target
Row Count 1,000 999
Status: MISMATCH
- Source has 1 more rows than target
Hint: Run 'synq-recon run-drill --include orders' to locate differences.
```
Two queries — one per side — and you know the datasets disagree. If they had agreed, this would be the entire run.
The command exits `1`. For a comparison, a non-zero exit means "differences found", which is a result rather than a failure. [Exit codes](/reconciliation/running-locally#exit-codes) has the full list.
`--no-report` keeps the run entirely local. Without it, a run reports its results to your workspace whenever it can find a credential, so they show up in the app alongside backend runs.
## Locate the difference
```bash theme={null}
synq-recon run quickstart.yaml --auto-drill --no-report
```
```
Depth 0: Segment [*, *)
Source: 1,000 rows, checksum: -2052783606565609
Target: 999 rows, checksum: -2210053578859533
Status: MISMATCH -> drilling down (20/1,000 rows in mismatched segments)
Depth 1: Segment [301, 401)
Source: 100 rows, checksum: -167029730887454
Target: 99 rows, checksum: -295596598382435
Status: MISMATCH -> drilling down (10/100 rows in mismatched segments)
Depth 2: Segment [381, 391)
Source: 10 rows, checksum: 330886401684630
Target: 9 rows, checksum: 202319534189649
Status: MISMATCH (leaf: threshold_reached)
Depth 1: Segment [601, 701)
Source: 100 rows, checksum: -683539572079355
Target: 100 rows, checksum: -712242676878298
Status: MISMATCH -> drilling down (10/100 rows in mismatched segments)
Depth 2: Segment [611, 621)
Source: 10 rows, checksum: -381158226855223
Target: 10 rows, checksum: -409861331654166
Status: MISMATCH (leaf: threshold_reached)
Summary
-------
Segments processed: 33
Mismatch leaves: 2
Max depth reached: 2
Duration: 26ms
```
Read that from the top. The whole dataset disagrees, so it is split into ten segments; eight of them match on the first comparison and are never looked at again. The two that differ get split again, and the run stops with two ten-row windows to inspect.
Notice the shape of each finding. The segment around order 384 has **one fewer row** on the target — a missing row. The segment around order 617 has the **same count but a different checksum** — a value changed. You have not read a single row value yet.
Thirty-three queries to find two bad rows in a thousand. The saving grows with the table: the number of comparisons scales with the *logarithm* of the row count, not the row count. That is the whole point of the drill-down.
## Get the rows
Every mismatch leaf comes with ready-to-run SQL for both sides:
```bash theme={null}
synq-recon run-drill quickstart.yaml --no-report -o json 2>/dev/null \
| jq -r '.investigation_queries[] | .source_query, .target_query, "--"'
```
Run those against the two databases and you are looking at the rows themselves. This is the point at which row values enter the picture — on your terms, in your SQL client, for ten rows rather than a million.
Redirect logs with `2>/dev/null`, never `2>&1`. Logs go to stderr and results to stdout; merging them makes `-o json` unparseable.
## Point it at your own databases
Swap the `connections:` block for the real thing, drop the `setup:` block, and name your tables. Nothing else changes:
```yaml suite.yaml theme={null}
connections:
app:
postgres:
host: db.internal
port: 5432
database: payments
username: ${PG_USER}
password: ${PG_PASSWORD}
warehouse:
snowflake:
account: myorg.us-east-1
warehouse: COMPUTE_WH
role: ANALYST
username: ${SF_USER}
password: ${SF_PASSWORD}
databases: [ANALYTICS]
reconciliations:
orders:
title: Orders (application vs warehouse)
source:
connection: app
table: public.orders
target:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
key_columns: [order_id]
mode: row_checksum
```
Then run the same four commands. Two things to do before you trust the result:
1. **Keep the credentials out of the file.** Move the `connections:` block to a git-ignored `.connections.yaml` — the CLI picks it up automatically. See [keep credentials out of the suite](/reconciliation/authoring-suites#keep-credentials-out-of-the-suite).
2. **Run `check-config --db`.** It confirms every connection and query, and warns if your key column is not indexed — which is the difference between a drill that takes seconds and one that takes minutes.
## Next steps
Datasets, column selection, key columns, and the validation loop in full.
Comparing two live systems? Read this before you trust a mismatch.
Save the suite, run it on our backend, put it on a schedule.
Every command, argument and flag, generated from the CLI itself.
# How comparison works
Source: https://docs.synq.io/reconciliation/how-comparison-works
The checksum, the bisection, the segmentation strategies, and what each one reveals
You do not need this page to use reconciliation. Read it when you want to know what the queries actually do — because you are reviewing them, because you are reasoning about cost, or because you need to tell a security reviewer exactly what leaves the database.
## The row checksum
Each row is reduced to a single 48-bit signed integer:
```
row_checksum = int(first 12 hex digits of MD5(col1 || '|' || col2 || ...)) - 2^47
```
Three details matter:
* **Columns are cast to text and joined with `|`** before hashing, in the order the comparison resolved them. `NULL` becomes the sentinel ``, so a null and an empty string are distinguishable.
* **Only 48 of the 128 bits are kept.** That leaves room to sum millions of row checksums inside a 64-bit integer without overflowing, which is the whole trick — the aggregate is computed by the database, not by us.
* **Subtracting 2^47 centres the values around zero**, so a sum over many rows drifts towards zero rather than towards the top of the range.
A segment's checksum is then simply:
```
segment_checksum = SUM(row_checksum)
```
Every dialect gets its own expression for the same arithmetic — `HASHBYTES` on SQL Server, `STANDARD_HASH` on Oracle, `MD5` plus a base conversion elsewhere — so two different platforms produce the same number for the same data. Which hash function is used is [negotiated per reconciliation](/reconciliation/comparison-modes#hash-algorithms).
**What leaves the database, in full:** one row per query containing a count and a sum. No row values, no keys, no column contents. That is true of the quick check and of every level of the drill-down, unless you explicitly raise the [privacy level](#privacy-levels).
## The quick check
One query per side:
```sql theme={null}
SELECT COUNT(*) AS row_count,
SUM() AS checksum
FROM () AS sub
```
If both numbers agree, the datasets are identical over the compared columns, and the run is done. A 500-million-row table costs one aggregate scan per side to clear.
## The bisection drill-down
When the totals disagree, the run needs to find *where*. It does that by splitting the key space and re-asking the same question of each piece.
`bisection.factor` (default 32, maximum 1024) sets N. The boundaries come from the segmentation strategy below.
Not N queries — one. The counts and checksums for all N segments come back from a single bucketed aggregate per side, so a level costs two queries regardless of the factor.
A segment whose count and checksum match on both sides is identical and is never queried again.
Drilling stops when a segment's row count falls below `bisection.threshold` (default 16384), when `--depth` is reached, or when the segment cannot be split any further. Those segments are the run's **mismatch leaves**.
Because each level discards everything that matched, the number of queries scales with the *logarithm* of the row count for data that is mostly identical. Locating one bad row in ten million takes a handful of round trips.
**The inverse also holds, and it is the one failure mode to know about.** Bisection is efficient because most segments match. If *most* rows differ — a broken backfill, a wrong join, comparing two unrelated tables — nothing can be discarded, every segment recurses, and the drill degenerates into thousands of queries each scanning a slice of the table.
If a drill reports thousands of leaves or runs for minutes, stop it. Localise with an [aggregate comparison](/reconciliation/comparison-modes#aggregate-mode) first — one query per side tells you which groups diverge — then drill a dataset narrowed to those groups.
## Segmentation strategies
How the key space is divided is configurable, and the choice is a trade-off between drill efficiency and what the boundaries reveal.
| `bisection.strategy` | How segments are formed | What the queries expose | Behaviour |
| ------------------------ | ------------------------------------- | ----------------------------------------- | ------------------------------------------------- |
| `quantile` **(default)** | `NTILE`-based split of the key range | Key boundary values | Recursive, multi-level |
| `hash` | `MOD(hash(key), N)` bucket assignment | Nothing about key values at the top level | Hash buckets first, then quantile within a bucket |
| `time` | Fixed periods of a time column | Time boundaries | Time buckets first, then quantile within a bucket |
| `auto` | Same as `quantile` | Same as `quantile` | Same as `quantile` |
### When to choose something other than the default
```yaml theme={null}
bisection:
strategy: hash
factor: 64
```
Segment boundaries are hash buckets, so the queries and the audit log contain no key values at the top level. Use it when the key is itself sensitive — an account number, a national id, a customer email.
The cost is locality: hash buckets scatter across the table, so the database cannot use a key index to prune a bucket the way it can prune a range.
```yaml theme={null}
bisection:
strategy: time
time_column: created_at
time_granularity: day
```
Segments are calendar periods (`hour`, `day`, `week`, `month`, `quarter`, `year`). On a table partitioned or clustered by that column this is the cheapest possible split — a clean day is dismissed with a partition-pruned query — and the findings read naturally: "the 17th is wrong".
This is the right strategy for validating an incremental pipeline, where differences cluster by load date.
## Privacy levels
By default nothing but counts and checksums is retrieved. `reporting.level` opts into more, per reconciliation:
| `reporting.level` | Retrieved | Use for |
| -------------------------- | ---------------------------------------- | --------------------------------------------------------- |
| `count_only` **(default)** | `COUNT(*)` and `SUM(checksum)` | Detecting and locating differences without exposing data. |
| `with_keys` | ...plus the key values of differing rows | Handing someone an exact list of affected ids. |
| `detailed` | ...plus sample row values | Debugging a specific difference in place. |
```yaml theme={null}
reporting:
level: with_keys
sample_limit: 100 # cap on rows returned at with_keys or detailed
```
`detailed` additionally requires `consent_acknowledged: true` — a deliberate speed bump, because it is the one setting that puts row values into a run record.
You rarely need either. `count_only` already tells you *which key ranges* differ, and every mismatch leaf carries ready-to-run SQL you can execute yourself against the two databases. That keeps row values in your SQL client and out of the audit log — see [investigation queries](/reconciliation/investigating-results#follow-a-finding-to-the-rows).
## Cost, in queries
| Stage | Queries |
| ---------------------------------- | ---------------------------------------------------------------- |
| Quick check | 2 — one per side |
| One drill level | 2 — one bucketed aggregate per side, whatever the factor |
| A drill over mostly-identical data | 2 × (levels needed), typically a handful |
| An aggregate comparison | 2 per hierarchy level entered, and only diverging groups descend |
What each query *scans* depends on your schema, which is why [key column indexing](/reconciliation/authoring-suites#key-columns-decide-everything) matters more than any setting on this page. [Running locally](/reconciliation/running-locally#gate-a-large-run-before-it-happens) covers the pre-run scan estimate and the gate flags.
## Next
Choosing between counts, checksums and aggregate measures.
Reading a segment tree and following a leaf to the rows.
# Investigating results
Source: https://docs.synq.io/reconciliation/investigating-results
Reading a run, following a finding to the rows, and confirming a fix worked
A mismatch is the start of the work, not the end of it. This page is the path from "these two disagree" to "here is the row, and here is why".
## Two statuses, and they mean different things
| Run status | Meaning |
| -------------------------- | ------------------------------------------------------------------------------ |
| `scheduled`, `in_progress` | Not finished. |
| `succeeded` | The run executed cleanly. **This says nothing about whether the data agreed.** |
| `failed` | The run itself could not complete — a connection, a timeout, a bad query. |
| `cancelled` | Cancelled, by a person or by `runs cancel`. |
| Result status | Meaning |
| ------------------ | ----------------------------------------------------------------------------------------------------------- |
| `passed` | The two sides agree. |
| `within_threshold` | They differ, but inside the configured [aggregate thresholds](/reconciliation/comparison-modes#thresholds). |
| `mismatched` | A real difference. |
| `failed` | This reconciliation could not be evaluated. |
A `succeeded` run reporting `mismatched` is the normal, healthy case — the tool did its job and found something. Filter on the result status, not the run status, when you want "did anything differ?".
## Reading a finished run
```bash theme={null}
synq-recon audit-logs list --status mismatched --limit 10
synq-recon audit-logs get
synq-recon audit-logs get -o json > run.json
```
**Health → Reconciliations** lists runs for Development and Production. Opening one gives the run detail page: per-reconciliation results, the segment tree, the drift map, the aggregate drill tree, the queries that ran, and the investigation queries for each finding.
### The segment tree
In `row_count` and `row_checksum` modes, a drill-down produces a tree of key ranges. Each node carries both sides' count and checksum, and the leaves are where drilling stopped:
```
Depth 0: Segment [*, *)
Source: 1,000 rows, checksum: -2052783606565609
Target: 999 rows, checksum: -2210053578859533
Status: MISMATCH -> drilling down (20/1,000 rows in mismatched segments)
Depth 1: Segment [301, 401)
Source: 100 rows, checksum: -167029730887454
Target: 99 rows, checksum: -295596598382435
Status: MISMATCH -> drilling down (10/100 rows in mismatched segments)
Depth 2: Segment [381, 391)
Source: 10 rows, checksum: 330886401684630
Target: 9 rows, checksum: 202319534189649
Status: MISMATCH (leaf: threshold_reached)
```
`20/1,000 rows in mismatched segments` is the useful number at each level: it is how much of the dataset is still in play. If it stays close to the total as you descend, the data is not mostly-identical and you are in the [expensive case](/reconciliation/how-comparison-works#the-bisection-drill-down).
The app renders the same tree graphically, plus a **drift map** — the key space with the divergent regions highlighted, which makes "the whole tail is wrong" versus "three rows scattered" obvious at a glance.
### What a mismatch leaf tells you
Read the **types**, not the counts. Every type that applies is reported, so a segment that differs in both size and content reports two:
| `mismatch_types` | Meaning |
| ------------------- | --------------------------------------------------------------------------- |
| `MISSING_IN_TARGET` | Rows on the source, none on the target — a real gap. |
| `MISSING_IN_SOURCE` | Rows on the target, none on the source — usually an orphan. |
| `COUNT_MISMATCH` | Both sides have rows, but not the same number. |
| `DATA_MISMATCH` | Both sides have the same rows and the checksums disagree — a value changed. |
Count direction alone does not classify a difference. A target with one row *more* than the source can still be missing a live row and carrying two orphans. The counts net out; the types do not.
Each leaf also carries a `drill_stop_reason`, which tells you whether the finding is as narrow as it can get:
| Reason | Meaning | What to do |
| ------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| `THRESHOLD_REACHED` | The segment fell below `bisection.threshold`. | [Drill deeper](#re-check-and-drill-deeper) with a lower `--threshold` if you want a tighter range. |
| `MAX_DEPTH_REACHED` | The depth limit stopped it. | Drill deeper with `--depth`. |
| `NOT_SPLITTABLE` | The segment cannot be divided further — typically identical key values. | This is as narrow as it gets. Look at the rows. |
### The aggregate drill tree
In `aggregate` mode the equivalent output is a hierarchy of groups, each labelled with why it diverged — `MEASURE_MISMATCH` for its own numbers, `SUBGROUP_MISMATCH` for something below it. [Comparison modes](/reconciliation/comparison-modes#the-group-hierarchy) has a worked example.
## Follow a finding to the rows
Every mismatch leaf comes with **investigation queries**: ready-to-run SQL for both sides, scoped to that leaf's key range.
```bash theme={null}
synq-recon run-drill suite.yaml --include orders -o json 2>/dev/null \
| jq -r '.investigation_queries[] | .source_query, .target_query, "--"'
```
Or from a saved audit log:
```bash theme={null}
jq -r '.reconciliations[].stages[].bisection_result?.mismatch_leaves[]?.diff_queries
| select(.) | .source_rows, .target_rows, "--"' run.json
```
The run detail page shows the investigation queries for each finding, ready to copy.
They look like this — the reconciliation's own dataset, wrapped in the leaf's key bounds:
```sql theme={null}
-- Source: primary (postgres)
-- Segment: depth=2, key range [381, 391)
select *
from (
SELECT * FROM app_orders
) AS sub
where order_id >= 381 AND order_id < 391
order by order_id
```
Run them against the two databases and you are looking at the rows themselves — ten of them, not a million.
This is why raising the [privacy level](/reconciliation/how-comparison-works#privacy-levels) is rarely necessary. `count_only` already tells you exactly which rows to look at; running the query yourself keeps the values in your SQL client rather than in a run record.
## Re-check and Drill deeper
Two operations on a **finished run**, rather than on a suite. Both take either a local audit-log file or, for a run stored in the workspace, its invocation id.
```bash theme={null}
# Did the difference go away? (after a backfill, a fix, a redeploy)
synq-recon recheck run.json --connections .connections.yaml
# Narrow every still-open segment further
synq-recon drill-deeper run.json --connections .connections.yaml --threshold 2
# Break each divergent aggregate group down by another column
synq-recon drill-deeper run.json --add-group-column region
# Hand the replay to the backend instead, against workspace integrations
synq-recon recheck --remote
```
**Re-check** and **Drill deeper** on the run detail page. Same operations, same semantics.
A re-check answers the only question that matters after a remediation, and answers it in one line:
```
Re-validation vs Previous Run
=============================
Previous run: bdb89bea-ab7f-434b-8259-e6dad97531b2
This run: ba170eb5-392c-4a6f-98a1-0a9b6603c5e7
RECONCILIATION BEFORE AFTER CHANGE
-------------- ---------------- ---------------- ------------------
orders mismatched mismatched still mismatched (row gap unchanged at -1)
```
And a drill deeper picks up where the previous run stopped rather than starting over. Continuing the run from [Getting started](/reconciliation/getting-started) at `--threshold 2`:
```
Depth 0: Segment [*, *)
Source: 20 rows, checksum: -50271825170593
Target: 19 rows, checksum: -207541797464517
Status: MISMATCH -> drilling down (2/20 rows in mismatched segments)
Depth 2: Segment [381, 391)
Status: MISMATCH -> drilling down (1/10 rows in mismatched segments)
Depth 3: Segment [384, 385)
Source: 1 rows, checksum: 128566867494981
Target: 0 rows, checksum: 0
Status: MISMATCH (leaf: threshold_reached)
Depth 2: Segment [611, 621)
Status: MISMATCH -> drilling down (1/10 rows in mismatched segments)
Depth 3: Segment [617, 618)
Source: 1 rows, checksum: -51531599134958
Target: 1 rows, checksum: -80234703933901
Status: MISMATCH (leaf: threshold_reached)
```
Twenty-two queries, and the answer is exact: order 384 is absent from the target, and order 617 exists on both sides with a different value. Note that it re-entered at depth 0 with **20 rows**, not 1,000 — only what the previous run left open is in scope.
### Four things that govern a replay
The audit log holds each query *after* variable interpolation and cutoff resolution, so a re-check compares the same window as the original run. That is precisely what makes "did the gap move?" a meaningful question rather than two unrelated measurements.
The consequence: a replay does **not** pick up an edited query, a changed variable, or a new cutoff until you pass `--reresolve`. And `--reresolve` is required for an `as_of` reconciliation, which otherwise re-compares the same frozen snapshot forever and can never turn green.
`drill-deeper` picks up the segments the previous run stopped at on its threshold or depth limit. `--depth` counts from the depth they already reached, so it means "this many *more* levels".
Segments that could not be split further, and aggregate groups present on only one side, are reported and skipped rather than silently dropped. An aggregate drill already visits every configured group column, so resuming one needs at least one `--add-group-column`.
By default. `--all` re-runs every reconciliation in the run.
It records connection *names* only, never credentials. Pass `--connections`, exactly as for a normal run — `no connections available to replay run ...` is what a missing one looks like.
`--remote` hands the replay to our backend, against workspace integrations instead of local credentials. It needs a stored run's invocation id — a local file has nothing server-side to reference — and accepts `--include` but not `--exclude`.
## Reading an audit log directly
The audit log is the machine-readable form of everything above, and its shape is published:
Every field, rendered.
Validate a log against the schema you were sent.
[Running locally](/reconciliation/running-locally#audit-logs) has the `jq` starting points, and the two traps worth internalising: snake\_case in a local file versus camelCase from the API, and counts encoded as strings.
## Next
Before you chase a difference, rule out the comparison window.
Turning a reconciliation into a gate that blocks a bad release.
# Reconciliation overview
Source: https://docs.synq.io/reconciliation/overview
Prove that two datasets agree — across databases, across clouds, without moving the data
Reconciliation answers one question: **do these two datasets actually agree?**
You point Coalesce Quality at a dataset in a source database and a dataset in a target database. It compares them, tells you whether they match, and — when they don't — narrows the difference down to the specific rows or groups involved.
**Only counts and checksums leave the database.** By default a reconciliation retrieves row counts and aggregate checksums, never row values. Both sides can be in different databases, different clouds, or different accounts, and nothing is copied between them. Revealing more than that is opt-in, per reconciliation — see [privacy levels](/reconciliation/how-comparison-works#privacy-levels).
## When you need it
Monitors and tests tell you whether one dataset looks healthy. Reconciliation tells you whether two datasets tell the same story. Reach for it when correctness depends on a copy staying faithful to its origin:
You are moving from one warehouse to another and need evidence — not a spot check — that the new platform returns the same data before you cut over.
A change-data-capture stream or read replica quietly falls behind, drops rows, or applies an update twice. Nothing in either system is "broken", so nothing alerts.
A transformation is supposed to preserve totals. Comparing the summary table against the operational source catches the day it stopped.
Finance reads the warehouse, the application writes Postgres. A reconciliation makes "the numbers don't match" a measurable, scheduled check instead of an argument.
## How a comparison runs
Every reconciliation runs in up to two stages, and the second one only happens if the first finds something.
A single aggregate query per database returns the row count and a checksum over the compared columns. It is fast and cheap no matter how large the tables are, and for the common case — the data agrees — this is the whole run.
If the totals disagree, the drill-down splits the key range into segments and re-compares each one, recursing only into the segments that differ. Finding a handful of bad rows in a large, mostly-identical table takes a logarithmic number of queries rather than a full row-by-row diff.
The result is a set of key ranges (or, in aggregate mode, groups) where the two sides disagree, each with ready-to-run SQL that returns the offending rows. The algorithm is described in full on [How comparison works](/reconciliation/how-comparison-works).
## Three stages, one suite
A **suite** is a YAML file holding one or more reconciliations plus the connections they use. The same suite moves through three stages, and the file never has to change to do it.
```mermaid theme={null}
flowchart LR
A[Local — author and run on your machine]
B[Development — stored and versioned in your workspace]
C[Production — a scheduled deployment]
A -- upload-config --> B
B -- promote --> C
C -- edit, then re-promote --> B
```
| Stage | What it is for | Where it is driven from |
| --------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| **Local** | Authoring and iterating. Fast feedback, no workspace state, nothing to clean up. | [The CLI](/reconciliation/running-locally) |
| **Development** | A stored, versioned suite anyone on the team can run on demand, without local database access. The shared draft. | [CLI or UI](/reconciliation/workspace-suites) |
| **Production** | A scheduled or API-triggered deployment whose results feed the rest of the platform. | [CLI or UI](/reconciliation/workspace-suites#promote-to-production) |
You can stop at any stage. A suite that only ever runs locally, reporting nothing to the cloud, is a supported way to use the tool — see [standalone runs](/reconciliation/running-locally#standalone-and-air-gapped-runs).
## Where results show up
Once a suite is promoted, each reconciliation in it becomes a first-class part of your workspace rather than a line of terminal output:
* **Assets** — every reconciliation in a deployment appears as an asset, so it shows up in search, lineage and folders alongside your tables and models.
* **Checks** — each run produces a check result, which means reconciliations participate in [check categorisation](/analytics/check-categories) and health reporting like any other check.
* **Issues and incidents** — a failing reconciliation opens an [issue](/incidents/incident-overview), with the mismatch detail attached.
* **Alerts** — issues route through your existing [alert channels](/alerts/alert-overview) and [ownership](/ownership/ownership-overview) rules. There is no separate notification setup.
* **Annotations** — labels you put on a suite or reconciliation follow it into the platform and annotate the resulting assets and checks.
In the app, reconciliations live under **Health → Reconciliations**, split into **Development** and **Production**.
## Where to go next
Install, authenticate, and locate a real difference in a sample dataset.
Suite, reconciliation, connection, deployment, run — the words used everywhere else.
The YAML anatomy, choosing key columns, and the validation loop.
The operating guide for a coding agent driving the CLI.
# Running locally
Source: https://docs.synq.io/reconciliation/running-locally
Running a suite against databases you can reach — output, audit logs, cost gates and exit codes
The local loop is where a suite gets written. It runs against credentials on your machine, against databases your machine can reach, and it is the fastest way to iterate.
## The three commands
Stage one only: counts and checksums. One query per side.
Stage two only: locate the differences. Assumes you already know there are some.
Stage one, then stage two on whatever mismatched. The everyday command.
```bash theme={null}
synq-recon run-check suite.yaml # is anything different?
synq-recon run-drill suite.yaml --include orders # where is it?
synq-recon run suite.yaml --auto-drill # both, in one pass
```
Reconciliation names are selected with `--include` and `--exclude`, both repeatable — **not** positionally. `run-drill suite.yaml orders` is rejected with `accepts 1 arg(s), received 2`.
## Selecting and parameterising a run
| Flag | Effect |
| ----------------------- | -------------------------------------------------------------------------------------------------------- |
| `--include ` | Run only these reconciliations. Repeatable. |
| `--exclude ` | Run everything except these. Repeatable. |
| `--var key=value` | Override a [template variable](/reconciliation/time-windows-and-cutoffs#template-variables). Repeatable. |
| `--concurrency ` | Reconciliations to run in parallel. Default `1`. |
| `--timeout ` | Per-query timeout. Default `5m`. |
| `--connections ` | Connections file. `.connections.yaml` in the working directory is picked up automatically. |
| `--dbt-profiles ` | Resolve connections from a dbt `profiles.yml` as a fallback. |
`--concurrency` fans reconciliations onto their connections; each connection additionally caps its own parallel queries with `parallelism:` (default 8), so raising concurrency does not stampede a single warehouse.
Every flag on every command is in the [CLI reference](/reconciliation/cli), which is generated from the binary — this page covers the ones with a decision attached.
## Reading the output
```bash theme={null}
synq-recon run-check suite.yaml -o json
```
**Set `-o` explicitly whenever something is going to parse the output.** The default is `table` for a human terminal, but it switches to `toon` when the CLI detects an AI-agent environment. An agent that assumed `table` — or `json` — gets neither.
Three more things to know before you pipe anything:
Redirect with `2>/dev/null`. Never `2>&1` — that merges log lines into the document you are trying to parse.
```bash theme={null}
synq-recon run-check suite.yaml -o json 2>/dev/null | jq '.summary'
```
`-o json`, and a text report for every other value. The output-shaping flags — `--jq`, `--columns`, `--no-headers`, `--wide` — do not apply to them; pipe their `-o json` through `jq` yourself.
The workspace commands (`suite`, `deployment`, `runs`, `audit-logs`, `connections`, `auth`) do honour all six formats and all four flags.
It emits the quick-check document, a plain-text banner, then one drill document per drilled reconciliation. To parse results, run the two stages separately — each is one valid document:
```bash theme={null}
synq-recon run-check suite.yaml -o json 2>/dev/null > check.json
synq-recon run-drill suite.yaml -o json 2>/dev/null > drill.json
```
Useful one-liners:
```bash theme={null}
# names of the reconciliations that differ
synq-recon run-check suite.yaml -o json 2>/dev/null \
| jq -r '.results[] | select(.match == false) | .name'
# key ranges where a difference lives
synq-recon run-drill suite.yaml --include orders -o json 2>/dev/null \
| jq -r '.mismatch_leaves[] | "\(.segment.min_key) .. \(.segment.max_key)"'
# ready-to-run SQL for the first difference, both sides
synq-recon run-drill suite.yaml --include orders -o json 2>/dev/null \
| jq -r '.investigation_queries[0] | .source_query, .target_query'
```
## Exit codes
| Command | `0` | `1` | `2` |
| ---------------------------------------------------------- | ------------------ | ------------------------------------------- | --------------------- |
| `run`, `run-check`, `run-drill`, `recheck`, `drill-deeper` | Everything matched | Differences found **or** the command failed | — |
| `run-remote --wait`, `trigger --wait` | Passed | A `--fail-on` condition was met | The run itself failed |
Locally, `1` does not distinguish "found a difference" from "could not run". If you need that distinction — in CI, say — either read `-o json` or use a backend run with `--wait`, whose codes are data-driven. See [CI/CD and automation](/reconciliation/cicd-and-automation).
## Audit logs
`--audit-log` writes the full record of a run: every query as executed, every count, checksum, timing, resolved variable, cutoff watermark and mismatch leaf.
```bash theme={null}
synq-recon run suite.yaml --auto-drill --audit-log run.json # a file
synq-recon run suite.yaml --auto-drill --audit-log audit-logs/ # a directory, auto-named
```
An audit log is what [`recheck` and `drill-deeper`](/reconciliation/investigating-results#re-check-and-drill-deeper) replay, and its shape is published as the [audit-log schema](https://schemas.synq.io/synq-recon/v1/audit-log.html).
Some paths worth knowing:
```bash theme={null}
jq -r '.reconciliations[].reconciliation.name' run.json
jq -r '.reconciliations[].stages[].quick_check_result? | select(.) | "\(.source_count) vs \(.target_count)"' run.json
jq -r '.reconciliations[].stages[].bisection_result?.mismatch_leaves[]?.segment | "\(.min_key)..\(.max_key)"' run.json
```
Two traps in that file, both of which return `null` rather than an error if you get them wrong:
* **Casing differs by source.** A local `--audit-log` file is snake\_case (`bisection_result`, `mismatch_leaves`). The same log fetched from the workspace with `audit-logs get -o json` is camelCase (`bisectionResult`, `mismatchLeaves`).
* **Counts and checksums are strings.** They are 64-bit integers, which the audit log encodes as quoted strings (`"source_count": "10"`) — unlike `run-check -o json`, where they are numbers. Compare with `tonumber`.
## What a run costs
Reconciliation runs real queries against real warehouses. On a consumption-priced platform those queries cost money, so it is worth knowing which commands spend before you put one in a loop.
| Command | Warehouse cost |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `check-config` | None. Never connects. |
| `check-config --db` | One planner call per query (`LIMIT 0`, no scan) plus a table-metadata sweep. |
| `run-check` | One aggregate query per side. Scans the compared columns once. |
| `run-drill`, `run --auto-drill` | Two queries per drill level. Cheap on mostly-identical data, [expensive when most rows differ](/reconciliation/how-comparison-works#the-bisection-drill-down). |
| `recheck`, `drill-deeper` | The stage they replay, scoped to what the previous run left open — usually much less than starting over. |
| `suite`, `deployment`, `runs`, `audit-logs`, `upload-config`, `promote` | None. Workspace API only. |
Where the engine reports them, a run prints its own statistics — including a rough BigQuery cost estimate:
```
Query Statistics
================
Bytes scanned: 4.2 GiB
Bytes billed: 4.2 GiB
Est. cost: $0.03 (BigQuery on-demand @ $6.25/TiB billed)
Slot time: 1m12s
Rows read: 18,204,551
```
BigQuery and Snowflake report bytes; ClickHouse and PostgreSQL report planner rows; DuckDB, Athena and Databricks report nothing, so the block is simply absent. The cost figure is derived from a public list price that varies by region and edition — treat it as an order of magnitude, not an invoice.
### Gate a large run before it happens
```bash theme={null}
synq-recon run-check suite.yaml --max-table-bytes 50000000000 # 50 GB
synq-recon run-check suite.yaml --max-table-rows 1000000000
```
These make the run estimate each reconciliation's scan **before** executing it — a dry run or `EXPLAIN`, not a scan — and warn when an estimate exceeds the threshold. Both default to `0` (off), so an automated run incurs no extra queries unless you ask for the gate.
Platforms that advertise no estimate support simply produce no warnings, so a gate is never a false sense of security. It is a guard against the accidental full-table drill, not a hard limit.
## Standalone and air-gapped runs
By default, a locally executed run reports its audit log to Coalesce Quality whenever it can resolve a credential, so local results appear in the workspace next to backend runs. It says so at `INFO`, naming the endpoint. This happens even when every database in the suite is local.
```bash theme={null}
synq-recon run suite.yaml --auto-drill --no-report --audit-log run.json
```
`--no-report` — or `RECON_NO_REPORT` in the environment — resolves no credential and opens no connection to us at all. The terminal and the audit-log file are the only outputs.
This is a fully supported way to operate, not a debugging flag. Combined with the default privacy level, it means: only counts and checksums leave the database, and even those never leave the machine. For a regulated environment where a comparison must not cross a boundary, this is the mode to use — and the audit log is a self-contained, schema-validated record you can hand to a reviewer.
Reporting also needs the `SCOPE_RECON_EDIT` permission. A credential without it produces one warning naming the remedy; the comparison has already happened and its result is unaffected.
## Local-only conveniences
Two features exist in the CLI and deliberately nowhere else:
* **Pre-flight table analysis.** `check-config --db` reports size, keys, indexes and a suggested key column. See [validate before you spend a query](/reconciliation/authoring-suites#validate-before-you-spend-a-query).
* **Environment overrides.** `--environment ` / `--env-file ` apply a named set of overrides at load time — most usefully pointing a suite at a dev copy of a schema while you author against it.
Environments are **local only**. They are applied by the CLI as it loads a suite; the workspace does not apply them. A suite uploaded with `upload-config` and run with `run-remote`, or promoted, sees no overrides. Use them for local authoring, not to model dev and prod in the platform — that is what [Development and Production](/reconciliation/workspace-suites) are for.
## Next
Reading a segment tree, and following a finding to the rows.
Save the suite, run it on our backend, put it on a schedule.
Every command and flag, generated from the binary.
The same loop, written as an operating procedure for an agent.
# Time windows and cutoffs
Source: https://docs.synq.io/reconciliation/time-windows-and-cutoffs
Comparing two live systems without inventing differences that are not there
Most "the data is wrong" findings are not data problems. They are comparison-window problems: two systems read at slightly different moments, or a target that has not finished catching up. This page is how you rule that out.
Reach for these in order:
| Symptom | Use |
| ------------------------------------------------------------------ | ----------------------------------------- |
| The target trails the source, and its tail looks like missing rows | [`cutoff`](#cutoffs-for-a-lagging-target) |
| Only a recent window is worth comparing | [`window`](#windows) |
| A query needs a date or an id boundary | [Template variables](#template-variables) |
| You want to compare against a point in time | [`as_of`](#time-travel) |
## Template variables
A variable is resolved **once per run** and interpolated into both sides, so the two queries are guaranteed to use the same boundary.
```yaml theme={null}
variables:
start_date: "{{ today - 7d }}"
end_date: "{{ today }}"
reconciliations:
orders-recent:
source:
connection: gateway
query: |
SELECT order_id, customer_id, total_amount
FROM public.orders
WHERE order_date >= '{{ start_date }}' AND order_date < '{{ end_date }}'
target:
connection: warehouse
query: |
SELECT order_id, customer_id, total_amount
FROM ANALYTICS.PUBLIC.ORDERS
WHERE order_date >= '{{ start_date }}' AND order_date < '{{ end_date }}'
key_columns: [order_id]
mode: row_checksum
```
Variables also interpolate into a table dataset's `where:`, so you do not have to switch to raw SQL to use them.
### What you can write inside `{{ }}`
| Expression | Resolves to | Example output |
| ----------------------------- | ------------------------------------------------------------------- | ---------------------- |
| `{{ today }}` | Today's date | `2026-03-14` |
| `{{ yesterday }}` | Yesterday's date | `2026-03-13` |
| `{{ now }}` | The run's reference instant, RFC 3339 | `2026-03-14T09:21:44Z` |
| `{{ now(2006-01-02 15:04) }}` | `now`, in a [Go time layout](https://pkg.go.dev/time#pkg-constants) | `2026-03-14 09:21` |
| `{{ today - 7d }}` | A date base, minus an offset | `2026-03-07` |
| `{{ now - 2h }}` | A timestamp base, minus an offset | `2026-03-14T07:21:44Z` |
| `{{ my_variable }}` | Another variable you defined | — |
Offsets subtract from `now`, `today` or `yesterday`, in units of `d` (days), `h` (hours), `m` (minutes) or `w` (weeks). Only subtraction is supported — a comparison window that reaches into the future is not a thing you want.
Override any variable for a single run:
```bash theme={null}
synq-recon run-check suite.yaml --var start_date=2026-01-01 --var end_date=2026-02-01
```
The resolved values are recorded in the audit log, which is what makes a [re-check](/reconciliation/investigating-results#re-check-and-drill-deeper) compare the same window as the original run.
**`NOW()`, `CURRENT_DATE` and `GETDATE()` in a query are a bug, not a shortcut.** Each side evaluates them at its own moment, on its own clock. Any row written between the two evaluations appears on one side and not the other, and you get a mismatch that has nothing to do with your data — reliably, on every run, for a different row each time.
`check-config` warns when it finds one. Set `strict_time_references: true` at suite level to make it an error, which is worth doing in CI.
## Windows
A `window:` restricts a reconciliation to a recent period without you writing the predicate:
```yaml theme={null}
reconciliations:
events-recent:
source:
connection: app
table: public.events
target:
connection: warehouse
table: ANALYTICS.PUBLIC.EVENTS
key_columns: [event_id]
mode: row_checksum
window:
column: created_at
lookback: "14d"
strategy: sliding
```
* `lookback` is required: `"14d"`, `"2h"`, `"1w"`.
* `strategy: sliding` (the default) measures back from the run's reference time, so each run compares a moving fortnight. `fixed` anchors the window to a period boundary, so consecutive runs inside the same period compare exactly the same rows.
Use a window when history is immutable and re-comparing it every hour is a waste of warehouse spend. Use `fixed` when you want two runs to be comparable to each other, not just each correct in isolation.
## Cutoffs for a lagging target
This is the important one, and the one people reach for last when they should reach for it first.
If the target trails the source — a CDC stream, a batch load, a read replica — then rows written recently are on the source and not yet on the target. They are not missing. They are in flight. A reconciliation with no cutoff reports them as a difference, every time, and the difference moves as the lag moves.
A `cutoff:` **derives a watermark from the data itself**, then filters both sides to at-or-below it. Rows in flight are excluded from the comparison rather than reported as errors.
```yaml theme={null}
reconciliations:
orders-replicated:
source:
connection: primary
table: app_orders
columns: [order_id, amount, updated_at]
target:
connection: replica
table: replica_orders
columns: [order_id, amount, updated_at]
key_columns: [order_id]
mode: row_checksum
cutoff:
column: updated_at
truncate: HOUR
offset: "-5m"
```
The difference it makes, on the same pair of tables — a primary with 500 orders and a replica that has caught up to 470 of them:
```
Reconciliation: Without a cutoff (orders-no-cutoff)
Source Target
Row Count 500 470
Status: MISMATCH
- Source has 30 more rows than target
---
Reconciliation: With a cutoff on the replication watermark (orders-with-cutoff)
Source Target
Row Count 415 415
Status: MATCH
```
Same data, same query, two different conclusions. The second one is the true one: the replica is not missing anything, it is simply thirty rows behind, and the comparison now says so by agreeing about the 415 rows both sides have definitely seen.
Notice the cutoff is stricter than the lag — 415 rows, not 470. `truncate: HOUR` snaps the watermark down to an hour boundary and `offset: "-5m"` pulls it back further. Both are deliberate margin, because a pipeline that writes slightly out of order can land a row *below* a watermark it has already passed.
### Three levels of control
One column, both sides:
```yaml theme={null}
cutoff:
column: created_at
```
Each side's watermark is `MAX(created_at)` over its own dataset; the lower of the two becomes the cutoff.
Common when the target records when it was loaded, not when the event happened:
```yaml theme={null}
cutoff:
source_column: created_at
target_column: synced_at
```
```yaml theme={null}
cutoff:
source:
column: created_at
aggregate: MAX # MAX (default) or MIN
target:
column: synced_at
query: | # derive it yourself instead
SELECT MAX(synced_at) AS watermark FROM warehouse.orders
combine: min # min (default), max, source, target
truncate: HOUR # HOUR, DAY, WEEK, MONTH, QUARTER, YEAR
offset: "-30m" # applied after truncation
apply: # filter a different column than the derived one
source: { column: created_at, operator: "<=" }
target: { column: created_at, operator: "<=" }
```
A custom `query:` must return a single row with a column named `watermark`.
### How a cutoff resolves
`MAX` (or `MIN`) of the named column, or the result of your custom query.
`combine: min` by default.
Optional. Skipped when the watermark is not a timestamp.
Optional, after truncation. Negative buys margin.
Against the derived column, or whatever `apply:` names.
Every one of those intermediate values — both watermarks, the combined cutoff, and the final `WHERE` clause per side — is recorded in the audit log. A run's comparison window is always recoverable after the fact.
**`combine: min` is the default and almost always the right answer.** The lower of the two watermarks is the point *both* sides have certainly reached.
`max`, `source` and `target` each keep rows that one side has and the other may not — which is a mismatch you created. They exist for cases where you know the asymmetry is real; if you are not sure, you want `min`.
The watermark does not have to be a timestamp. A monotonically increasing sequence or id works exactly the same way, in which case `truncate` and `offset` are ignored rather than applied.
## Time travel
`as_of` compares against a point-in-time snapshot rather than the current state, on platforms that support it — Snowflake, BigQuery and Databricks:
```yaml theme={null}
source:
connection: warehouse
table: ANALYTICS.PUBLIC.ORDERS
as_of: "2026-02-01 00:00:00"
```
This is the tool for "was it right yesterday, before the deploy?" and for pinning both sides to the same instant when one of them is being written to continuously.
A [re-check](/reconciliation/investigating-results#re-check-and-drill-deeper) replays the original run's queries, which for an `as_of` reconciliation means it re-compares the same frozen snapshot and can therefore never turn green. Pass `--reresolve` to re-derive the queries against current data.
## Choosing between them
The two systems are the same data at different times. You want to compare what both sides have, and ignore what is still on its way.
History is settled and you only care about recent data — usually for cost, not correctness.
You need an explicit, reproducible boundary in your own SQL, identical on both sides.
You need a specific historical state, not "now".
They compose. A cutoff on top of a window is a normal thing to write: compare the last fortnight, up to the point the target has caught up to.
## Next
Overriding variables per run, and reading what a run resolved them to.
Confirming a difference is real, and re-checking after a fix.
# Workspace suites
Source: https://docs.synq.io/reconciliation/workspace-suites
From a local file to a scheduled production deployment — Development, Production, and what each step preserves
A suite that only runs on your machine is a useful tool. A suite in your workspace is a monitored one: versioned, runnable by anyone with access, schedulable, and wired into assets, checks, issues and alerts.
Two stages, in the app under **Health → Reconciliations**:
| Stage | What lives there | How a run starts |
| --------------- | ------------------------------------------------------------------- | ---------------------------------------- |
| **Development** | Stored, versioned suites. The shared draft. | On demand only |
| **Production** | Deployments — immutable snapshots with a schedule and run settings. | Schedule, API trigger, or the Run button |
## Save to Development
```bash theme={null}
synq-recon auth whoami # confirm the workspace first
synq-recon upload-config suite.yaml --change-summary "Add inventory reconciliation"
```
Prints the suite id. Requires `SCOPE_RECON_EDIT`.
**Development suites → New suite** opens a four-step wizard: **Data Sources**, **Comparison**, **Suite Info**, **Review**. It searches your catalog, so you can pick a table you have already catalogued rather than typing warehouse coordinates.
**Upload Suite Config** takes a whole suite as pasted or uploaded YAML — which is how you get anything the wizard does not cover. [What the wizard covers](/reconciliation/authoring-suites#what-the-wizard-covers-and-what-needs-yaml) is the map.
Every save creates a new **version**. The change summary is what makes the version history readable six months later.
```bash theme={null}
synq-recon suite list
synq-recon suite versions
synq-recon suite yaml > suite.yaml # read it back as editable YAML
synq-recon suite delete # soft delete
```
`suite yaml` is the round-trip that makes a stored suite editable again — including one someone else created in the wizard. Fetch it, edit the file, `upload-config` it back. This is also the recipe for copying a suite between workspaces.
## Bind connections to integrations
A backend run does not see the credentials in your YAML. It uses **integrations** — the warehouse credentials your workspace already manages.
```bash theme={null}
synq-recon connections remote list # what is available, with ids
synq-recon connections remote list --recon-deployable # only the ones recon can use
```
By default each connection name binds to the integration whose id matches it. Map them explicitly when the names differ:
```bash theme={null}
synq-recon run-remote --map gateway= --map warehouse=
```
In the app this is the **Bind suite connections to integrations** dialog.
`N connection(s) could not be bound to an integration` means a suite connection has no matching integration, or the integration is not enabled for reconciliation. Check the names with `connections remote list --recon-deployable`, or bind explicitly with `--map`.
Read [connection vs integration](/reconciliation/concepts#connection-vs-integration) once if that distinction is new — the same YAML key means two different things in the two stages, and it is the most common source of confusion.
## Run it on the backend
```bash theme={null}
synq-recon run-remote --drill=false --wait
```
The run is asynchronous. `--wait` blocks until it finishes and sets a meaningful exit code; without it, poll with `synq-recon audit-logs get `.
`--invocation-id ` makes submission idempotent — re-submitting with the same id will not start a duplicate run, which is what you want from a retrying pipeline.
**Development → Run** on the suite. The run options dialog carries the same drill and timeout settings.
**Pass `--drill=false` explicitly if you do not want a drill.** Omitting the flag does not mean "off".
Unlike `promote`, where an omitted flag preserves the stored setting, an ad-hoc run has no deployment to inherit from — so an omitted `--drill` falls through to each reconciliation's own `bisection.enabled` in the YAML, which defaults to on. On a suite with genuinely many differences that is the difference between a two-minute run and a fifteen-minute one with nothing usable at the end.
## Promote to production
Promoting creates a **deployment**: an immutable snapshot of the suite plus its schedule, bindings, run settings and annotations.
```bash theme={null}
synq-recon promote \
--schedule "0 */4 * * *" \
--timezone UTC \
--triggerable-by-api \
--drill=false \
--execution-timeout 30m \
--annotation team=data-platform \
--change-summary "Every four hours, no drill"
```
**Promote to production** on the suite card. The dialog covers the schedule and the run settings, and shows a diff of what is about to change against what production is running today.
Once promoted, each reconciliation in the deployment becomes a platform asset that produces a check on every run — so it appears in search and lineage, participates in [check categorisation](/analytics/check-categories), and opens [issues](/incidents/incident-overview) that route through your existing [alerts](/alerts/alert-overview) and [ownership](/ownership/ownership-overview).
### Schedules
Two forms, mutually exclusive:
```bash theme={null}
--schedule "0 */4 * * *" # cron
--ical "FREQ=MONTHLY;BYDAY=TH;BYSETPOS=-1" # RFC 5545 recurrence rule
```
Both take `--timezone` (for example `UTC`, `Europe/Warsaw`); `--ical` additionally accepts `--dtstart` as an anchor. Use iCal for the schedules cron cannot express — last Thursday of the month, the second Tuesday, business-day patterns.
### Two different timeouts
`--timeout` and `--execution-timeout` are unrelated, and mixing them up is easy:
* **`--timeout`** is a **per-query** budget for locally executed commands. Default `5m`.
* **`--execution-timeout`** is the **whole-run** wall-clock budget for a backend run, set on a deployment or per trigger. The server clamps it to its supported range.
## Editing a deployment
Deployment edits **preserve what you omit**. `deployment update` always behaves this way, and so does a re-promote — so refreshing a suite snapshot never silently unschedules the deployment or turns off API triggers.
```bash theme={null}
synq-recon deployment update --execution-timeout 45m # changes only that
synq-recon deployment update --clear # remove the schedule
synq-recon promote --clear-schedule # same, while re-promoting
```
Removing a schedule is therefore always explicit.
**A *fresh* promote applies defaults, and one of them may surprise you.** With no existing deployment to preserve from, a promote defaults to: no schedule, not triggerable by API, the server-default execution timeout — and **drill-down on**.
If you want a scheduled production run that never drills, pass `--drill=false` on the first promote. Do not rely on omission.
**A deployment is a snapshot, not a pointer.** Editing the suite in Development changes nothing in production until you re-promote. The app says so on the suite card — *"Dev has unpromoted changes"* versus *"Up to date with prod"* — and it is worth checking that line before concluding that a fix did not work.
### Keep the deployment id stable
A deployment's id is part of every reconciliation's asset path. Rebuilding a deployment from scratch under a new id re-homes its checks and drops their history.
Re-promoting the same suite reuses its id automatically, so this is only a concern if you are rebuilding deliberately — in which case pin it:
```bash theme={null}
synq-recon promote --deployment-id
```
## Pause, resume, unpromote
```bash theme={null}
synq-recon deployment pause --until 2026-04-01T00:00:00Z
synq-recon deployment pause # indefinitely
synq-recon deployment resume
synq-recon unpromote --reason "Migration complete"
```
Pause is for a planned maintenance window: the deployment stays configured and stops running. Unpromote deactivates it entirely; its history is kept, and re-promoting brings it back under the same id.
`deployment is not active; re-promote to modify` means the deployment was unpromoted. Re-promote before changing or tearing it down.
## Inspecting what ran
```bash theme={null}
synq-recon runs list --status in_progress
synq-recon runs list --trigger scheduled --suite --limit 20
synq-recon runs cancel
synq-recon audit-logs list --status mismatched
synq-recon audit-logs get -o json
synq-recon deployment get -o yaml # schedule, bindings, run settings
synq-recon deployment history # every promote, pause, edit
```
A run's `--trigger` says how it started, which is often the first thing you want to know:
| Trigger | Means |
| ----------- | ------------------------------------------------------------------------------------------------- |
| `adhoc` | Submitted against a Development suite (`run-remote`, or **Run** in the app). |
| `scheduled` | A schedule fired. |
| `api` | An explicit trigger — the Run button on a promoted suite, or an external caller such as a CI job. |
`deployment history` is append-only and records every promote, unpromote, schedule change, binding change, annotation edit, pause and resume. When production behaviour changed and nobody remembers why, it is the first place to look.
## Copy production back to Development
To iterate on what production is actually running, rather than on what Development happens to contain:
```bash theme={null}
synq-recon suite yaml > suite.yaml
# edit
synq-recon upload-config suite.yaml --change-summary "Iterating on the prod snapshot"
```
**Copy production snapshot to development** on the production deployment card.
## Permissions
| Action | Scope |
| ----------------------------------------------------------------------- | --------------------- |
| View suites, deployments, runs, audit logs | `SCOPE_RECON_READ` |
| `upload-config`, suite edits and deletes, ad-hoc runs, cancelling a run | `SCOPE_RECON_EDIT` |
| Promote, unpromote, trigger, pause, resume, deployment edits | `SCOPE_RECON_PROMOTE` |
| Report a locally executed run's results | `SCOPE_RECON_EDIT` |
The app hides controls whose call would be refused, so a missing scope shows up as a missing button rather than an error. [CI/CD and automation](/reconciliation/cicd-and-automation#scopes-and-credentials) maps these to roles and to the credentials an unattended caller uses.
## Next
Reading a run, and following a finding to the rows.
`trigger --wait` as a release gate, exit codes and credentials.
# Agent workflow
Source: https://docs.synq.io/scout/agent-workflow
The operating guide for a coding agent driving Scout
This page is the published copy of the operating guide that ships with the tool
as `AGENTS.md` — in the release archive and in
[getsynq/synq-scout](https://github.com/getsynq/synq-scout). It is deliberately
denser than the rest of this section. See [MCP](/scout/mcp) for the hosted
server and its tool tables, and the [CLI reference](/scout/cli) for every flag.
This is the operating guide for a coding agent using `synq-scout`: what it can do,
how to reach it, which command to pick, and the mistakes that waste a session. It
is written to be acted on top-down.
**Scout is an agent over your data estate.** It answers questions about your
warehouse and your Coalesce Quality workspace — what an asset is, what changed,
what broke and why, what to test — and it can act: set an issue's status, comment,
open an incident, author monitors and tests. Every capability is a **tool**, and
the same tool set backs all three ways of running it.
Scout only ever connects outward, so it can run inside your network with nothing
exposed.
## 1. Pick the right surface
Three ways in. The first is almost always the right answer.
**1. The hosted MCP server — no install.** Scout's tools are served over MCP at a
URL, so an MCP client (Claude Code, Cursor, Claude Desktop) can use them with
nothing running on your side. If your goal is "let my agent query the estate",
stop here — you do not need this binary at all.
| Region | URL |
| ------ | ---------------------------- |
| EU | `https://mcp.synq.io/mcp` |
| US | `https://mcp.us.synq.io/mcp` |
| AU | `https://mcp.au.synq.io/mcp` |
**2. `synq-scout mcp` — the same tools, served locally.** Use this when the data
must not leave your network, or when you need warehouse tools that query your
databases directly with credentials you hold. It speaks MCP over stdio, so point
your client at the command rather than a URL:
```json theme={null}
{
"mcpServers": {
"coalesce-quality": {
"command": "synq-scout",
"args": ["mcp"]
}
}
}
```
**3. `synq-scout tools` — one tool, one command, no client.** The fastest way to
answer a single question, and the only surface where you can see a tool's exact
schema. Start here when exploring what Scout can do.
`synq-scout agent` is the fourth mode: long-lived, picking up triage work from your
workspace on its own. It is a deployment, not something you drive — see the
installation notes that ship beside this guide.
***
## 2. Authenticate, and confirm what you are pointed at
Scout takes the first credential it finds:
1. `QUALITY_CLIENT_ID` + `QUALITY_CLIENT_SECRET` — for servers and containers.
2. `QUALITY_TOKEN` — an `st-…` API token.
3. A browser login, cached under `~/.synq/oauth/`.
```bash theme={null}
synq-scout auth login # browser flow
synq-scout auth whoami # who you are, which workspace, which permissions
```
**Read `auth whoami` before anything that writes.** It is the only thing that tells
you which workspace a mutation will land in. `auth status` shows every stored
credential across regions, `auth token` prints a fresh access token for scripting,
`auth logout` removes one.
If your workspace is not in the EU, pass `--region us` (or `au`), or set
`QUALITY_REGION`. It works on every command, not just `auth`, and a successful
login is remembered — so later commands need no flag.
Then confirm the whole setup at once:
```bash theme={null}
synq-scout health
```
This checks the API, the model endpoint and every configured warehouse
connection. Run it before blaming a tool for failing.
***
## 3. The loop
**1. Find the tool.** Do not guess a tool name; the list is derived from the build
you have.
```bash theme={null}
synq-scout tools list
```
**2. Read its schema before calling it.**
```bash theme={null}
synq-scout tools describe get_entity_details
```
`describe` prints the arguments, which are required, and the enum values a field
accepts. This is cheaper than a failed call and far cheaper than a wrong one.
**3. Call it.**
```bash theme={null}
synq-scout tools search_entities --query "orders"
synq-scout tools get_entity_details --entity-id ""
```
Flags are derived from the schema: `issueId` becomes `--issue-id`, a string array
becomes a repeatable flag, and anything nested takes JSON. For a deeply nested
argument, pass the whole payload instead:
```bash theme={null}
synq-scout tools save_domain --json '{"name":"Finance","definition":{...}}'
```
**4. Read the response, then follow where it points.** Tool responses carry a
`tool_usage_guidance` field when there is an obvious next step — it names the
specific follow-up tool and the argument to carry over. Follow it rather than
guessing, and rather than re-running the same list with tweaked filters.
***
## 4. Never do these
* **Do not call a tool without `describe`-ing it first.** Argument names are
derived from a schema, not from convention, and a plausible guess usually fails.
* **Do not self-confirm a gated write.** Tools that would reset a check's baseline,
overwrite something the UI owns, or delete a resource return
`requires_user_confirmation` with a list of ids, and apply nothing. Those ids are
a *human* authorization. Surface the impact, get a person to agree, then re-send
with the confirmation. Passing the ids straight back because you saw them in the
response defeats the entire mechanism.
* **Do not treat an empty result as "no data".** Scout returns an explicit "no
results for \" rather than an empty list. If you got that message, the
filter is the problem, not the estate.
* **Do not parse an id out of a handle.** Some responses intern a repeated
sub-record into a table with short handles. Handles are local to that one
response — never pass one back as an argument, and never assume it means anything
next time.
* **Do not assume a write happened under `--dry-run`.** See below.
***
## 5. Dry run: the default differs per surface
`synq-scout tools` defaults to **`--dry-run=true`**. Read calls pass through
normally; a write call returns its optimistic response but **nothing reaches the
backend**. That makes exploring safe, and it makes "I ran the tool and nothing
changed" the expected outcome rather than a bug.
```bash theme={null}
synq-scout tools set_issue_status --issue-id --status FIXED # dropped
synq-scout tools set_issue_status --issue-id