# 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 title 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. title ### 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](/support/support) 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@coalesce.io](mailto:support@coalesce.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://auth.eu.coalescesoftware.io/login/callback` | | **US** | `https://app.us.synq.io` | `https://auth.us.coalescesoftware.io/login/callback` | | **AU** | `https://app.au.synq.io` | `https://auth.apac.coalescesoftware.io/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@coalesce.io](mailto:support@coalesce.io) to connect an on-premises directory. If you’re not sure whether your provider is supported, reach out to [support@coalesce.io](mailto:support@coalesce.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. manage-team upload-app add-synq * 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. add-integration choose-ms-teams get-link create-integration # 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. add-owner edit-owner * 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. add-teams add-channel * 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. # Checking that alerts arrive Every alert Coalesce Quality sends to Opsgenie is recorded under **Settings > Integrations > your Opsgenie integration > Deliveries**: the request made to the Opsgenie API, the response it returned, and — when nothing was sent — the reason. Use **Send test event** to open a real test alert and see the outcome, and **Redeliver** to send an earlier event again once you have changed something. An invalid or revoked `API Key` shows up there as a rejected request rather than as silence, which is the usual reason alerts stop arriving. See [Debugging Deliveries](/api-reference/webhook-deliveries). Opsgenie carries issue and incident lifecycle events. A delivery skipped as *Event type unsupported by integration* or *No action for lifecycle state* is an event Opsgenie has no equivalent for, not a fault. # 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. # Checking that alerts arrive Every alert Coalesce Quality sends to PagerDuty is recorded under **Settings > Integrations > your PagerDuty integration > Deliveries**: the request made to the PagerDuty Events API, the response it returned, and — when nothing was sent — the reason. Use **Send test event** to send a test alert and see the outcome, and **Redeliver** to send an earlier event again once you have changed something. A wrong or rotated Integration Key shows up there as a rejected request rather than as silence, which is the usual reason alerts stop arriving. Each delivery also carries the PagerDuty `dedup_key`, so an incident on the PagerDuty side can be traced back to the delivery that opened it. See [Debugging Deliveries](/api-reference/webhook-deliveries). # 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. ![](https://pdpartner.s3.amazonaws.com/ig-template-incoming-event-source-key.png) ### 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. ![](https://pdpartner.s3.amazonaws.com/ig-template-copy-integration-key.png) ## 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. title ### 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` title # 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, and volume 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](/monitor-types/schema-monitor)**. 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* title ### 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* title 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. ## Managing routing programmatically * **Public API** — `synq.alerts.services.v1.AlertsService` covers alerts and their destinations. Reading needs a token with `SCOPE_ALERTS_READ`, writing needs `SCOPE_ALERTS_EDIT`. See the [API reference](/api-reference/api) and [API scopes](/api-reference/scopes). * **MCP** — routing that goes through an owner is managed with the [owner tools](/scout/mcp#owners-and-ownership): an owner's channels and the alert configuration on each of its ownerships are set in the same call that creates it. This needs the Governance permission. # 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. title 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. title * **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* title ### 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 title ## Data quality dimensions All metrics are broken down into automated groupings. See [How metrics are calculated](/analytics/how-metrics-are-calculated) for which checks fall into each dimension and how every metric is computed. | 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). | | Consistency | Ensures related data agrees across tables (e.g., relationships test between a foreign key and its parent table, reconciliations between a source and its replica). | | 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). | | Uncategorized | 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 `quality.check_category` / `quality.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. `quality.check_category` and `quality.governance_category` are the documented annotation names. The original `synq.check_category` and `synq.governance_category` names remain supported permanently, so existing configurations do not need to change. Both namespaces also accept an underscore in place of the dot (for example, `quality_check_category`). A producer may prefix the annotation name; matching by suffix means a name such as `dbt.tag.quality.check_category` resolves the same way. Use the `quality.*` names in new configurations. ## 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 in the same scope 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 take precedence over the **global**, Coalesce Quality-provided rules whatever their priority. A global rule applies only when no workspace rule matches the check, so overriding a global rule takes a workspace rule that matches, not a higher priority number. 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. ## Managing categorisation programmatically The **Check categorisation** screens are one client of the categorisation API. The same rules and per-check overrides are available over the public API and to an AI assistant over MCP, and all three drive the same services — so a rule authored by an assistant is the same rule the page shows, subject to the same precedence and the same recategorisation sweep. * **Public API** — `synq.entities.checks.v2.ChecksCategorisationRulesService` covers the rules (list them, preview a candidate's reach, upsert, delete, and read the recategorisation status); `synq.entities.checks.v2.ChecksCategoriesService` covers per-check overrides, the workspace's category vocabulary, and the attribute values a predicate can be built from. Reading needs a token with `SCOPE_POLICIES_READ`, writing needs `SCOPE_POLICIES_EDIT`. See the [API reference](/api-reference/api) and [API scopes](/api-reference/scopes). * **MCP** — the [check categorisation tools](/scout/mcp#check-categorisation) let an AI assistant review what is uncategorised, draft a rule, preview its impact, and save it once you approve. Reading is covered by read-only consent; saving or deleting a rule and setting a per-check override need the Governance permission, and every write is confirmation-gated. # How metrics are calculated Source: https://docs.synq.io/analytics/how-metrics-are-calculated How Coalesce Quality calculates the Analytics metrics, the data quality dimensions, and the data product quality score Every number in [Analytics](/analytics/analytics-overview) and in a data product's quality score is built from the same two counts: * **Tests**: the distinct checks that ran at least once in a period. * **Tests with issues**: the distinct checks that had an open issue at any point in that period. This page explains what goes into those two counts, how checks are grouped into data quality dimensions, and how each metric is derived from them. ## What counts as a test A test is any check that produces runs in Coalesce Quality: * dbt tests, and dbt model, source, snapshot, seed and metric runs * SQLMesh audits and model runs * Coalesce Transform node runs and node tests * Coalesce Quality monitors, including segmented monitors * SQL tests and reconciliations A test is counted in a period if it ran **at least once** in that period, whatever the result. A test that ran 50 times in a week counts as one test for that week. ## When a test has an issue A test has an issue in a period when one of its issues was open at any point during that period. An issue is open from the run that raised it until the run that resolved it, so it is counted in every period it spans: * an issue that started in the period * an issue that was resolved in the period * an issue that started earlier and is still open Runs with a **warning**, **error** or **critical** status raise issues. A warning counts as an issue, so a test whose severity is set to warn still lowers your scores while it is failing. Issues whose status is set to **Expected** or **No action needed** are not counted. A test is counted once per period no matter how many issues it had. ## Data quality dimensions Each test is assigned to one dimension based on its type. Tests whose type is not listed fall into **Uncategorized**. | Dimension | Tests included | | - | - | | Accuracy | `accepted_values`, `accepted_range`, `dbt_expectations` column-value and column-pair range tests, SQLMesh `accepted_values`, `accepted_range`, `at_least_one` and `forall` audits, SQL tests of type `accuracy` | | Completeness | `not_null`, `not_empty_string`, volume and custom volume monitors, field stats monitors, SQLMesh `not_null`, `not_null_proportion`, `not_empty_string` and string-length audits, Coalesce `hasNull`, SQL tests of type `completeness` | | Consistency | `relationships`, `dbt_utils.equality`, `expect_column_pair_values_to_be_equal`, reconciliations, SQL tests of type `consistency` | | Uniqueness | `unique`, `unique_combination_of_columns`, `expect_compound_columns_to_be_unique`, SQLMesh `unique_combination_of_columns` and `unique_values` audits, Coalesce `isDistinct`, SQL tests of type `uniqueness` | | Timeliness | Freshness, custom freshness and table stats monitors, `dbt_utils.recency`, `expect_row_values_to_have_recent_data`, SQL tests of type `timeliness`, **and model, source, snapshot, seed and node runs** from dbt, SQLMesh and Coalesce Transform | | Validity | `dbt_utils.expression_is_true`, custom numeric monitors, segmented monitors, SQLMesh regex-pattern and `not_accepted_values` audits, SQL tests of type `validity` | | Uncategorized | Every other test, including custom dbt tests and any test type not listed above | Model, source and node runs count under **Timeliness**. A dbt model that fails to build counts as a Timeliness test with an issue. ## Analytics metrics Analytics splits the selected date range into weekly or monthly periods. Each column in a table is one period, and each row is one dimension. Every metric is calculated per period and per dimension. Values from different periods are never added together. | Metric | How it is calculated | | - | - | | **Number of tests** | Tests that ran at least once in the period. | | **Number of tests with issues** | Tests that had an open issue at any point in the period. | | **% of tests without issues** | (Number of tests − Number of tests with issues) ÷ Number of tests × 100, to one decimal place. | | **New and resolved issues** | Shown as `+new / resolved`. *New* is the number of tests whose issue started in the period. *Resolved* is the number of tests whose issue was resolved in the period. | | **MTTR (hr)** | Total time from the start to the resolution of every issue resolved in the period, divided by the number of issues resolved, in hours to one decimal place. Shows **—** when no issue was resolved in the period. | | **# Incidents** | Tests that had an open issue linked to an [incident](/incidents/incident-overview) at any point in the period. This counts affected tests, not incidents, so one incident covering three failing tests counts as 3. | A period in which no test in a dimension ran shows **—** for that dimension. The **Total** row adds up the counts of every dimension first, then calculates the percentage from those sums. It is not an average of the dimension percentages, so a dimension with many tests moves the total more than a dimension with few. ### Choosing what is counted By default Analytics counts every test in the workspace. Filters narrow it to tests on matching assets. A test is included if **any** asset it checks matches the filter, so a `relationships` test between two tables counts when either table matches. The **Product** filter includes the data product's own assets. Turn on **Include upstream assets** to also count every test on assets upstream of the product. ## Data product quality score The data product **Overview** shows a quality score and test coverage, calculated from the same counts as Analytics over the **last 4 weeks**, including the current week. The score covers tests on the data product's assets **and on every asset upstream of them**, so a failing test on a source table lowers the score of every product built on it. **Quality score** ```text theme={null} average tests per week − average tests with issues per week ─────────────────────────────────────────────────────────── × 100 average tests per week ``` The averages are taken over the 4 weeks before dividing, and the result is rounded to a whole percent. The score is **—** when no test ran in those 4 weeks. The score is shown in: * **Green** at 100% * **Amber** from 90% to 99% * **Red** below 90% **Test coverage** is the average number of tests that ran per week over the 4 weeks, rounded to a whole number. It is a count of tests, not a percentage of assets. **Change indicators** compare the most recent week with the week before it. The score change uses each week's own percentage. The coverage change is the difference in the number of tests that ran. **Breakdown by dimension.** When tests from more than one dimension ran, click the score to see the same calculation for each dimension that had tests in the last 4 weeks. # API Source: https://docs.synq.io/api-reference/api ## Services ### 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. ### 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. #### DeleteComment DeleteComment ([DeleteCommentRequest](#deletecommentrequest)) [DeleteCommentResponse](#deletecommentresponse) Delete a comment on an issue. Only the actor who posted the comment may delete it. Deleting an already-deleted comment succeeds. ### CommitsService (synq.git.commits.v1.CommitsService) #### GetDiffByChangeId GetDiffByChangeId ([GetDiffByChangeIdRequest](#getdiffbychangeidrequest)) [GetDiffByChangeIdResponse](#getdiffbychangeidresponse) #### GetDiffByCommit GetDiffByCommit ([GetDiffByCommitRequest](#getdiffbycommitrequest)) [GetDiffByCommitResponse](#getdiffbycommitresponse) ### RecommendationsService (synq.recommendations.v1.RecommendationsService) RecommendationsService lists the changes Coalesce Quality recommends you make, and records what you decided about them. See `Recommendation` for what a recommendation is. Recommendations are created and removed by Coalesce Quality itself: one appears when something only you can change is found, and disappears once it no longer holds. What you can do is decide whether a recommendation stays in front of you: * Dismiss hides it until something new is found about it: an object it did not list before, or a different remediation. * Ignore hides it for good. * Restore undoes either. Decisions are kept by recommendation id, so they keep applying when a recommendation disappears and comes back. A recommendation about an integration is also governed by that integration's permissions: reading it needs a credential that can read integrations, and deciding about it one that can edit them. One that cannot does not see it listed. Related services: `synq.integrations.v1.IntegrationsService` manages the integrations recommendations can be about. #### ListRecommendations ListRecommendations ([ListRecommendationsRequest](#listrecommendationsrequest)) [ListRecommendationsResponse](#listrecommendationsresponse) List the ids of the workspace's recommendations, optionally limited by target and state. Fetch the recommendations themselves with `BatchGetRecommendations`. Ids are returned in a stable order, so paging is consistent while recommendations are added or removed. Returns INVALID\_ARGUMENT for a malformed cursor. #### BatchGetRecommendations BatchGetRecommendations ([BatchGetRecommendationsRequest](#batchgetrecommendationsrequest)) [BatchGetRecommendationsResponse](#batchgetrecommendationsresponse) Fetch recommendations by id. Ids that are unknown, belong to another workspace, no longer exist because the condition cleared, or concern an integration the credential cannot read are omitted from the response rather than erroring. #### DismissRecommendation DismissRecommendation ([DismissRecommendationRequest](#dismissrecommendationrequest)) [DismissRecommendationResponse](#dismissrecommendationresponse) Dismiss a recommendation until something new is found about it. Replaces an ignore. Dismissing again records the recommendation as it reads now, so it stays hidden until something newer than that is found. Returns NOT\_FOUND when the recommendation does not exist in the workspace, and PERMISSION\_DENIED when it concerns an integration the credential cannot edit. #### IgnoreRecommendation IgnoreRecommendation ([IgnoreRecommendationRequest](#ignorerecommendationrequest)) [IgnoreRecommendationResponse](#ignorerecommendationresponse) Ignore a recommendation for good, whatever is found about it later. Replaces a dismissal. Ignoring an ignored recommendation succeeds without change. Returns NOT\_FOUND when the recommendation does not exist in the workspace, and PERMISSION\_DENIED when it concerns an integration the credential cannot edit. #### RestoreRecommendation RestoreRecommendation ([RestoreRecommendationRequest](#restorerecommendationrequest)) [RestoreRecommendationResponse](#restorerecommendationresponse) Remove the dismissal or ignore standing against a recommendation, so it is open again. Restoring a recommendation nobody decided about succeeds without change. Returns NOT\_FOUND when the recommendation does not exist in the workspace, and PERMISSION\_DENIED when it concerns an integration the credential cannot edit. ### 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) ### MonitorInfoService (synq.monitors.info.v1.MonitorInfoService) #### MonitorInfo MonitorInfo ([MonitorInfoRequest](#monitorinforequest)) [MonitorInfoResponse](#monitorinforesponse) ### 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) ### MonitorSegmentsService (synq.monitors.segments.v1.MonitorSegmentsService) Reads and names the segments of a segmented custom monitor. A monitor configured with a segmentation expression splits the data it monitors into one time series per distinct value of that expression, and each of those is a segment. The label is what every downstream surface shows for a segment: the name of the check it produces, the search result, the alert. A segment with no label falls back to its raw value, so a monitor segmented on something encoded (an id, a code, a hashed bucket) reads as that raw value everywhere until the segment is named. #### ListMonitorSegments ListMonitorSegments ([ListMonitorSegmentsRequest](#listmonitorsegmentsrequest)) [ListMonitorSegmentsResponse](#listmonitorsegmentsresponse) Lists the segments a monitor has ingested so far, with their raw value and current label. A segment appears only once data has been observed for it, so a monitor that has not run yet lists none. #### BatchUpdateMonitorSegmentLabels BatchUpdateMonitorSegmentLabels ([BatchUpdateMonitorSegmentLabelsRequest](#batchupdatemonitorsegmentlabelsrequest)) [BatchUpdateMonitorSegmentLabelsResponse](#batchupdatemonitorsegmentlabelsresponse) Sets or clears the label of one or more segments. Segments are addressed by the id ListMonitorSegments returns. A segment id encodes a sanitised form of the segment value, so it cannot be constructed from that value: read the ids first, then write against them. ### HistoryService (synq.monitors.history.v1.HistoryService) #### History History ([HistoryRequest](#historyrequest)) [HistoryResponse](#historyresponse) ### 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). ### 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. ### 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. ### 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) ### 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) ### AlertsService (synq.alerts.services.v2.AlertsService) AlertsService provides operations for managing alert configurations. It supersedes synq.alerts.services.v1.AlertsService: entities are selected with the canonical synq.queries.v1.Query + resolver\_ql trigger rather than the bespoke EntityGroupQuery. #### Create Create ([CreateRequest](#createrequest)) [CreateResponse](#createresponse) Create a new alert configuration. #### Upsert Upsert ([UpsertRequest](#upsertrequest)) [UpsertResponse](#upsertresponse) Creates the alert when no alert holds `fqn`, otherwise replaces the stored alert with the state given here in a single write. Use it to make a stored alert match a declared state, e.g. when deploying alerts from configuration as code. See UpsertRequest for which fields cannot change. #### 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. #### Rename Rename ([RenameRequest](#renamerequest)) [RenameResponse](#renameresponse) Rename an existing alert configuration. The config can be identified by either ID or FQN. #### UpdateTargets UpdateTargets ([UpdateTargetsRequest](#updatetargetsrequest)) [UpdateTargetsResponse](#updatetargetsresponse) Replace the delivery targets of an existing alert configuration. The config can be identified by either ID or FQN. #### UpdateSettings UpdateSettings ([UpdateSettingsRequest](#updatesettingsrequest)) [UpdateSettingsResponse](#updatesettingsresponse) Update the trigger and/or the kind-specific settings of an alert. The config can be identified by either ID or FQN. #### UpdateTemplate UpdateTemplate ([UpdateTemplateRequest](#updatetemplaterequest)) [UpdateTemplateResponse](#updatetemplateresponse) Set or clear the message template of 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. #### ToggleIncidentOwnerAlert ToggleIncidentOwnerAlert ([ToggleIncidentOwnerAlertRequest](#toggleincidentowneralertrequest)) [ToggleIncidentOwnerAlertResponse](#toggleincidentowneralertresponse) Turns the workspace's incident-owner alert on or off. This alert notifies each incident's owner on its configured channels and has no other configuration, so it is managed here rather than through Create / Delete and does not appear in List or BatchGet. Read its current state with GetIncidentOwnerAlert. #### GetIncidentOwnerAlert GetIncidentOwnerAlert ([GetIncidentOwnerAlertRequest](#getincidentowneralertrequest)) [GetIncidentOwnerAlertResponse](#getincidentowneralertresponse) Reports whether the workspace's incident-owner alert is on. This alert has no other configuration and does not appear in List or BatchGet; turn it on or off with ToggleIncidentOwnerAlert. #### SendTestAlert SendTestAlert ([SendTestAlertRequest](#sendtestalertrequest)) [SendTestAlertResponse](#sendtestalertresponse) Delivers a static test message to the given targets so you can confirm that delivery reaches each channel before relying on a real alert. Nothing is stored and the targets need not belong to a saved alert, so this can be called while an alert is still being authored. ### AlertsService (synq.alerts.services.v1.AlertsService) AlertsService provides operations for managing alert configurations. Deprecated: use synq.alerts.services.v2.AlertsService. The v2 service selects entities with the canonical synq.queries.v1.Query + resolver\_ql trigger; this v1 service, which uses the bespoke EntityGroupQuery selection, is scheduled for removal. Migrate existing integrations to v2. #### 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. ### 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 and sub-domains. ### 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.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) Report how many domains the workspace uses, split into top-level and sub-domains. ### 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. * `DescribeResolverQl` returns the language itself — every function, every accepted enum value — so you author against what this deployment compiles rather than against a table baked into your client. All three authenticate and resolve your workspace from your credentials. `DescribeResolverQl` additionally needs no permission of its own, so any credential can read it; the other two read the catalog and are scoped. #### DescribeResolverQl DescribeResolverQl ([DescribeResolverQlRequest](#describeresolverqlrequest)) [DescribeResolverQlResponse](#describeresolverqlresponse) Describe the ResolverQL this deployment accepts: every function with its arguments and documentation, the category order to group them by, and the accepted values of every enum-typed argument. Read it before authoring a selection, and validate against it rather than against a copy compiled into your client. The language gains functions and accepted values as Coalesce Quality supports more, and a client working from its own table both misses what was added and refuses a query this server would compile. Nothing is passed, and no permission is needed beyond being authenticated — so a client holding a narrow credential, one that may write a deployment rule but cannot read entities, can still find out how to write the selection it is being asked for. Read it as an answer for your workspace, not as a constant. Most of it is the same for everyone, but the entity types you defined yourself are part of the language too: today they are reachable only through `ResolverQlEnumDomain.pattern`, which is why that field exists, and named by `synq.entities.typedefs.v1.TypeDefsService.ListEntityTypeDefs`. Caching it for the life of your process is fine; re-read it after you add or rename an entity type of your own. #### 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. ### 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. #### DeleteComment DeleteComment ([DeleteCommentRequest](#deletecommentrequest)) [DeleteCommentResponse](#deletecommentresponse) Delete a comment on an incident. Only the actor who posted the comment may delete it. Deleting an already-deleted comment succeeds. ### OverlaysService (synq.overlays.v1.OverlaysService) OverlaysService answers which organizational overlays claim an entity. An overlay is a grouping you lay over your catalog rather than something the warehouse itself knows about. Two kinds exist today: a **data product**, which groups the assets that make up something your organization delivers, and an **owner**, which names the person or team responsible for a set of assets and where alerts about them go. Each is defined by a membership rule, not by an explicit list, so what belongs to one changes as your warehouse does. "Owner" here means stewardship — who is accountable for an asset and who hears about it when something breaks. It is not the structural containment sense the word carries elsewhere in the API, where an asset can be said to own the checks and monitors declared on it. Nothing this service returns describes that relationship. This service reads that membership backwards. The defining services answer "what is in this data product"; this one answers "which data products and owners claim this table" — the question you have when you are looking at one asset and want to know who cares about it and what it feeds. Membership follows identity. Where the same table is represented more than once in your catalog — a transformation model and the warehouse table it builds — an overlay whose rule matches one of them claims the others too. So an alert routed by ownership reaches the responsible party whichever representation raised it, and you do not have to know which one a rule was written against. Two consequences worth planning around. You can ask about whichever representation you happen to hold and get the same answer, so there is no need to resolve an identity group first. And if you do ask about several members of one group in a single call, each comes back with its own entry carrying the same overlays — correct, but redundant, so ask about one member per group when you are near the request limit. Related services: * `synq.dataproducts.v2.DataproductsService` and `synq.owners.v1.OwnersService` define the overlays read here, and turn an id from a response into a name, a description and its contact channels. * `synq.entities.resolve.v1.IdentifierResolveService` turns an identifier you already hold — a warehouse table name, a dbt model — into the `entity_id` these calls take. #### BatchGetEntityOverlays BatchGetEntityOverlays ([BatchGetEntityOverlaysRequest](#batchgetentityoverlaysrequest)) [BatchGetEntityOverlaysResponse](#batchgetentityoverlaysresponse) For each entity, list every overlay that claims it. The response has one entry per requested id, in the order you asked, so you can match results positionally and never have to tell "absent" from "empty". An entity that belongs to no overlay comes back with empty lists. Freshness. Which overlays exist and what they are attached to is up to date the moment you change it — create an overlay, delete one, point an ownership at a different data product, and the next call reflects it. What each overlay *contains* is recomputed periodically, so an asset that newly satisfies an existing rule — a table appearing in a folder a rule watches — shows up shortly afterwards rather than instantly. Returns PERMISSION\_DENIED if your credential can read neither data products nor owners. If it can read one but not the other, the call succeeds and the list you may not read comes back empty rather than failing. #### BatchGetOverlayMemberCounts BatchGetOverlayMemberCounts ([BatchGetOverlayMemberCountsRequest](#batchgetoverlaymembercountsrequest)) [BatchGetOverlayMemberCountsResponse](#batchgetoverlaymembercountsresponse) Count the members of each named overlay. The cheap way to answer "how big is this" — use it for a summary line or a badge. When you need the assets themselves, list them through the service that defines the overlay. Counts distinct members, so an owner responsible for two data products that overlap is not charged twice for the assets they share. Same freshness as `BatchGetEntityOverlays`: counts follow the periodic recomputation of what each overlay contains. Returns PERMISSION\_DENIED if your credential can read neither data products nor owners. #### ListEntityCoverage ListEntityCoverage ([ListEntityCoverageRequest](#listentitycoveragerequest)) [ListEntityCoverageResponse](#listentitycoverageresponse) List the candidate assets together with the overlays claiming each, and narrow them to what is or is not covered. This is the question behind a governance audit: of the assets you care about, which belong to no data product, and which have nobody responsible for them. You give the candidate set as a query — every asset, one platform, one folder, one domain — and each row comes back carrying the same owner and data-product lists `BatchGetEntityOverlays` returns, so a single call is both the count and the worklist. `total_count` is how many candidates match `filter` across every page, so you can say "312 of 4,190 tables are in no data product" without paging to the end. Freshness. By default this reads the same periodically recomputed membership the rest of this service reads, and tells you how old it is in `members_computed_at`. Ask for `FRESHNESS_LIVE` when the answer has to reflect every definition as of now — it re-resolves them, which is far slower and far more expensive, so keep it for a one-off audit rather than a page that refreshes. Returns PERMISSION\_DENIED if your credential can read neither data products nor owners, and also if `filter` names a kind it may not read: an empty list must not be the answer to both "nothing is uncovered" and "you may not look". A kind you may not read still comes back as an empty list on each row, as it does elsewhere in this service. Returns INVALID\_ARGUMENT if the selection resolves to more assets than one call will report on — see `CoverageSelection` for the limit and for how to choose a candidate set worth reading. #### GetCoverageSummary GetCoverageSummary ([GetCoverageSummaryRequest](#getcoveragesummaryrequest)) [GetCoverageSummaryResponse](#getcoveragesummaryresponse) Count coverage over one or more named candidate sets, without listing the assets themselves. The aggregate behind a coverage dashboard. Each selection you send comes back as one row of totals, keyed by the label you gave it, so a breakdown by type, platform, folder or domain is one round trip rather than one call per bucket. There is no server-side grouping, on purpose. This service knows what claims an asset, not what kind of thing the asset is, so naming the selections yourself — `with_type("dbt_model")`, `in_folder(...)`, `in_domain(...)` — keeps the buckets in your own vocabulary and costs the same. Selections are counted independently and may overlap. An asset in two of them is counted in both. Returns PERMISSION\_DENIED unless your credential can read both data products and owners. Every row names both, and a zero that was never looked at is indistinguishable from a zero that was. ### 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). ### PlatformsService (synq.platforms.v1.PlatformsService) PlatformsService is a service for managing Platforms and Integrations. #### SetPlatformAuthentication SetPlatformAuthentication ([SetPlatformAuthenticationRequest](#setplatformauthenticationrequest)) [SetPlatformAuthenticationResponse](#setplatformauthenticationresponse) ### DeliveriesService (synq.deliveries.v1.DeliveriesService) DeliveriesService reports what was sent to your notification integrations — webhooks, PagerDuty, Opsgenie — and what came back. It answers the three questions an integration owner has. "Did this event reach my endpoint": list the deliveries for an event id and read the outcome of each. "Why did my endpoint reject it": read the attempts, which carry the request as it was sent and the response as it came back. "Why did I get nothing at all": every delivery that sent nothing records a reason, so a silent integration can be explained rather than guessed at. Deliveries are kept for 90 days. Credential-bearing header values are never returned, on either side of an attempt — see `Header`. #### ListDeliveries ListDeliveries ([ListDeliveriesRequest](#listdeliveriesrequest)) [ListDeliveriesResponse](#listdeliveriesresponse) List deliveries, newest event first. With no `integration_id` this is the whole workspace's feed; with one it is that integration's. #### BatchGetDeliveries BatchGetDeliveries ([BatchGetDeliveriesRequest](#batchgetdeliveriesrequest)) [BatchGetDeliveriesResponse](#batchgetdeliveriesresponse) Fetch deliveries by id. Ids that do not exist, or have passed out of the retention window, are omitted from the response rather than causing an error. Unlike `ListDeliveries`, this always returns the routing provenance. #### GetDelivery GetDelivery ([GetDeliveryRequest](#getdeliveryrequest)) [GetDeliveryResponse](#getdeliveryresponse) Fetch a single delivery by id. `BatchGetDeliveries` does the same for many at once and is the variant exposed over REST. #### ListAttempts ListAttempts ([ListAttemptsRequest](#listattemptsrequest)) [ListAttemptsResponse](#listattemptsresponse) List every attempt made for one delivery, oldest first. A delivery is attempted at most ten times, so the result is small and is not paginated. #### SummariseDeliveries SummariseDeliveries ([SummariseDeliveriesRequest](#summarisedeliveriesrequest)) [SummariseDeliveriesResponse](#summarisedeliveriesresponse) Count deliveries over a window, bucketed by outcome, by skip reason and by HTTP status class. Use it to watch your own delivery failure rate without paging through the feed. #### Redeliver Redeliver ([RedeliverRequest](#redeliverrequest)) [RedeliverResponse](#redeliverresponse) Send an earlier delivery again, to the same integration, with the same event. The replay is a new delivery with its own id, linked to the original through `redelivery_of`, and appears in `ListDeliveries` like any other. It is signed with the integration's current secret rather than the one the original used, which makes it the way to confirm that a rotated secret is accepted by the receiver. Retrying this call sends the delivery again. Rate-limited per integration; over the limit it fails with `RESOURCE_EXHAUSTED` rather than queueing. #### SendTestDelivery SendTestDelivery ([SendTestDeliveryRequest](#sendtestdeliveryrequest)) [SendTestDeliveryResponse](#sendtestdeliveryresponse) Send a test delivery to an integration, to confirm the endpoint is reachable and that it accepts what is sent. It is always sent, whatever event types the integration subscribes to — a test that silently matches nothing would report the same as a broken endpoint. Returns the id of the delivery it created. The send is asynchronous: poll `BatchGetDeliveries` with that id until the outcome leaves `OUTCOME_PENDING`. Retrying this call sends another test. Rate-limited per integration; over the limit it fails with `RESOURCE_EXHAUSTED` rather than queueing. ### 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. ### 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. ### 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. ### 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) ### 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). ParseYaml refuses two types of suite with INVALID\_ARGUMENT and a SuiteValidationFailure detail: * A suite with `setup_file` or `teardown_file`. These fields refer to files that the server cannot read. * A suite with `reporting.level: detailed`. To find all other problems in a suite, use ValidateSuite. #### RenderYaml RenderYaml ([RenderYamlRequest](#renderyamlrequest)) [RenderYamlResponse](#renderyamlresponse) RenderYaml renders a ReconciliationSuite proto as a YAML config string. #### ValidateSuite ValidateSuite ([ValidateSuiteRequest](#validatesuiterequest)) [ValidateSuiteResponse](#validatesuiteresponse) ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as `synq-recon check-config` without `--db`. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it. ### 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. A suite with `reporting.level: detailed` gets INVALID\_ARGUMENT with a SuiteValidationFailure detail. To find all other problems before you save, call YamlService.ValidateSuite. Use expected\_state\_at or create\_only to save only when a condition is true. Without them, the save replaces the suite that is stored. #### 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. ### 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. ### 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. #### UpdateDeploymentCategories UpdateDeploymentCategories ([UpdateDeploymentCategoriesRequest](#updatedeploymentcategoriesrequest)) [UpdateDeploymentCategoriesResponse](#updatedeploymentcategoriesresponse) Change the categories declared for a deployment's reconciliation checks without re-promoting the suite snapshot. Each field is patched independently: omitting one leaves it as it was, sending an empty string clears it, and sending a value sets or replaces it — so changing the governance category can never disturb the technical one. The new categories reach the published checks immediately; a re-promote is not needed for them to take effect. #### 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. ### 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. ### 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. ### 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. ### 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. The response reports what each requested relationship did, and under which (check, checked) pair of entities it was stored. #### DeleteCheckRelationships DeleteCheckRelationships ([DeleteCheckRelationshipsRequest](#deletecheckrelationshipsrequest)) [DeleteCheckRelationshipsResponse](#deletecheckrelationshipsresponse) Delete relationships between checks and the entities they validate. Relationships that do not exist are ignored. The response says which of them actually removed something. #### ListCheckRelationships ListCheckRelationships ([ListCheckRelationshipsRequest](#listcheckrelationshipsrequest)) [ListCheckRelationshipsResponse](#listcheckrelationshipsresponse) List every relationship that attaches a check to the entities it validates, across the whole workspace. ### 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. The response reports what each requested relationship did to the stored graph, and under which pair of entities it was stored. Read it: a relationship whose endpoints resolve to a pair another relationship in the same batch also resolves to is one edge, and only the last write to it survives. #### DeleteRelationships DeleteRelationships ([DeleteRelationshipsRequest](#deleterelationshipsrequest)) [DeleteRelationshipsResponse](#deleterelationshipsresponse) Delete relationships between entities. If the relationship does not exist, it will be ignored. The response says which of them actually removed something, so a caller reconciling a set of edges can tell a withdrawal from a no-op. #### ListRelationships ListRelationships ([ListRelationshipsRequest](#listrelationshipsrequest)) [ListRelationshipsResponse](#listrelationshipsresponse) List relationships touching the given entities, or every relationship in the workspace when ids is left empty. ### 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 ### 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. ### 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 the features of one entity, or of every custom entity in the workspace when entity\_id is left unset. ### 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. ### 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. ### 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. #### BatchGetEntityAnnotations BatchGetEntityAnnotations ([BatchGetEntityAnnotationsRequest](#batchgetentityannotationsrequest)) [BatchGetEntityAnnotationsResponse](#batchgetentityannotationsresponse) Read the annotations carried by specific entities. ListAnnotations answers what the workspace annotates by and how often; this answers what one entity carries. They are separate reads because an entity's annotations are not part of the entity: `synq.entities.v1.Entity` is the shape `synq.entities.custom.v1.UpsertEntity` accepts, so the `annotations` field on it is what a producer ASSERTS about an entity, and answering a read with it would make a read-edit-write round trip write one entity's annotations onto another. ### 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. ### 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. ### ImpactService (synq.entities.impact.v1.ImpactService) #### GetImpact GetImpact ([GetImpactRequest](#getimpactrequest)) [GetImpactResponse](#getimpactresponse) ### 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. ### ActivityService (synq.entities.activity.v1alpha.ActivityService) ActivityService reads the query history of a workspace's data platforms: how popular an entity is, who reads and writes it, what one login, tool, job or person touched and what it cost, and where a workspace's compute goes. Every read covers a window of whole UTC hours, by default the 30 days before the current hour. A login's reads count toward popularity as its service account's popularity policy says (see synq.entities.platformusers.v1alpha.ServiceAccountsService), and Coalesce Quality's own queries never count. Weights are per query, in each platform's own figures. bytes\_scanned is never a cost, and no platform reports cost per table, so an entity's share of a query is an equal split. Nothing here is credits or currency. #### BatchGetPopularity BatchGetPopularity ([BatchGetPopularityRequest](#batchgetpopularityrequest)) [BatchGetPopularityResponse](#batchgetpopularityresponse) Read how popular each asked entity is over the window: its counted reads and writes per measure, and its rank in each pool it has reads in. An entity is answered with the entities it is the same as, such as a dbt model and the table it builds. Every asked id has an answer, an empty one when nothing counted. #### ListEntityActors ListEntityActors ([ListEntityActorsRequest](#listentityactorsrequest)) [ListEntityActorsResponse](#listentityactorsresponse) Read who read and wrote each asked entity over the window: the jobs, the service accounts, the tools and the logins. Anyone who reads lineage, and the reliability agent, is served. Only a caller holding the platform users scope sees the logins: any other gets every logins list empty and logins\_hidden set. #### ListPersonActivity ListPersonActivity ([ListPersonActivityRequest](#listpersonactivityrequest)) [ListPersonActivityResponse](#listpersonactivityresponse) Read what one person's logins read and wrote over the window, per entity, direction and measure. What a colleague read is personal data, so a user caller needs the platform users scope from its role, which a Developer and an Admin have. Logins in a service account, and Coalesce Quality's own queries, are never part of the answer. #### GetEntityActivitySeries GetEntityActivitySeries ([GetEntityActivitySeriesRequest](#getentityactivityseriesrequest)) [GetEntityActivitySeriesResponse](#getentityactivityseriesresponse) Read how access to one entity moves over the window: per direction, a point per UTC hour, a point per day in the asked time zone, and a weekday and hour grid. A direction's total is the sum of its actors in ListEntityActors under the same lens. It names tools, never a login. #### BatchGetEntityUsage BatchGetEntityUsage ([BatchGetEntityUsageRequest](#batchgetentityusagerequest)) [BatchGetEntityUsageResponse](#batchgetentityusageresponse) Read how each asked entity is used over the window, in one line: what loads it, what runs and builds it, what else writes it, and who reads it, such as "loaded by Fivetran, orchestrated by Airflow, transformed by dbt, read by Looker Studio, 3 people and 12 logins". Each role names its actor at the most precise level known: a job or app, else a service account, else the tool. It answers "what runs this" for a table or a model, and GetActorSummary answers "what this job runs". It names tools, jobs and service accounts, never a login. #### GetActorSummary GetActorSummary ([GetActorSummaryRequest](#getactorsummaryrequest)) [GetActorSummaryResponse](#getactorsummaryresponse) Read what one actor read, built and wrote over the window, what its queries cost per compute and platform, and when it works. The actor is asked for by name, so nothing is left out for being Coalesce Quality's own access, a writer's own read or a policy. What a person did is personal data: a person, or a login, is answered only to that person, or to a caller holding the platform users scope, which a Developer and an Admin have. Anyone else gets PERMISSION\_DENIED. A job, a service account, a tool and Coalesce Quality are answered to every caller, and without the platform users scope the answer names no login. #### GetActivityOverview GetActivityOverview ([GetActivityOverviewRequest](#getactivityoverviewrequest)) [GetActivityOverviewResponse](#getactivityoverviewresponse) Read a workspace's queries and their cost per group of logins, per platform, and its most read entities. It names groups and entities, never a login or a person. #### ListActors ListActors ([ListActorsRequest](#listactorsrequest)) [ListActorsResponse](#listactorsresponse) List the workspace's actors, the service accounts, tools, people, logins nothing classifies and Coalesce Quality, each with the totals GetActorSummary has for it: its queries and their weights, its reads, inputs and writes, and the entities it read and wrote. A login can be in several actors, such as its service account and the tool that issued its queries, so the actors never add up to the workspace: GetActivityOverview is the split that does. Only a caller holding the platform users scope sees people and logins: any other gets the rest with people\_hidden set. #### ListAccessSignals ListAccessSignals ([ListAccessSignalsRequest](#listaccesssignalsrequest)) [ListAccessSignalsResponse](#listaccesssignalsresponse) List the entities of the workspace, or of a selection, that one signal names, such as the tables a pipeline builds and nobody reads, or the tables nobody touched. A signal is computed from the window's access on each call, so a service account change shows on the next one. It names entities and tools, never a login. ### OrchestrationService (synq.entities.orchestration.v1.OrchestrationService) OrchestrationService tells which jobs, job steps and tasks run an entity, and which entities a job, job step or task runs, from the runs of the last 31 days. It covers Airflow tasks and DAGs, dbt Cloud job steps and Coalesce jobs. Deprecated: use synq.entities.activity.v1alpha.ActivityService. BatchGetEntityUsage answers "what runs this" for a table or a model, as its ORCHESTRATED and TRANSFORMED roles, and GetActorSummary answers "what this job runs", from its RUNS writes. #### BatchOrchestration BatchOrchestration ([BatchOrchestrationRequest](#batchorchestrationrequest)) [BatchOrchestrationResponse](#batchorchestrationresponse) BatchOrchestration returns, for each requested entity, the jobs, job steps and tasks that ran it in the last 31 days (upstream), and the entities it ran (downstream). ### ChecksCategoriesService (synq.entities.checks.v2.ChecksCategoriesService) ChecksCategoriesService reads and edits the categories of the checks in a workspace. Categorising checks is what turns a long list of tests into a picture of data quality: it lets you ask how much of a data product is covered for completeness, or which freshness checks exist across three warehouses that each name the same idea differently. Every check resolves to at most one category per dimension: * technical — what kind of check this is, mechanically ("nullness", "uniqueness", "freshness"); * governance — what the check is for, in data-quality terms ("Completeness", "Accuracy", "Timeliness"). The two are independent, and each resolves from three sources, in descending precedence: a category set explicitly on the check through this service, a category the producing tool declared, and a category one of the workspace's categorisation rules computed. Rules are managed by ChecksCategorisationRulesService and are the right tool for anything that generalises; set a category explicitly only for the checks that are genuine exceptions. The workspace and the acting identity always come from the request credentials, never from the payload. #### UpsertCheckCategories UpsertCheckCategories ([UpsertCheckCategoriesRequest](#upsertcheckcategoriesrequest)) [UpsertCheckCategoriesResponse](#upsertcheckcategoriesresponse) Set the category of one or more checks explicitly. An explicit category is authoritative for its check: it overrides both the producer-declared category and anything the categorisation rules compute, and it survives every later rule change. Each dimension updates independently. A field that is omitted leaves that dimension as it is; a field set to the empty string clears the explicit category on that dimension, so the check falls back to its producer-declared or rule-computed value. Repeating the same request converges to the same state rather than accumulating changes. #### DeleteCheckCategories DeleteCheckCategories ([DeleteCheckCategoriesRequest](#deletecheckcategoriesrequest)) [DeleteCheckCategoriesResponse](#deletecheckcategoriesresponse) Clear the explicit categories of one or more checks, on both dimensions. Each check falls back to its producer-declared or rule-computed category. Idempotent — clearing a check that has no explicit category succeeds. #### ListCheckCategories ListCheckCategories ([ListCheckCategoriesRequest](#listcheckcategoriesrequest)) [ListCheckCategoriesResponse](#listcheckcategoriesresponse) List the workspace's checks with their resolved categories. Returns every check by default; the filters combine, so one call answers questions like "which dbt tests still have no governance category" or "which checks did this rule categorise". #### BatchGetCheckCategories BatchGetCheckCategories ([BatchGetCheckCategoriesRequest](#batchgetcheckcategoriesrequest)) [BatchGetCheckCategoriesResponse](#batchgetcheckcategoriesresponse) Read the categories of specific checks. Ids that do not exist are omitted from the response rather than causing an error, so a partially-stale list of ids still returns what it can. #### ListCategories ListCategories ([ListCategoriesRequest](#listcategoriesrequest)) [ListCategoriesResponse](#listcategoriesresponse) List the workspace's category vocabulary: the category names in use on each dimension, whether a workspace or platform rule produces each one, and how many checks carry it. Use it to populate a category picker so a workspace converges on one spelling per concept, and to see how much of the workspace is still uncategorised. #### ListCategorisationFilters ListCategorisationFilters ([ListCategorisationFiltersRequest](#listcategorisationfiltersrequest)) [ListCategorisationFiltersResponse](#listcategorisationfiltersresponse) List the attribute values the workspace's checks actually have — the platforms, entity types, packages and kinds available to build a categorisation rule or a listing filter from. Pass `selected` to narrow each list to values that co-occur with the current selection, so a rule editor never offers a combination that matches nothing. A list never constrains itself: choosing one platform still leaves every other platform selectable. ### ChecksCategorisationRulesService (synq.entities.checks.v2.ChecksCategorisationRulesService) ChecksCategorisationRulesService manages the rules that categorise a workspace's checks automatically. A rule says "checks matching this predicate get this category on this dimension". Rules are the scalable way to categorise: they apply to checks that already exist and to every check ingested afterwards, so a new dbt package or a new warehouse does not mean a fresh round of manual tagging. A rule-computed category is the lowest-precedence source — a category set explicitly on a check through ChecksCategoriesService, and one the producing tool declared, both win over it. A typical loop is: ListCategorisationFilters to see what the workspace's checks look like, PreviewRule to check the reach of a candidate, UpsertRule to save it, then GetRecategorisationStatus to confirm the existing checks have caught up. Every workspace starts with a set of platform-provided rules covering the common cases. They are visible here, they can be superseded by a workspace rule of any priority, and they cannot be edited from a workspace. #### UpsertRule UpsertRule ([UpsertRuleRequest](#upsertrulerequest)) [UpsertRuleResponse](#upsertruleresponse) Create or update a categorisation rule. The rule id is supplied by the caller (a UUID), which makes this operation idempotent — repeating the same request converges to the same rule rather than creating a duplicate. On create, `dimension`, `title`, `category` and `matcher` are required. On update, a field that is set is written and a field that is omitted is left unchanged. To guard against overwriting a concurrent edit, pass the `etag` you last read. Saving a rule schedules a sweep that recategorises the workspace's existing checks. It normally completes in seconds; GetRecategorisationStatus confirms it. #### DeleteRule DeleteRule ([DeleteRuleRequest](#deleterulerequest)) [DeleteRuleResponse](#deleteruleresponse) Delete a categorisation rule. Checks the rule categorised fall back to the next rule that matches them, or become uncategorised. Idempotent — deleting an already-deleted or unknown rule succeeds. Pass `etag` to guard against deleting a concurrently-edited rule. #### ListRules ListRules ([ListRulesRequest](#listrulesrequest)) [ListRulesResponse](#listrulesresponse) List the rules that apply to the caller's workspace — its own rules plus the platform-provided ones — in the order they are tried. Narrow with `dimension` and `scope`. #### BatchGetRules BatchGetRules ([BatchGetRulesRequest](#batchgetrulesrequest)) [BatchGetRulesResponse](#batchgetrulesresponse) Read specific rules by id — typically to resolve the `rule_id` a ResolvedCategory carries into the rule that produced it. Ids the caller cannot see, or that do not exist, are omitted from the response rather than causing an error. #### PreviewRule PreviewRule ([PreviewRuleRequest](#previewrulerequest)) [PreviewRuleResponse](#previewruleresponse) Report what a candidate rule would change, without saving it. The candidate is slotted into the workspace's live rule set — replacing an existing rule when `id` names one — and the whole resolution is run over every check, so scope, priority, explicit categories and producer-declared categories are all honoured. The response separates the candidate's raw reach from its real effect, which are rarely the same number. Preview a rule before saving it: one that matches broadly can recategorise a large part of a workspace in a single sweep. #### ListRuleMatches ListRuleMatches ([ListRuleMatchesRequest](#listrulematchesrequest)) [ListRuleMatchesResponse](#listrulematchesresponse) Report how many checks each rule currently categorises, with a sample of them — the state already applied, not a projection. Use it to show "categorises N checks" next to each rule, and to spot a rule that has stopped matching anything. For the full, paginated list of one rule's checks, call ChecksCategoriesService.ListCheckCategories with the rule id. #### GetRecategorisationStatus GetRecategorisationStatus ([GetRecategorisationStatusRequest](#getrecategorisationstatusrequest)) [GetRecategorisationStatusResponse](#getrecategorisationstatusresponse) Progress of the re-categorisation sweep a rule change schedules. The sweep normally completes in seconds, so this is how to confirm that the workspace's existing checks have caught up with the new rules — not something a client has to wait on. ### 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. ### 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 ### PlatformUsersService (synq.entities.platformusers.v1alpha.PlatformUsersService) PlatformUsersService reads the logins of a workspace's data platforms, as its integrations declare them and as their queries show them: how each login reads, why, how much it does and what it costs. Logins, their emails and what they read are often personal data, so every read here needs the platform users scope, which a Developer and an Admin have. #### ListPlatformUsers ListPlatformUsers ([ListPlatformUsersRequest](#listplatformusersrequest)) [ListPlatformUsersResponse](#listplatformusersresponse) List the workspace's logins by their share of the workspace's activity, highest first. The first page carries a summary of the whole window. #### BatchGetPlatformUsers BatchGetPlatformUsers ([BatchGetPlatformUsersRequest](#batchgetplatformusersrequest)) [BatchGetPlatformUsersResponse](#batchgetplatformusersresponse) Read logins by platform user id. Ids no integration declared and with no activity in the window are left out. #### ListLinkSuggestions ListLinkSuggestions ([ListLinkSuggestionsRequest](#listlinksuggestionsrequest)) [ListLinkSuggestionsResponse](#listlinksuggestionsresponse) Suggest which workspace member each unclassified login may belong to, by matching the login against the members the caller passes. Accept a suggestion with synq.users.v1 UsersService.UpsertUserAliases. A login already linked is skipped only when the caller lists its platform\_user\_id among a member's identities. ### ServiceAccountsService (synq.entities.platformusers.v1alpha.ServiceAccountsService) ServiceAccountsService maintains a workspace's service accounts, person links and popularity policies: which logins act for a tool, which belong to a person, and whose reads count toward an entity's popularity. Every change goes through a plan first. A typical loop is: ListPlatformUsers with unclassified\_only to see the logins nothing classifies, ListServiceAccountSuggestions for the accounts their evidence points at, PlanServiceAccountChanges to see what a change set moves, then ApplyServiceAccountChanges with the plan's token. A change takes effect on the next read. Exact matchers, suggestion evidence and plans name logins, which are often personal data. A caller without the platform users scope gets them with every platform user id, login and person identity cleared, and the counts kept. A suggestion's account name and login patterns come from the logins it saw, so that caller gets those cleared too, and a suggestion named after its one login is named "Service login". #### ListServiceAccounts ListServiceAccounts ([ListServiceAccountsRequest](#listserviceaccountsrequest)) [ListServiceAccountsResponse](#listserviceaccountsresponse) List every workspace service account, then every built-in one, in the order they apply, and the person links in a second list. #### BatchGetServiceAccounts BatchGetServiceAccounts ([BatchGetServiceAccountsRequest](#batchgetserviceaccountsrequest)) [BatchGetServiceAccountsResponse](#batchgetserviceaccountsresponse) Read service accounts by id, built-in ids included. Ids that do not exist are left out. #### ListServiceAccountSuggestions ListServiceAccountSuggestions ([ListServiceAccountSuggestionsRequest](#listserviceaccountsuggestionsrequest)) [ListServiceAccountSuggestionsResponse](#listserviceaccountsuggestionsresponse) Suggest service accounts for the logins the evidence says are not a person, each as a change set with its evidence. A login a workspace account, a person link or Coalesce Quality takes is left out. A login only a built-in account holds is suggested too, so it can get an account of its own. A suggestion changes nothing by itself: edit it if needed, plan it with PlanServiceAccountChanges, then apply it. #### PlanServiceAccountChanges PlanServiceAccountChanges ([PlanServiceAccountChangesRequest](#planserviceaccountchangesrequest)) [PlanServiceAccountChangesResponse](#planserviceaccountchangesresponse) Report what a change set would change, without writing it: every login slice whose classification moves, how many counted reads each adds or removes, and the entities whose rank moves most. The plan\_token it returns is what ApplyServiceAccountChanges takes. #### ApplyServiceAccountChanges ApplyServiceAccountChanges ([ApplyServiceAccountChangesRequest](#applyserviceaccountchangesrequest)) [ApplyServiceAccountChangesResponse](#applyserviceaccountchangesresponse) Write a planned change set, all of it or nothing. It is refused with FAILED\_PRECONDITION when the token is not from a plan of exactly this change set against the workspace as it is now: plan it again. A change to an account or person link whose etag no longer matches is refused with ABORTED, and nothing is written. Caller-supplied ids and etags make a retry converge. ### 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 by how many entities", "what SQL constructs does this specific entity use" and "which columns does building this entity join on", 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. Every count is a number of entities, not a number of occurrences: an entity whose SQL contains five GROUP BY clauses adds one to the HAS\_GROUP\_BY count, not five. 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 for each of the requested entities, keyed by their synq path: the set of detected SQL constructs and, when the request asks for them, the joins that building the entity makes. Every requested path appears in the response, including a path with no SQL details and a path matching no entity; both are returned with an empty set of constructs and no joins. #### ListJoinPatterns ListJoinPatterns ([ListJoinPatternsRequest](#listjoinpatternsrequest)) [ListJoinPatternsResponse](#listjoinpatternsresponse) ListJoinPatterns lists how other SQL joins a table, or one of its columns: every join key that the SQL of a table, view or model in the workspace uses to join the requested entity, read from the requested entity's side, and which SQL makes it. It is the reverse of `BatchSqlDetails` joins, which say how building one entity joins others: here the requested entity is the one being joined. The requested entity is taken together with every entity that is the same object, like a dbt model, the table it builds and that table in a catalog, so asking about any of them returns the joins on all of them. ### 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. ### 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. ### TypeDefsService (synq.entities.typedefs.v1.TypeDefsService) TypeDefsService tells you what the type values in every other endpoint mean. Responses across the API describe things by enum — an entity is an `ENTITY_TYPE_BQ_TABLE`, it belongs to `DATA_PLATFORM_TYPE_BIGQUERY`, a run is an `EXECUTION_TYPE_DBT_INVOCATION`. This service turns each of those into a name you can display and a set of facts you can act on: is this a transformation model, does it live in a warehouse, can it be monitored. Read it instead of keeping your own copy of the list. New entity types and new platforms are added as Coalesce Quality supports more tools, and a hard-coded table in your code will label them with whatever its fallback produces and miss that an existing type gained a capability. Everything here comes from the server, so you pick both up without changing your code. A typical integration calls them once at startup, keeps them in a map, and looks types up as responses arrive. It also tells you what a selection query can ask for: ListEntityTraitDefs is the vocabulary behind `traits`, which selects entities by what they are rather than by naming every type. Scoping and freshness: * ListEntityTypeDefs is per workspace, because the types you defined yourself are part of your workspace's vocabulary. It returns the built-in types and your own custom types together. * ListPlatformDefs, ListExecutionTypeDefs and ListEntityTraitDefs are the same for everyone. * The built-in half changes only when Coalesce Quality is upgraded, so caching it for the life of your process is fine. You can add or edit your own custom types at any time, so if a newly created type needs to appear promptly, cache the entity types for minutes rather than hours, or re-read after you change one. The workspace comes from your credentials; there is nothing to pass. Each list is small — hundreds of entries — so every call returns the whole set and none of them page. #### ListEntityTypeDefs ListEntityTypeDefs ([ListEntityTypeDefsRequest](#listentitytypedefsrequest)) [ListEntityTypeDefsResponse](#listentitytypedefsresponse) List every kind of entity in your workspace, the built-in types and your own. The built-in half covers every value of `synq.entities.v1.EntityType` this server serves, so this is also how you discover a type that your generated code is too old to name. Your own types have no enum value of their own — each one is identified by its `type_id`. #### ListPlatformDefs ListPlatformDefs ([ListPlatformDefsRequest](#listplatformdefsrequest)) [ListPlatformDefsResponse](#listplatformdefsresponse) List every platform Coalesce Quality connects to, with its display name. Use it to name the platform on an entity — "BigQuery", "Microsoft SQL Server" — rather than deriving a name from the enum value. #### ListEntityTraitDefs ListEntityTraitDefs ([ListEntityTraitDefsRequest](#listentitytraitdefsrequest)) [ListEntityTraitDefsResponse](#listentitytraitdefsresponse) List every trait a selection query can filter entities by. Read it before writing a selection that uses `traits`, and to show a person what one covers. A trait name this list does not contain selects nothing, so reading the list is how you tell a trait that does not exist from one your client is too old to know about. #### ListExecutionTypeDefs ListExecutionTypeDefs ([ListExecutionTypeDefsRequest](#listexecutiontypedefsrequest)) [ListExecutionTypeDefsResponse](#listexecutiontypedefsresponse) List every kind of run Coalesce Quality records against an entity. A dbt invocation, a warehouse query job, a detected schema change. Use it to name the `execution_type` that execution and run endpoints return. ### 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. ### 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 ### LineageFoldsService (synq.entities.lineage.folds.v1alpha.LineageFoldsService) LineageFoldsService manages the lineage folds of a workspace: rules that show many similar entities, a table or a storage path written anew on every run, as one node in lineage. See `LineageFold`. A change to a fold reaches lineage shortly after the call returns, not within it. Fold ids are UUIDs chosen by the caller, so a retried create converges on the same fold instead of making a second one. Pass the `etag` you last read on a change to guard against overwriting a concurrent edit. This API is in alpha: its shape may change without notice. #### CreateFold CreateFold ([CreateFoldRequest](#createfoldrequest)) [CreateFoldResponse](#createfoldresponse) Create a fold. Repeating the same request returns the fold it created; creating a different fold under an id already in use is refused with ALREADY\_EXISTS. #### ListFolds ListFolds ([ListFoldsRequest](#listfoldsrequest)) [ListFoldsResponse](#listfoldsresponse) List the ids of every fold in the workspace, switched off ones included, oldest first. Read the folds with `BatchGetFolds`. #### BatchGetFolds BatchGetFolds ([BatchGetFoldsRequest](#batchgetfoldsrequest)) [BatchGetFoldsResponse](#batchgetfoldsresponse) Read folds by id. An id with no fold is absent from the response. #### BatchGetFoldNodes BatchGetFoldNodes ([BatchGetFoldNodesRequest](#batchgetfoldnodesrequest)) [BatchGetFoldNodesResponse](#batchgetfoldnodesresponse) Read fold nodes by entity id: which fold a node in a lineage response stands for, and which entities it showed. An id is answered for as long as lineage may still return it; an id with nothing to answer is absent from the response. #### RenameFold RenameFold ([RenameFoldRequest](#renamefoldrequest)) [RenameFoldResponse](#renamefoldresponse) Change the name shown on a fold's node. #### UpdateFoldMatcher UpdateFoldMatcher ([UpdateFoldMatcherRequest](#updatefoldmatcherrequest)) [UpdateFoldMatcherResponse](#updatefoldmatcherresponse) Change which entities a fold matches. The fold's node keeps its entity id. #### SetFoldEnabled SetFoldEnabled ([SetFoldEnabledRequest](#setfoldenabledrequest)) [SetFoldEnabledResponse](#setfoldenabledresponse) Switch a fold on or off. A fold switched off is kept and listed, and lineage shows the entities it matched as their own nodes again. #### DeleteFold DeleteFold ([DeleteFoldRequest](#deletefoldrequest)) [DeleteFoldResponse](#deletefoldresponse) Delete a fold. Deleting a fold that does not exist succeeds. #### PreviewFold PreviewFold ([PreviewFoldRequest](#previewfoldrequest)) [PreviewFoldResponse](#previewfoldresponse) Show what a matcher would fold, before it is saved: how many entities and lineage edges it matches, a sample of them, and the entities that stop being shown on the same node as a folded one. Answered from the lineage the workspace has now, without any fold applied. ### 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) ### 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) Links aliases to users. A platform user alias needs SCOPE\_PLATFORM\_USER\_LINK, every other alias type SCOPE\_USER\_EDIT. A request holding an alias the caller may not write is refused as a whole, and nothing is written. #### DeleteUserAliases DeleteUserAliases ([DeleteUserAliasesRequest](#deleteuseraliasesrequest)) [DeleteUserAliasesResponse](#deleteuseraliasesresponse) Removes aliases from users. A platform user alias removes only that login, every other alias type removes the user's alias of that type. The scopes are checked per alias, as for UpsertUserAliases. #### AddUserRole AddUserRole ([AddUserRoleRequest](#adduserrolerequest)) [AddUserRoleResponse](#adduserroleresponse) Grants a role to a user in the workspace. Granting a role the user already holds succeeds without change. Granting a role to a user who is not a member of the workspace makes them a member; such a user can only be named by their synq or email identity. #### RemoveUserRole RemoveUserRole ([RemoveUserRoleRequest](#removeuserrolerequest)) [RemoveUserRoleResponse](#removeuserroleresponse) Withdraws a role from a user in the workspace. Withdrawing a role the user does not hold succeeds without change. Withdrawing the user's last role removes them from the workspace, together with their linked aliases. #### 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:\", and the "platform\_user:" id of every linked platform user. ### 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. ### IamService (synq.auth.iam.v1.IamService) #### Iam Iam ([IamRequest](#iamrequest)) [IamResponse](#iamresponse) Iam returns information about caller authentication ### KnowledgeService (synq.knowledge.v1alpha.KnowledgeService) KnowledgeService reads the knowledge a team keeps about its data: knowledge pages written or imported by the team, and the descriptions people write for entities. Knowledge pages form a tree, and pages and entities are pinned to each other. Nothing here is the description an entity's own source reports, which `synq.entities.entities.v1.EntitiesService` reads. This API is in alpha: its shape may change without notice. #### BatchGetEntityKnowledge BatchGetEntityKnowledge ([BatchGetEntityKnowledgeRequest](#batchgetentityknowledgerequest)) [BatchGetEntityKnowledgeResponse](#batchgetentityknowledgeresponse) Read the knowledge held about entities: the description people wrote for each one, and the knowledge pages pinned to it. An entity with no knowledge is absent from the response, as is an id that names no entity. Returns UNAVAILABLE when the knowledge could not be read, which is worth retrying. #### ListKnowledgePages ListKnowledgePages ([ListKnowledgePagesRequest](#listknowledgepagesrequest)) [ListKnowledgePagesResponse](#listknowledgepagesresponse) List the ids of knowledge pages, ordered by name, optionally narrowed by a part of their name and by certification. Deprecated pages are left out unless asked for. Read the pages with `BatchGetKnowledgePages`. #### BatchGetKnowledgePages BatchGetKnowledgePages ([BatchGetKnowledgePagesRequest](#batchgetknowledgepagesrequest)) [BatchGetKnowledgePagesResponse](#batchgetknowledgepagesresponse) Read knowledge pages by id: their content, where they sit in the tree, who owns them and how they are tagged. A page that does not exist, or was deleted, is absent from the response. Set `skip_content` to read everything but the content, for showing a listing. #### ListKnowledgePageLinks ListKnowledgePageLinks ([ListKnowledgePageLinksRequest](#listknowledgepagelinksrequest)) [ListKnowledgePageLinksResponse](#listknowledgepagelinksresponse) List what is pinned to a knowledge page, in either direction: the ids of the entities and of the other knowledge pages. ### 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. ### 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. ### 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.services.v2.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. ### CloudwatchService (synq.ingest.cloudwatch.v1.CloudwatchService) #### IngestCloudwatchLogsData IngestCloudwatchLogsData ([IngestCloudwatchLogsDataRequest](#ingestcloudwatchlogsdatarequest)) [IngestCloudwatchLogsDataResponse](#ingestcloudwatchlogsdataresponse) ### SqlMeshService (synq.ingest.sqlmesh.v1.SqlMeshService) #### IngestMetadata IngestMetadata ([IngestMetadataRequest](#ingestmetadatarequest)) [IngestMetadataResponse](#ingestmetadataresponse) #### IngestExecution IngestExecution ([IngestExecutionRequest](#ingestexecutionrequest)) [IngestExecutionResponse](#ingestexecutionresponse) ### 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) Accepts what a DataHub REST emitter sends when its server is set to `/api/ingest/airflow/v1`: it posts to `{server}/aspects?action=ingestProposal`. ### DbtService (synq.ingest.dbt.v1.DbtService) #### IngestInvocation IngestInvocation ([IngestInvocationRequest](#ingestinvocationrequest)) [IngestInvocationResponse](#ingestinvocationresponse) ### OpenlineageService (synq.ingest.openlineage.v1.OpenlineageService) #### Ingest Ingest ([IngestRequest](#ingestrequest)) [IngestResponse](#ingestresponse) ### 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. ### SqlTestsDeploymentRulesService (synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService) SqlTestsDeploymentRulesService manages SqlTestDeploymentRules — rules that dynamically deploy SQL test templates onto every table or view a query matches, resyncing over time as the match set changes. #### GetSqlTestDeployOverview GetSqlTestDeployOverview ([GetSqlTestDeployOverviewRequest](#getsqltestdeployoverviewrequest)) [GetSqlTestDeployOverviewResponse](#getsqltestdeployoverviewresponse) Preview the effect of deploying a rule (which have not yet been saved), without deploying it. #### GetSqlTestDeployDeleteOverview GetSqlTestDeployDeleteOverview ([GetSqlTestDeployDeleteOverviewRequest](#getsqltestdeploydeleteoverviewrequest)) [GetSqlTestDeployDeleteOverviewResponse](#getsqltestdeploydeleteoverviewresponse) Preview the effect of deleting a rule, without deleting it. #### ListSqlTestDeploymentRules ListSqlTestDeploymentRules ([ListSqlTestDeploymentRulesRequest](#listsqltestdeploymentrulesrequest)) [ListSqlTestDeploymentRulesResponse](#listsqltestdeploymentrulesresponse) #### BatchGetSqlTestDeploymentRules BatchGetSqlTestDeploymentRules ([BatchGetSqlTestDeploymentRulesRequest](#batchgetsqltestdeploymentrulesrequest)) [BatchGetSqlTestDeploymentRulesResponse](#batchgetsqltestdeploymentrulesresponse) #### DeploySqlTestDeploymentRule DeploySqlTestDeploymentRule ([DeploySqlTestDeploymentRuleRequest](#deploysqltestdeploymentrulerequest)) [DeploySqlTestDeploymentRuleResponse](#deploysqltestdeploymentruleresponse) Deploy (create or update) a SqlTestDeploymentRule and immediately sync tests onto its current match set. #### BatchDeploySqlTestDeploymentRules BatchDeploySqlTestDeploymentRules ([BatchDeploySqlTestDeploymentRulesRequest](#batchdeploysqltestdeploymentrulesrequest)) [BatchDeploySqlTestDeploymentRulesResponse](#batchdeploysqltestdeploymentrulesresponse) #### DeleteSqlTestDeploymentRule DeleteSqlTestDeploymentRule ([DeleteSqlTestDeploymentRuleRequest](#deletesqltestdeploymentrulerequest)) [DeleteSqlTestDeploymentRuleResponse](#deletesqltestdeploymentruleresponse) #### BatchDeleteSqlTestDeploymentRules BatchDeleteSqlTestDeploymentRules ([BatchDeleteSqlTestDeploymentRulesRequest](#batchdeletesqltestdeploymentrulesrequest)) [BatchDeleteSqlTestDeploymentRulesResponse](#batchdeletesqltestdeploymentrulesresponse) ### 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) ## Messages ### 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 | ### 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) ### DeleteCommentRequest (synq.issues.v2.DeleteCommentRequest) | Field | Type | Description | | - | - | - | | issue\_id | [ string](#string) | ID of the issue the comment is on. | | comment\_id | [ string](#string) | ID of the comment to delete, as returned by PostComment or read from the issue's comments. | | actor | [ Actor](#actor) | Actor deleting the comment. Must match the actor that posted it. | ### DeleteCommentResponse (synq.issues.v2.DeleteCommentResponse) ### 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 | ### 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 | ### 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 | ### 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 | ### EditIntegrationAction (synq.recommendations.v1.EditIntegrationAction) EditIntegrationAction opens an integration's settings, where the change is made through `synq.integrations.v1.IntegrationsService.UpdateIntegration` or the app. | Field | Type | Description | | - | - | - | | integration\_id | [ string](#string) | Id of the integration (UUID). | | config\_fields | [repeated string](#string) | The configuration fields to change, named as in the integration's configuration message (`job_ids` on a dbt Cloud integration), so a client can take you straight to them. Empty when the change is not about particular fields. | ### IntegrationTarget (synq.recommendations.v1.IntegrationTarget) IntegrationTarget is one integration of the workspace. | Field | Type | Description | | - | - | - | | integration\_id | [ string](#string) | Id of the integration (UUID), as `synq.integrations.v1.IntegrationsService` knows it. | ### LinkAction (synq.recommendations.v1.LinkAction) LinkAction is a page that explains how to make the change: Coalesce Quality documentation, or the documentation of a system the workspace connects to. | Field | Type | Description | | - | - | - | | title | [ string](#string) | What the link is about ("Selecting dbt Cloud jobs", "Snowflake: GRANT privileges"), to show as the link text. Always set. | | url | [ string](#string) | Absolute https URL of the page. | | platform | [ DataPlatformType](#dataplatformtype) | Which system the page belongs to, to show that platform's icon beside the link. Unspecified for Coalesce Quality documentation or where no platform fits. | ### NewIntegrationAction (synq.recommendations.v1.NewIntegrationAction) NewIntegrationAction starts connecting a new integration of a platform the workspace has none of, where it is made through `synq.integrations.v1.IntegrationsService.CreateIntegration` or the app. | Field | Type | Description | | - | - | - | | platform | [ DataPlatformType](#dataplatformtype) | The platform to connect. A platform with several kinds of integration has one action per kind (`DATA_PLATFORM_TYPE_DBT_CLOUD` and `DATA_PLATFORM_TYPE_DBT_SELF_HOSTED` for dbt). A client that cannot connect the platform offers no button for it. | ### OpenInAppAction (synq.recommendations.v1.OpenInAppAction) OpenInAppAction opens a place in the Coalesce Quality app. The place is named rather than given as a URL, so a client builds the link for its own routes. | Field | Type | Description | | - | - | - | | destination | [ AppDestination](#appdestination) | none | ### Recommendation (synq.recommendations.v1.Recommendation) Recommendation is a change Coalesce Quality recommends you make: a grant an integration's role is missing, a setting that stopped matching what runs, a feature worth enabling, a review waiting for you. Nothing is broken; making the change gets you more, or better, out of the product. A recommendation stays for as long as the condition holds, and disappears on its own once it no longer does. You can dismiss it until something new is found, or ignore it for good. | Field | Type | Description | | - | - | - | | recommendation\_id | [ string](#string) | Stable id of the recommendation (UUID). The same recommendation for the same target always has the same id, also after it disappeared and came back, so a dismissal or an ignore keeps applying to it. | | target | [ RecommendationTarget](#recommendationtarget) | What the recommendation is about. | | code | [ string](#string) | Stable identifier of the kind of recommendation (`stale_job_selection`), lower snake\_case. It never changes for a given kind, so it is safe to filter or group on; the wording of `message` and `remediation` may improve. | | subject | [ string](#string) | What within the target the recommendation is about, when one target can carry the same kind of recommendation about several things ("job selection", a database name). Empty when it concerns the target as a whole. | | message | [ string](#string) | What was found, as one sentence. | | remediation | [ string](#string) | What to change, and where. | | details | [repeated string](#string) | The objects the recommendation concerns, one per entry. | | details\_omitted | [ int32](#int32) | How many further objects exist beyond `details`. Zero when `details` lists all of them. | | actions | [repeated RecommendationAction](#recommendationaction) | What you can do about it, most useful first, for a client to offer as buttons beside `remediation`. Empty when `remediation` is all there is to go on. | | first\_stated\_at | [ Timestamp](#timestamp) | When the condition was first found, without it clearing in between. | | changed\_at | [ Timestamp](#timestamp) | When what is reported last changed: a new object, a different remediation, a reworded message, different actions. | | state | [ RecommendationState](#recommendationstate) | Whether the recommendation is in front of you, after any dismissal or ignore. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_decision.decision | [optional RecommendationDecision](#recommendationdecision) | The dismissal or ignore standing against the recommendation. Still present when it reopened because something new was found since it was dismissed. Absent when nobody decided. | ### RecommendationAction (synq.recommendations.v1.RecommendationAction) RecommendationAction is one thing you can do about a recommendation. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.edit\_integration | [ EditIntegrationAction](#editintegrationaction) | Open an integration's settings. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.link | [ LinkAction](#linkaction) | Open a page that explains the change. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.open\_in\_app | [ OpenInAppAction](#openinappaction) | Open a place in the Coalesce Quality app. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) action.new\_integration | [ NewIntegrationAction](#newintegrationaction) | Start connecting a new integration. | ### RecommendationDecision (synq.recommendations.v1.RecommendationDecision) RecommendationDecision is a dismissal or an ignore. | Field | Type | Description | | - | - | - | | kind | [ RecommendationDecisionKind](#recommendationdecisionkind) | none | | decided\_at | [ Timestamp](#timestamp) | When the decision was made. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_decided\_by.decided\_by | [optional Actor](#actor) | Who made it. Absent when the request identified no one. | ### RecommendationTarget (synq.recommendations.v1.RecommendationTarget) RecommendationTarget is what a recommendation is about. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.workspace | [ WorkspaceTarget](#workspacetarget) | The workspace as a whole: a feature to enable, a review waiting. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) target.integration | [ IntegrationTarget](#integrationtarget) | One integration: a grant its role lacks, a setting to change. | ### WorkspaceTarget (synq.recommendations.v1.WorkspaceTarget) WorkspaceTarget is the workspace as a whole. ### BatchGetRecommendationsRequest (synq.recommendations.v1.BatchGetRecommendationsRequest) Request to fetch recommendations by id. | Field | Type | Description | | - | - | - | | recommendation\_ids | [repeated string](#string) | Ids of the recommendations (UUIDs). | ### BatchGetRecommendationsResponse (synq.recommendations.v1.BatchGetRecommendationsResponse) Response with the recommendations found, keyed by id. | Field | Type | Description | | - | - | - | | recommendations | [map RecommendationsEntry](#recommendationsentry) | none | ### BatchGetRecommendationsResponse.RecommendationsEntry (synq.recommendations.v1.BatchGetRecommendationsResponse.RecommendationsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ Recommendation](#recommendation) | none | ### DismissRecommendationRequest (synq.recommendations.v1.DismissRecommendationRequest) Request to dismiss a recommendation. | Field | Type | Description | | - | - | - | | recommendation\_id | [ string](#string) | Id of the recommendation (UUID). | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is deciding. Optional: identity is completed from the calling credentials. | ### DismissRecommendationResponse (synq.recommendations.v1.DismissRecommendationResponse) Response with the recommendation as stored after the call. | Field | Type | Description | | - | - | - | | recommendation | [ Recommendation](#recommendation) | none | ### IgnoreRecommendationRequest (synq.recommendations.v1.IgnoreRecommendationRequest) Request to ignore a recommendation. | Field | Type | Description | | - | - | - | | recommendation\_id | [ string](#string) | Id of the recommendation (UUID). | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is deciding. Optional: identity is completed from the calling credentials. | ### IgnoreRecommendationResponse (synq.recommendations.v1.IgnoreRecommendationResponse) Response with the recommendation as stored after the call. | Field | Type | Description | | - | - | - | | recommendation | [ Recommendation](#recommendation) | none | ### ListRecommendationsRequest (synq.recommendations.v1.ListRecommendationsRequest) Request to list recommendation ids. | Field | Type | Description | | - | - | - | | target\_kinds | [repeated RecommendationTargetKind](#recommendationtargetkind) | Limit the list to these kinds of target. Empty lists every kind. | | integration\_ids | [repeated string](#string) | Limit the list to recommendations about these integrations (UUIDs). Implies the integration target kind. Empty applies no integration filter. | | states | [repeated RecommendationState](#recommendationstate) | Limit the list to recommendations in these states. Empty lists every state; pass `RECOMMENDATION_STATE_OPEN` for the ones still in front of you. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Cursor-based pagination. Omit to get every id in one response; set it without a `page_size` for pages of the default size. | ### ListRecommendationsResponse (synq.recommendations.v1.ListRecommendationsResponse) Response with a page of recommendation ids. | Field | Type | Description | | - | - | - | | recommendation\_ids | [repeated string](#string) | none | | page\_info | [ PageInfo](#pageinfo) | Pass `page_info.last_id` as the next cursor. Empty once there are no more. | ### RestoreRecommendationRequest (synq.recommendations.v1.RestoreRecommendationRequest) Request to restore a recommendation. | Field | Type | Description | | - | - | - | | recommendation\_id | [ string](#string) | Id of the recommendation (UUID). | ### RestoreRecommendationResponse (synq.recommendations.v1.RestoreRecommendationResponse) Response with the recommendation as stored after the call. | Field | Type | Description | | - | - | - | | recommendation | [ Recommendation](#recommendation) | 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 | | never\_negative | [ bool](#bool) | The aggregation is never negative, so the anomaly engine never forecasts below 0. | ### 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) | Config ID this monitor was authored from, when deployed via configuration as code. Unset for monitors authored directly through this API. | On a write this field is only ever set, never unset: omitting it keeps the stored value, so a full-replace update cannot detach the monitor from the config that owns it. An empty string is a real config id — the one a deploy that declares no namespace uses — so sending it attaches the monitor to that config rather than clearing the field. No value detaches a monitor; recreating it is the only way to hand it back to the app. | \| 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. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Technical category this monitor declares for itself — what kind of check it is mechanically (e.g. "volume", "freshness"). It is the monitor's own declaration, not an administrative override: it is authoritative over any categorisation rule the workspace would otherwise apply, and is itself overridden by an explicit per-check category an admin sets. The value is free-form and workspace-defined — whatever vocabulary your categorisation rules already use. It is displayed with underscores turned into spaces, so `snake_case` reads well. Send the whole monitor on every upsert: leaving this out is the same as sending it empty, and both mean the monitor declares no technical category. A monitor then falls back to its `quality.check_category` annotation, which remains accepted and keeps working — this field simply outranks it. A segmented monitor's segments take this value too. A segment is the same monitor sliced by a column value, so it cannot declare a category of its own. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Governance category this monitor declares for itself — what the check is for, the data quality dimension governance reports on (e.g. "timeliness"). Resolves independently of `category` — setting one never suppresses the other — and follows the same precedence, the same free-form vocabulary and the same full-state upsert rule described above. Its annotation fallback is `quality.governance_category`. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When the monitor was deleted. Unset while it is live, which is every monitor an ordinary listing reports; a deleted one comes back only from a listing that asked for it. Read-only, and ignored on writes. | ### MonitorFieldStats (synq.monitors.custom\_monitors.v1.MonitorFieldStats) | Field | Type | Description | | - | - | - | | fields | [repeated string](#string) | Columns monitored with every metric of their data type. A column may appear here or in field\_options, not both. At least one of fields / field\_options must be non-empty. | | field\_options | [repeated FieldOption](#fieldoption) | Columns monitored with an explicit metric selection. The sensitivity of each metric applies to that metric instead of the monitor's sensitivity. Changing the selection keeps the history of the metrics that remain and does not reset the monitor: a removed metric stops being predicted, and adding it back resumes it. | ### MonitorFieldStats.FieldOption (synq.monitors.custom\_monitors.v1.MonitorFieldStats.FieldOption) | Field | Type | Description | | - | - | - | | field | [ string](#string) | Column name, as in the table schema. | | metrics | [repeated MetricOption](#metricoption) | Metrics to predict on this column, each with its sensitivity. Must be metrics that exist for the column's data type (e.g. mean is not available on a text column): - text: NUM\_ROWS, NUM\_NULL, PCT\_NULL, NUM\_UNIQUE, PCT\_UNIQUE, NUM\_EMPTY, PCT\_EMPTY. - numeric: the text metrics plus MEAN, MIN, MAX, MEDIAN, STDDEV. - date and time: NUM\_ROWS, NUM\_NULL, PCT\_NULL, NUM\_UNIQUE, PCT\_UNIQUE, MIN, MAX. A metric the column's data warehouse cannot compute is skipped (Redshift does not compute NUM\_UNIQUE or PCT\_UNIQUE on numeric columns), so a column whose whole selection is skipped produces no predictions. | ### 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. | | delay\_model | [ DelayModel](#delaymodel) | How the delay and volume\_change\_delay metrics model the expected arrival time of new data. Unset leaves the stored value unchanged. | ### 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 | | errors | [repeated CreateError](#createerror) | One entry per requested monitor that was not created, most commonly because a monitor with that id already exists. Empty when every requested monitor was created. | ### BatchCreateMonitorResponse.CreateError (synq.monitors.custom\_monitors.v1.BatchCreateMonitorResponse.CreateError) Details of a requested monitor that was not created. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ 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 | | errors | [repeated DeleteError](#deleteerror) | One entry per requested monitor that was not deleted, most commonly because no monitor with that id exists. Empty when every requested monitor was deleted. | ### BatchDeleteMonitorResponse.DeleteError (synq.monitors.custom\_monitors.v1.BatchDeleteMonitorResponse.DeleteError) Details of a requested monitor that was not deleted. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ 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 | | errors | [repeated UpdateError](#updateerror) | One entry per requested monitor that was not updated, most commonly because no monitor with that id exists. Empty when every requested monitor was updated. | ### BatchUpdateMonitorModeResponse.UpdateError (synq.monitors.custom\_monitors.v1.BatchUpdateMonitorModeResponse.UpdateError) Details of a requested monitor whose mode was not updated. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ 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 | | errors | [repeated UpdateError](#updateerror) | One entry per requested monitor that was not updated, most commonly because no monitor with that id exists. Empty when every requested monitor was updated. | ### BatchUpdateMonitorResponse.UpdateError (synq.monitors.custom\_monitors.v1.BatchUpdateMonitorResponse.UpdateError) Details of a requested monitor that was not updated. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ 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 | | errors | [repeated UpdateError](#updateerror) | One entry per requested monitor that was not updated, most commonly because no monitor with that id exists. Empty when every requested monitor was updated. | ### BatchUpdateMonitorSeverityResponse.UpdateError (synq.monitors.custom\_monitors.v1.BatchUpdateMonitorSeverityResponse.UpdateError) Details of a requested monitor whose severity was not updated. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ 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 | | include\_deleted | [ bool](#bool) | Include deleted monitors in the listing. Off by default, so an ordinary listing keeps describing only what is live. | Turn it on to resolve a `monitor_ids` entry that may name a deleted monitor. The id this endpoint returns is the only reference a caller holds after creating or listing a monitor, and the monitored asset needed to address the same monitor as an entity is on the stored row and nowhere else, so a listing that excluded it left the id unresolvable. One entry per monitor either way: a monitor keeps a row per version, and the listing reports the latest one. `deleted_at` on each returned monitor is what tells a deleted monitor from a live one. | \| [**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. | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional string](#string) | Human-provided description of what this monitor checks. Unset for monitor types that don't carry one. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sql\_source.sql\_source | [optional string](#string) | SQL query used as the data source instead of querying the monitored table or view directly, when the monitor is configured with one. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deleted\_at.deleted\_at | [optional Timestamp](#timestamp) | When set, the monitor has been deleted: it no longer runs, no longer reports metrics, and is excluded from every listing. The record is still served by id so a stored or stale identifier resolves to something, which makes this the only signal that the monitor is gone. Unset for a live monitor. | ### 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 | ### MonitorInfoRequest (synq.monitors.info.v1.MonitorInfoRequest) | Field | Type | Description | | - | - | - | | id | [ Identifier](#identifier) | Identifier of the monitor, or of a monitor-like entity such as a dbt test or a SQL test. Its `synq_path` spelling also accepts a custom monitor's own id, in either of the forms `monitor_id` takes. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_monitor\_id.monitor\_id | [optional string](#string) | Id of a custom monitor, as `synq.monitors.custom_monitors.v1.ListMonitors` returns it and `BatchUpdateMonitor` takes it. Accepts the bare UUID or the `custom-` form. An alternative to `id` rather than an addition to it: setting both is an error. | ### 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 | ### 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.entity\_ids | [ EntityIds](#entityids) | Deploy monitors on specific entities, named by the ids the API returned for them. Read back as `identifier_list`, with each id on the identifier it names. | | [**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` and is stored compiled; on read it carries the canonical rendering of the stored selection, equal to `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 | | overlapping\_rule\_ids | [repeated string](#string) | Deployment rules OTHER than the one this overview is for that also govern the assets it leaves monitored (the ones in active\_monitors\_for / active\_custom\_monitors\_for). Exact and complete: it is read off the same rule/asset rows the overview itself is computed from, so no per-asset lookup can improve on it. Empty when no other rule covers those assets — and note that a rule whose contribution is shadowed instead (SkippedAsset.reason SKIPPED\_HIGHER\_PRIORITY\_RULE) is not here; those assets are not left monitored by this rule at all. | Ids only. Read their titles, owners and types with ListDeploymentRules(rule\_ids). | ### 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) | Config ID this rule was authored from, when deployed via configuration as code. Unset for rules authored directly through this API. | On a write this field is only ever set, never unset: omitting it keeps the stored value, so a full-replace update cannot detach the rule from the config that owns it. An empty string is a real config id — the one a deploy that declares no namespace uses — so sending it attaches the rule to that config rather than clearing the field. No value detaches a rule; recreating it is the only way to hand it back to the app. | ### 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. Returned sorted by metric\_id — a client can rely on that ordering rather than re-sorting. | | delay\_model | [ DelayModel](#delaymodel) | How the delay and volume\_change\_delay metrics model the expected arrival time of new data. Unset leaves the stored value unchanged. | ### 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. Returned sorted by metric\_id — a client can rely on that ordering rather than re-sorting. | | 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. The selection is compiled when it is written and stored in that form, so the text itself is not kept: two spellings of the same selection store the same rule, and a type alias such as "table" is expanded to the types it names at the time of the write. On read this field carries the canonical rendering of the stored selection, equal to `rendered_resolver_ql`, whichever way the rule was written, and is empty when the selection has no ResolverQL representation. Writing a read response back unchanged stores the same selection. `query` is always populated. | | 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. Empty only for selections that have no ResolverQL representation. Compare selections by this field rather than by the text a rule was written with, which may be spelled differently. | | delay\_model | [ DelayModel](#delaymodel) | How the delay and volume\_change\_delay metrics model the expected arrival time of new data. Unset leaves the stored value unchanged. | ### SkippedAsset (synq.monitors.automated\_monitors.v1.SkippedAsset) | Field | Type | Description | | - | - | - | | asset\_path | [ string](#string) | none | | reason | [ string](#string) | Why the asset was skipped, as a stable SCREAMING\_SNAKE token. Clients branch on these, so treat the spellings as part of this API: adding a value is safe, renaming one is a breaking change. A value not listed here may appear — a client must fall through to "skipped, reason unrecognised" rather than assume the set is closed. | SKIPPED\_HIGHER\_PRIORITY\_RULE another rule of higher precedence governs the asset, so this rule's settings never reach it (see rule precedence) SKIPPED\_NO\_FRESHNESS\_COLUMN\_MATCH no column matched the freshness field SKIPPED\_NO\_FRESHNESS\_FIELD\_PATTERN no freshness field pattern is configured SKIPPED\_NO\_INTEGRATION the asset's integration is gone SKIPPED\_TEST\_PREPARATION\_FAILED the test could not be prepared SKIPPED\_TEST\_OWNED\_BY\_OTHER\_RULE another rule already deploys that test A string rather than an enum for compatibility: an enum would have to be introduced as a second field, since the producers already write these tokens. | \| reason\_code | [ SkipReason](#skipreason) | Machine-checkable form of `reason`, so a client can branch on a value the compiler knows instead of string-matching a wire constant. `reason` remains authoritative and keeps being written unchanged; `reason_code` is SKIP\_REASON\_UNSPECIFIED for a `reason` this field does not yet cover — fall through to "skipped, reason unrecognised" rather than treat that as impossible, since the set of reasons is expected to grow. | ### 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. Returned sorted by metric\_id — a client can rely on that ordering rather than re-sorting. | | delay\_model | [ DelayModel](#delaymodel) | How the delay and volume\_change\_delay metrics model the expected arrival time of new data. Unset leaves the stored value unchanged. | ### 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) | Field | Type | Description | | - | - | - | | deleted\_ids | [repeated string](#string) | IDs for which DeploymentRules were deleted without error. | | errors | [repeated DeleteError](#deleteerror) | Errors raised while deleting. This list will be empty if there were no errors. | ### BatchDeleteDeploymentRulesResponse.DeleteError (synq.monitors.automated\_monitors.v1.BatchDeleteDeploymentRulesResponse.DeleteError) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ string](#string) | none | ### 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) | Field | Type | Description | | - | - | - | | updated\_ids | [repeated string](#string) | IDs of the deployment rules whose title was updated. Optional and additive: an older server leaves it unset even though it did rename the rules. | | errors | [repeated UpdateError](#updateerror) | One entry per requested deployment rule that was not updated, most commonly because no rule with that id exists. Empty when every requested rule was updated. A rule missing from both lists was not renamed. | ### BatchUpdateDeploymentRuleTitleResponse.UpdateError (synq.monitors.automated\_monitors.v1.BatchUpdateDeploymentRuleTitleResponse.UpdateError) Details of a requested deployment rule that was not updated. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ string](#string) | none | ### 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) | Field | Type | Description | | - | - | - | | overview | [ MonitorsDeploymentOverview](#monitorsdeploymentoverview) | What the deploy did: the monitors it created, removed and left in place, the surviving monitors whose settings it changed, and the assets it skipped. | Computed inside this call, before the write, from the same overview the deploy acted on — so unlike an overview a caller fetches for itself, no decision window separates it from what happened. Optional and additive: an older server leaves it unset, and a caller must then answer from what it knew before the call rather than treat the absence as an error. | ### 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) ### BatchUpdateMonitorSegmentLabelsRequest (synq.monitors.segments.v1.BatchUpdateMonitorSegmentLabelsRequest) | Field | Type | Description | | - | - | - | | segments | [repeated SegmentLabel](#segmentlabel) | The segments to name. Each entry replaces that segment's label outright; a segment not listed is left alone. | ### BatchUpdateMonitorSegmentLabelsRequest.SegmentLabel (synq.monitors.segments.v1.BatchUpdateMonitorSegmentLabelsRequest.SegmentLabel) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Id of the segment to name, as returned by ListMonitorSegments. | | label | [ string](#string) | The name to give the segment. An empty string clears the label, so the segment falls back to showing its raw value. | ### BatchUpdateMonitorSegmentLabelsResponse (synq.monitors.segments.v1.BatchUpdateMonitorSegmentLabelsResponse) | Field | Type | Description | | - | - | - | | segments | [repeated MonitorSegment](#monitorsegment) | The segments that were updated, in their state after the update. | | errors | [repeated UpdateError](#updateerror) | One entry per requested segment that was not updated, most commonly because no segment with that id has been ingested. Empty when every requested segment was updated. | ### BatchUpdateMonitorSegmentLabelsResponse.UpdateError (synq.monitors.segments.v1.BatchUpdateMonitorSegmentLabelsResponse.UpdateError) Details of a requested segment that was not updated. | Field | Type | Description | | - | - | - | | id | [ string](#string) | The id as it was requested. | | reason | [ string](#string) | none | ### ListMonitorSegmentsRequest (synq.monitors.segments.v1.ListMonitorSegmentsRequest) | Field | Type | Description | | - | - | - | | monitor\_id | [ string](#string) | The monitor whose segments to list: either a custom monitor id, or the Coalesce Quality path of the monitor. Both are accepted wherever this API addresses a monitor. | ### ListMonitorSegmentsResponse (synq.monitors.segments.v1.ListMonitorSegmentsResponse) | Field | Type | Description | | - | - | - | | segments | [repeated MonitorSegment](#monitorsegment) | The monitor's segments, ordered by name. Empty when the monitor is not segmented, or has not ingested any data yet. | ### MonitorSegment (synq.monitors.segments.v1.MonitorSegment) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Identifier of this segment. Opaque: pass it back to BatchUpdateMonitorSegmentLabels to name the segment, or to synq.monitors.predictions.v1.MonitorPredictionsService as synq\_path to read this segment's predictions. Do not construct or parse it. | | monitor\_id | [ string](#string) | Id of the monitor this segment belongs to, as accepted by synq.monitors.custom\_monitors.v1.CustomMonitorsService. | | segmentation\_expression | [ string](#string) | The monitor's segmentation expression: the column or expression whose distinct values produce the segments, for example "country". | | value | [ string](#string) | The value of the segmentation expression this segment covers, exactly as it was read from the monitored data. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_label.label | [optional string](#string) | The name given to this segment. Unset when the segment has never been named, in which case every surface shows `value` instead. | | name | [ string](#string) | What this segment is shown as: `label` when one is set, `value` otherwise. This is the name that reaches check names, search and alerts. | | created\_at | [ Timestamp](#timestamp) | When this segment was first observed in the monitored data. | | last\_ingested\_at | [ Timestamp](#timestamp) | When this segment was last observed in the monitored data. A segment whose value stops appearing keeps its last observation time until the monitor drops it. | ### 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) | Monitor synq path (e.g. monitor::integration::db::schema::table::volume). REST clients pass this as the `monitorPath` query parameter. | | 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 | ### 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 to read. Accepts the monitor's synq\_path, the `::seg-` synq\_path of one of its segments, or — for a custom monitor — its own id as `synq.monitors.custom_monitors.v1.ListMonitors` returns it: the bare UUID or the `custom-` form. | | [**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. | ### 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`. | ### 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 | ### 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 | ### 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 | ### 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 | ### 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 | ### AlertingTarget (synq.alerts.v2.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.v2.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.v2.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.v2.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.v2.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.v2.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. | ### Alert (synq.alerts.v2.Alert) Alert represents the configuration for an alert. An alert is exactly one concrete kind, distinguished by the `kind` oneof: * `issue_lifecycle`: fires on the issues of selected entities. * `schema_change`: fires on the schema changes of selected entities. * `incident_lifecycle`: fires on incident state transitions. The identity, template and ownership fields are shared; everything specific to how an alert triggers and delivers lives on its kind message. Incident-owner alerts (which notify each incident's owner) are not configurable and are not represented here; they are turned on or off with AlertsService.ToggleIncidentOwnerAlert. | 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. | | created\_at | [ Timestamp](#timestamp) | Timestamp when the alert config was created. | | is\_disabled | [ bool](#bool) | Whether the alert config is currently disabled. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_template.template | [optional AlertTemplate](#alerttemplate) | Optional custom template for the rendered alert message. Common to every alert kind. Currently applied only to issue alerts; on other kinds it is accepted and ignored until templating is supported for them. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.issue\_lifecycle | [ IssueLifecycleAlert](#issuelifecyclealert) | Fires on the issues of selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.schema\_change | [ SchemaChangeAlert](#schemachangealert) | Fires on the schema changes of selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.incident\_lifecycle | [ IncidentLifecycleAlert](#incidentlifecyclealert) | Fires on incident state transitions. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | Config ID this alert was deployed from through configuration as code, unset otherwise. Immutable after creation; an empty string is the config of a deploy that declares no namespace. To move an alert to another config, delete it and recreate it under the same `fqn`. | | etag | [ string](#string) | Output-only opaque tag, changed by every write. Pass it back as `etag` on a write to guard against overwriting a concurrent change. | ### EmailCustomizationOptions (synq.alerts.v2.EmailCustomizationOptions) EmailCustomizationOptions customises the addresses used when an alert is delivered by email. Unset addresses fall back to the workspace defaults. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_from.from | [optional EmailSender](#emailsender) | Sender address emails are sent from. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reply\_to.reply\_to | [optional EmailSender](#emailsender) | Reply-to address for emails. | ### EmailSender (synq.alerts.v2.EmailSender) EmailSender is an email address paired with an optional display name. | Field | Type | Description | | - | - | - | | email | [ string](#string) | Email address. | | name | [ string](#string) | Display name shown alongside the address. | ### IncidentLifecycleAlert (synq.alerts.v2.IncidentLifecycleAlert) IncidentLifecycleAlert fires when an incident transitions into one of the selected states. It takes no entity selection. | Field | Type | Description | | - | - | - | | targets | [repeated AlertingTarget](#alertingtarget) | Targets where alerts will be sent. At least one is required. | | settings | [ IncidentLifecycleAlertSettings](#incidentlifecyclealertsettings) | Incident lifecycle alert settings. | ### IncidentLifecycleAlertSettings (synq.alerts.v2.IncidentLifecycleAlertSettings) IncidentLifecycleAlertSettings configures an alert that fires when an incident enters one of the selected states. | Field | Type | Description | | - | - | - | | states | [repeated State](#state) | Incident states whose transitions fire this alert; an empty list would create an alert that never fires. | ### IssueAlertSettings (synq.alerts.v2.IssueAlertSettings) IssueAlertSettings is the unified alert settings type for issue-based alerts. | 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_email\_customization\_options.email\_customization\_options | [optional EmailCustomizationOptions](#emailcustomizationoptions) | Optional customisation of the sender and reply-to addresses on email alerts. | ### IssueGroupingStrategy (synq.alerts.v2.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.v2.IssueGroupingStrategy.NoGrouping) NoGrouping - each issue triggers a separate alert. ### IssueGroupingStrategy.SystemDetected (synq.alerts.v2.IssueGroupingStrategy.SystemDetected) SystemDetected - the system automatically groups related issues. ### IssueLifecycleAlert (synq.alerts.v2.IssueLifecycleAlert) IssueLifecycleAlert fires on the issues of the entities its trigger selects. | Field | Type | Description | | - | - | - | | trigger | [ Trigger](#trigger) | Selects the entities that can trigger this alert. | | targets | [repeated AlertingTarget](#alertingtarget) | Targets where alerts will be sent. At least one is required. | | settings | [ IssueAlertSettings](#issuealertsettings) | Issue alert settings. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_owner.owner | [optional Owner](#owner) | Optional owner information. The owner is fixed when the alert is created. | ### OngoingAlertsStrategy (synq.alerts.v2.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.v2.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.v2.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.v2.OngoingAlertsStrategy.Stream) Stream strategy - alerts are sent continuously as issues persist. No configuration needed - alerts stream continuously. ### Owner (synq.alerts.v2.Owner) Owner attributes an alert to an owner and ownership. Only entity-scoped alerts (issue and schema change) can be owned. | Field | Type | Description | | - | - | - | | owner\_path | [ string](#string) | Path identifying the owner of this alert config. | | ownership\_id | [ string](#string) | Ownership identifier. Empty for an alert scoped to the owner as a whole rather than to one of its ownerships. | ### SchemaChangeAlert (synq.alerts.v2.SchemaChangeAlert) SchemaChangeAlert fires on the schema changes of the entities its trigger selects. | Field | Type | Description | | - | - | - | | trigger | [ Trigger](#trigger) | Selects the entities that can trigger this alert. | | targets | [repeated AlertingTarget](#alertingtarget) | Targets where alerts will be sent. At least one is required. | | settings | [ SchemaChangeAlertSettings](#schemachangealertsettings) | Schema change alert settings. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_owner.owner | [optional Owner](#owner) | Optional owner information. The owner is fixed when the alert is created. | ### SchemaChangeAlertSettings (synq.alerts.v2.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. | | ongoing | [ OngoingAlertsStrategy](#ongoingalertsstrategy) | Delivery strategy. Unset or stream sends one alert per schema change; a schedule batches them into a periodic digest on the given cron cadence. | ### Trigger (synq.alerts.v2.Trigger) Trigger selects the entities whose issues or schema changes fire this alert: a structured `query`, an optional ResolverQL string that takes precedence when set, and a read-only canonical rendering. | Field | Type | Description | | - | - | - | | query | [ Query](#query) | Structured selection of the entities that can trigger this alert. On write it is the selection unless `resolver_ql` is set, which takes precedence. Always populated on read, best-effort — a part with no public form is carried as `unsupported`. | | resolver\_ql | [ string](#string) | ResolverQL selection string, a more expressive alternative to `query` for selections it cannot express (e.g. lineage walks, column predicates). When set on write it takes precedence and `query` is ignored. On read it is echoed back verbatim for alerts authored via ResolverQL and empty for structured alerts, so writing a read response back unchanged preserves the authored form. See `rendered_resolver_ql` for the ResolverQL form of a structured alert. | | rendered\_resolver\_ql | [ string](#string) | Output-only canonical ResolverQL rendering of this alert's selection, populated regardless of how it was authored (it equals `resolver_ql` for ResolverQL-authored alerts). Ignored on write. Empty only for selections with no ResolverQL representation. | ### AlertIdentifier (synq.alerts.services.v2.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.v2.BatchGetRequest) | Field | Type | Description | | - | - | - | | identifiers | [repeated AlertIdentifier](#alertidentifier) | IDs of the alerts to get. | ### BatchGetResponse (synq.alerts.services.v2.BatchGetResponse) | Field | Type | Description | | - | - | - | | alerts | [map AlertsEntry](#alertsentry) | Alerts mapped by their identifiers. | ### BatchGetResponse.AlertsEntry (synq.alerts.services.v2.BatchGetResponse.AlertsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ Alert](#alert) | none | ### ConfigsFilter (synq.alerts.services.v2.ConfigsFilter) ConfigsFilter selects alerts by the config that manages them. | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | Config IDs to match. An empty string matches the config a deploy without a namespace uses. | ### CreateRequest (synq.alerts.services.v2.CreateRequest) CreateRequest creates a new alert configuration. The `kind` oneof carries the full specification of the alert; its target and trigger constraints are enforced on the concrete kind messages. Incident-owner alerts are not created here — turn them on with ToggleIncidentOwnerAlert. | 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_template.template | [optional AlertTemplate](#alerttemplate) | Optional custom template for the rendered alert message. Common to every alert kind; currently applied only to issue alerts. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.issue\_lifecycle | [ IssueLifecycleAlert](#issuelifecyclealert) | An issue alert on selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.schema\_change | [ SchemaChangeAlert](#schemachangealert) | A schema change alert on selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.incident\_lifecycle | [ IncidentLifecycleAlert](#incidentlifecyclealert) | An incident lifecycle alert. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | Config ID that owns this alert when deployed from configuration as code (see `Alert.config_id`); omit it for an alert authored directly. Cannot be combined with `owner.ownership_id`. | ### CreateResponse (synq.alerts.services.v2.CreateResponse) CreateResponse returns the created alert configuration. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was created. | ### DeleteRequest (synq.alerts.services.v2.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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the delete fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### DeleteResponse (synq.alerts.services.v2.DeleteResponse) DeleteResponse confirms the deletion (empty response). Empty response - successful deletion is indicated by HTTP 200 status. ### GetIncidentOwnerAlertRequest (synq.alerts.services.v2.GetIncidentOwnerAlertRequest) GetIncidentOwnerAlertRequest reads the workspace's incident-owner alert state. ### GetIncidentOwnerAlertResponse (synq.alerts.services.v2.GetIncidentOwnerAlertResponse) GetIncidentOwnerAlertResponse reports the current state. | Field | Type | Description | | - | - | - | | is\_enabled | [ bool](#bool) | Whether the incident-owner alert is on. | ### ListRequest (synq.alerts.services.v2.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. Only issue and schema change alerts carry an owner; filtering by owner therefore returns those only. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_configs\_filter.configs\_filter | [optional ConfigsFilter](#configsfilter) | Optional filter by the config the alerts were deployed from. Unset: no config filtering. Empty `ids`: only alerts managed by some config. Non-empty `ids`: only alerts managed by one of those configs. | ### ListResponse (synq.alerts.services.v2.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. | ### RenameRequest (synq.alerts.services.v2.RenameRequest) RenameRequest changes an alert's human-readable name. | Field | Type | Description | | - | - | - | | identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to rename. | | name | [ string](#string) | New human-readable name for the alert configuration. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### RenameResponse (synq.alerts.services.v2.RenameResponse) RenameResponse returns the renamed alert configuration. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was renamed. | ### SendTestAlertRequest (synq.alerts.services.v2.SendTestAlertRequest) SendTestAlertRequest delivers a static test message to the given targets. | Field | Type | Description | | - | - | - | | name | [ string](#string) | Alert name shown in the test message. Optional — leave empty while an alert is still being created; the message then omits the name. | | kind | [ TestAlertKind](#testalertkind) | The alert kind the test stands in for. Optional; selects the message wording only, so an unspecified kind produces a generic test message. | | targets | [repeated AlertingTarget](#alertingtarget) | The targets to deliver the test message to. At least one and at most 20 per request. Owner targets are expanded to each owner's configured channels. | ### SendTestAlertResponse (synq.alerts.services.v2.SendTestAlertResponse) SendTestAlertResponse reports the per-target outcome of the test send. | Field | Type | Description | | - | - | - | | dispatches | [repeated TestAlertDispatch](#testalertdispatch) | One entry per delivered target, in the order they were resolved. Owner targets contribute one entry per resolved channel. | ### TestAlertDispatch (synq.alerts.services.v2.TestAlertDispatch) TestAlertDispatch is the outcome of delivering the test message to one target. | Field | Type | Description | | - | - | - | | target | [ AlertingTarget](#alertingtarget) | The resolved target this outcome refers to. | | dispatched | [ bool](#bool) | True once the message was handed to the delivery channel; the delivery itself is asynchronous, so this does not confirm the recipient received it. | | error | [ string](#string) | Why this target was not dispatched; empty when dispatched is true. | ### ToggleEnabledRequest (synq.alerts.services.v2.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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### ToggleEnabledResponse (synq.alerts.services.v2.ToggleEnabledResponse) ToggleEnabledResponse confirms the toggle operation (empty response). Empty response - successful toggle is indicated by HTTP 200 status. ### ToggleIncidentOwnerAlertRequest (synq.alerts.services.v2.ToggleIncidentOwnerAlertRequest) ToggleIncidentOwnerAlertRequest turns the workspace's incident-owner alert on or off. | Field | Type | Description | | - | - | - | | is\_enabled | [ bool](#bool) | true turns the incident-owner alert on (creating it if absent); false turns it off (removing it). Setting the current state is a no-op. | ### ToggleIncidentOwnerAlertResponse (synq.alerts.services.v2.ToggleIncidentOwnerAlertResponse) ToggleIncidentOwnerAlertResponse reports the resulting state. | Field | Type | Description | | - | - | - | | is\_enabled | [ bool](#bool) | Whether the incident-owner alert is on after the call. | ### UpdateSettingsRequest (synq.alerts.services.v2.UpdateSettingsRequest) UpdateSettingsRequest updates an alert's trigger and/or its kind-specific settings. At least one of the two must be provided; whichever is omitted is left unchanged (neither can be cleared). The provided settings must match the alert's existing kind — switching an alert from one kind to another is not permitted. | Field | Type | Description | | - | - | - | | identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to update. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_trigger.trigger | [optional Trigger](#trigger) | New entity selection. Issue and schema change alerts only. Omit to keep the current trigger; it cannot be cleared. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) settings.issue\_lifecycle | [ IssueAlertSettings](#issuealertsettings) | Settings for an issue alert. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) settings.schema\_change | [ SchemaChangeAlertSettings](#schemachangealertsettings) | Settings for a schema change alert. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) settings.incident\_lifecycle | [ IncidentLifecycleAlertSettings](#incidentlifecyclealertsettings) | Settings for an incident lifecycle alert. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### UpdateSettingsResponse (synq.alerts.services.v2.UpdateSettingsResponse) UpdateSettingsResponse returns the updated alert configuration. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was updated. | ### UpdateTargetsRequest (synq.alerts.services.v2.UpdateTargetsRequest) UpdateTargetsRequest replaces an alert's delivery targets. | Field | Type | Description | | - | - | - | | identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to update. | | targets | [repeated AlertingTarget](#alertingtarget) | The complete set of delivery targets, replacing the existing ones. At least one target is required; the allowed target types depend on the alert's kind. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### UpdateTargetsResponse (synq.alerts.services.v2.UpdateTargetsResponse) UpdateTargetsResponse returns the updated alert configuration. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was updated. | ### UpdateTemplateRequest (synq.alerts.services.v2.UpdateTemplateRequest) UpdateTemplateRequest sets or clears an alert's message template. | Field | Type | Description | | - | - | - | | identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to update. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_template.template | [optional AlertTemplate](#alerttemplate) | New custom template for the rendered alert message. Omit to clear the template and revert to the default rendering. Currently applied only to issue alerts; accepted and ignored for other kinds. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict (ABORTED) if the alert was modified since this etag was read. | ### UpdateTemplateResponse (synq.alerts.services.v2.UpdateTemplateResponse) UpdateTemplateResponse returns the updated alert configuration. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was updated. | ### UpsertRequest (synq.alerts.services.v2.UpsertRequest) UpsertRequest states the complete alert held under `fqn`. Nothing is merged with the stored alert: every field is written as sent, so an omitted `template` clears it and the targets replace the stored ones. The only exception is `is_disabled`, described on the field. The alert kind, the `owner` inside it, and `config_id` are fixed when an alert is created. When an alert already holds `fqn` and any of them differs from the stored value, the request fails with FAILED\_PRECONDITION and nothing is written; to change one, delete the alert and upsert it again. The trigger is stored as sent, as with Create. A `query` read back from the API carries parts it cannot express as `unsupported`, so to write a stored selection back unchanged send the `rendered_resolver_ql` you read as `resolver_ql`. Incident-owner alerts cannot be upserted — manage them with ToggleIncidentOwnerAlert. | Field | Type | Description | | - | - | - | | name | [ string](#string) | Human-readable name for the alert configuration. | | fqn | [ string](#string) | Fully qualified name identifying the alert. An alert holding it is replaced; otherwise a new alert is created with it. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_template.template | [optional AlertTemplate](#alerttemplate) | Custom template for the rendered alert message. Omit to use the default rendering, clearing any stored template. Currently applied only to issue alerts; accepted and ignored for other kinds. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.issue\_lifecycle | [ IssueLifecycleAlert](#issuelifecyclealert) | An issue alert on selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.schema\_change | [ SchemaChangeAlert](#schemachangealert) | A schema change alert on selected entities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.incident\_lifecycle | [ IncidentLifecycleAlert](#incidentlifecyclealert) | An incident lifecycle alert. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | Config ID that owns this alert when deployed from configuration as code (see `Alert.config_id`); omit it for an alert authored directly. Cannot be combined with `owner.ownership_id`. For an existing alert it must equal the stored value, where omitted and the empty string are different values. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_is\_disabled.is\_disabled | [optional bool](#bool) | Whether the alert is paused. When omitted, a new alert is created enabled and an existing alert keeps its current state, so a deploy that does not manage pausing never re-enables an alert someone paused in the app. Set it to make the deploy own the paused state. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard: the write fails with ABORTED if the alert holding `fqn` was modified since this etag was read, or no longer exists. | ### UpsertResponse (synq.alerts.services.v2.UpsertResponse) UpsertResponse returns the stored alert after the write. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration as stored. | | created | [ bool](#bool) | True when no alert held `fqn` and this call created one. | ### AlertIdentifier (synq.alerts.services.v1.AlertIdentifier) Deprecated: use synq.alerts.services.v2.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) Deprecated: use synq.alerts.services.v2.BatchGetRequest. | Field | Type | Description | | - | - | - | | identifiers | [repeated AlertIdentifier](#alertidentifier) | IDs of the alerts to get. | ### BatchGetResponse (synq.alerts.services.v1.BatchGetResponse) Deprecated: use synq.alerts.services.v2.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. Deprecated: use synq.alerts.services.v2.CreateRequest. | 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. Deprecated: use synq.alerts.services.v2.CreateResponse. | 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. Deprecated: use synq.alerts.services.v2.DeleteRequest. | Field | Type | Description | | - | - | - | | identifier | [ AlertIdentifier](#alertidentifier) | Identifier for the config to delete. | ### DeleteResponse (synq.alerts.services.v1.DeleteResponse) DeleteResponse confirms the deletion (empty response). Deprecated: use synq.alerts.services.v2.DeleteResponse. ### ListRequest (synq.alerts.services.v1.ListRequest) ListRequest filters alert configurations to retrieve. Deprecated: use synq.alerts.services.v2.ListRequest. | 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. Deprecated: use synq.alerts.services.v2.ListResponse. | 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. Deprecated: use synq.alerts.services.v2.ToggleEnabledRequest. | 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). Deprecated: use synq.alerts.services.v2.ToggleEnabledResponse. ### UpdateRequest (synq.alerts.services.v1.UpdateRequest) UpdateRequest updates an existing alert configuration. The config can be identified by either ID or FQN. Deprecated: use the intent-specific requests on synq.alerts.services.v2 (RenameRequest, UpdateTargetsRequest, UpdateSettingsRequest, UpdateTemplateRequest). | 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. Deprecated: use the intent-specific responses on synq.alerts.services.v2. | Field | Type | Description | | - | - | - | | alert | [ Alert](#alert) | The alert configuration that was updated. | ### AlertingTarget (synq.alerts.v1.AlertingTarget) AlertingTarget represents a destination where alert notifications will be sent. Each target type has its own specific configuration requirements. Deprecated: use synq.alerts.v2.AlertingTarget. | 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. Deprecated: use synq.alerts.v2.EmailTarget. | 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 either a Microsoft Teams channel or a specific member. Deprecated: use synq.alerts.v2.MsTeamsTarget. | Field | Type | Description | | - | - | - | | channel | [ string](#string) | Teams channel name or ID. Leave unset to direct-message a member instead. | | member\_id | [ string](#string) | Microsoft Teams member id for direct-message delivery. | ### 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. Deprecated: use synq.alerts.v2.OwnerTarget. | 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. Deprecated: use synq.alerts.v2.SlackTarget. | 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. Deprecated: use synq.alerts.v2.WebhookTarget. | 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. | ### Alert (synq.alerts.v1.Alert) Alert represents the configuration for an alert. It contains all the necessary information to trigger and send alerts. Deprecated: use synq.alerts.v2.Alert, whose trigger is the canonical synq.queries.v1.Query + resolver\_ql selection. This message is served only by the deprecated synq.alerts.services.v1.AlertsService and is scheduled for removal. | 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. Deprecated: use synq.alerts.v2.Owner. | 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. Deprecated: synq.alerts.v2.Alert carries its settings per alert type (synq.alerts.v2.IssueLifecycleAlert, synq.alerts.v2.SchemaChangeAlert). | 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. Deprecated: the v2 trigger selects entities with synq.queries.v1.Query + resolver\_ql instead. Scheduled for removal with synq.alerts.services.v1. | 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. Deprecated: use synq.alerts.v2.IssueAlertSettings. | 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. Deprecated: use synq.alerts.v2.IssueGroupingStrategy. | 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. Deprecated: use synq.alerts.v2.SchemaChangeAlertSettings. | Field | Type | Description | | - | - | - | | notify\_upstream | [ bool](#bool) | Whether to notify upstream dependencies when schema changes occur. | | ongoing | [ OngoingAlertsStrategy](#ongoingalertsstrategy) | Delivery strategy. Unset or stream sends one alert per schema change; a schedule batches them into a periodic digest on the given cron cadence. | ### 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. Deprecated: the v2 trigger selects entities with synq.queries.v1.Query + resolver\_ql instead. Scheduled for removal with synq.alerts.services.v1. | 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.entity\_ids | [ EntityIds](#entityids) | Alert on specific entities, named by the ids the API returned for them. Read back as `identifier_list`, with each id on the identifier it names. | | [**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. | ### AlertTemplate (synq.alerts.templates.v2.AlertTemplate) AlertTemplate customises the message rendered for an alert. The body is either verbatim text (`plain`), rendered exactly as given, or a structured template (`structured`) assembled from named blocks written in Jinja-compatible syntax and grouped by where they render. | Field | Type | Description | | - | - | - | | title | [ string](#string) | Optional custom title for the rendered message. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) body.plain | [ string](#string) | Verbatim message text, rendered as-is with no templating. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) body.structured | [ StructuredTemplate](#structuredtemplate) | A structured, dynamically rendered body. | ### StructuredTemplate (synq.alerts.templates.v2.StructuredTemplate) StructuredTemplate is a dynamic template split into the two tiers a message renders in. Within each tier, blocks render in list order. A block that should appear in both tiers is listed in both `summary` and `issue_details` with the same `name`. | Field | Type | Description | | - | - | - | | summary | [repeated TemplateBlock](#templateblock) | Blocks rendered once, in the group/summary message. | | issue\_details | [repeated TemplateBlock](#templateblock) | Blocks rendered per issue, in the per-issue attachment or card. | ### TemplateBlock (synq.alerts.templates.v2.TemplateBlock) TemplateBlock is one unit of Jinja-compatible source. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name.name | [optional string](#string) | Optional block name. A block listed in both `summary` and `issue_details` under the same name is one shared block. Leave it unset and the server assigns and returns a stable name. Names reserved for built-in catalog blocks render under the server's own layout rather than emitting your content verbatim, so give a custom block a distinct name. | | content | [ string](#string) | Jinja-compatible source of the block body. | ### 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. | ### 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. | ### 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. | ### DomainMembership (synq.domains.members.v1.DomainMembership) | Field | Type | Description | | - | - | - | | user\_id | [ string](#string) | none | | domain\_id | [ string](#string) | none | | is\_default | [ bool](#bool) | none | ### 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) ### 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) ### 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. | ### 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)." | ### 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. | ### 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.entity\_ids | [ EntityIds](#entityids) | Pin specific entities by the ids the API returned for them. Read back as `identifier_list`, with each id on the identifier it names. | | [**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. | ### DescribeResolverQlRequest (synq.queries.v1.DescribeResolverQlRequest) ### DescribeResolverQlResponse (synq.queries.v1.DescribeResolverQlResponse) | Field | Type | Description | | - | - | - | | functions | [repeated ResolverQlFunction](#resolverqlfunction) | Every function the language has, ordered by name. | | categories | [repeated string](#string) | The categories a function's `category` names, in the order the product presents them. Group the catalog by this rather than sorting the names. | | enum\_domains | [map EnumDomainsEntry](#enumdomainsentry) | The accepted values of every enum-typed argument, keyed by the name an argument's `enum_domain` carries. A domain absent here places no restriction on the argument beyond its type. | ### DescribeResolverQlResponse.EnumDomainsEntry (synq.queries.v1.DescribeResolverQlResponse.EnumDomainsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ ResolverQlEnumDomain](#resolverqlenumdomain) | none | ### 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). | ### ResolverQlArg (synq.queries.v1.ResolverQlArg) One argument of a function, positional or keyword. | Field | Type | Description | | - | - | - | | name | [ string](#string) | The argument's name. For a keyword argument this is the spelling written before the `=`. | | type | [ string](#string) | The value shape the argument takes — a string, a list of strings, a boolean, a nested query. Names are the language's own and are stable. | | required | [ bool](#bool) | Whether the call fails to compile without this argument. | | enum\_domain | [ string](#string) | Names an entry in `enum_domains` when the argument accepts only values from a fixed vocabulary. Empty when any value of `type` is accepted. | | doc | [ string](#string) | What this argument does, in one sentence. Empty when the function's own doc says all there is to say. | ### ResolverQlEnumDomain (synq.queries.v1.ResolverQlEnumDomain) The values one enum-typed argument accepts. | Field | Type | Description | | - | - | - | | values | [repeated string](#string) | Every value the domain enumerates, lowercase. A value is matched case-insensitively, so a caller holding an upper-case spelling can send it as it is. | | pattern | [ string](#string) | An RE2 pattern of values accepted in **addition** to `values`, matched against the lowercased value. Empty when the domain accepts nothing beyond the list. | It exists because one domain is not fully enumerated: the entity types a workspace defines itself are a reserved band of the asset-type vocabulary rather than members of it, spelled `custom_type_`, and `values` today holds only the built-in half. A client that validates against `values` alone rejects a query this server compiles. Keep honouring the pattern even once a domain enumerates more than it does today: it is what makes a value the list has not caught up with still acceptable. | ### ResolverQlFunction (synq.queries.v1.ResolverQlFunction) One function of the ResolverQL language, as this deployment compiles it. | Field | Type | Description | | - | - | - | | name | [ string](#string) | The name the query writes, lowercase and canonical. Function names compile case-insensitively, so `WITH_TYPE` reaches the same function as `with_type`. | | category | [ string](#string) | Which job this function does, one of the values in `categories`. Use it to group the catalog the way the product does rather than inventing an order. | | doc | [ string](#string) | What the function selects, in one sentence. Written for a person choosing between functions; safe to show verbatim. | | variadic | [ bool](#bool) | Whether the function accepts more arguments than it declares. A variadic function with no declared arguments — `and`, `or` — takes any number of sub-queries. | | default\_kwarg | [ string](#string) | The keyword argument a bare positional value is routed to when the call names none. Empty when the function has no such argument. | | positional | [repeated ResolverQlArg](#resolverqlarg) | Arguments in the order they are written before any `name=value` argument. | | kwargs | [repeated ResolverQlArg](#resolverqlarg) | Arguments written as `name=value`, ordered by name. An argument that can be written either way appears in `positional` only. | ### EntityIds (synq.queries.v1.EntityIds) Selects exactly the entities you list, by the `entity_id` the API returned for each of them. This is the pin-these-specific-entities part of a query: the assets a user ticked in a list, the results of a search you just ran, the entities another API call handed you. Because you pass the ids back as they were given, you do not need to know what kind of entity each one is, or how its address in the source system is spelled. `identifier_list` is the alternative, and the choice between them is about what you have in hand: * `entity_ids` — you are holding ids the API gave you. Pass them through unchanged. * `identifier_list` — you are naming entities by their address in the source system (a BigQuery project/dataset/table, a dbt model, a Looker explore), for example because a person or a config file wrote it down rather than an API call. **Reading back a selection you wrote with `entity_ids`.** Selections are always returned as `identifier_list`, whichever of the two you sent — one uniform shape, so integrations built before `entity_ids` existed keep reading stored queries unchanged. Your ids are not lost in the process: every returned identifier carries its `entity_id`, so you can match each one back to what you sent, and compare a saved selection against the one you are about to save. The returned id is the entity's canonical form, which can differ from an equivalent spelling you sent for the same entity. **An id that matches nothing selects nothing**, and is not an error — so a saved query keeps working after one of the entities it names is deleted or renamed, rather than failing every time it is read or resolved. | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | The entities to select. An id may not be blank. | An empty list selects no entities, exactly as an empty `identifier_list` does. Be deliberate about it, because it is not the same as leaving the part out: a part that selects nothing still counts, so it empties an AND, adds nothing to an OR, and removes nothing from an EXCEPT. If what you mean is "do not restrict on specific entities", omit the part instead of sending it empty. Ids may be up to 1024 characters — the same limit as `Identifier.entity_id`, where you read them from, so any id the API returned is accepted here. | ### 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. The name and the values match case-insensitively. | 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, or carry one of the provided traits. | Field | Type | Description | | - | - | - | | type | [ Type](#type) | none | | types | [repeated Type](#type) | none | | traits | [repeated string](#string) | Traits to select by, instead of — or alongside — naming types. | A trait is a property a type has, so `is_monitorable` means "everything a monitor can run on" without listing the forty-odd types that satisfy it today. The list it stands for is worked out each time the selection runs, so a selection saved this way covers a new platform's tables as soon as we support them, and you never have to revisit it. Entities carrying any of the traits match. When `types` is also set the two narrow each other: the entity must be one of the named types AND carry one of the traits. Accepted values, and what each one means, come from the selection-query grammar the API publishes (`describe_resolver_ql`, or the query editor's reference). A name that is not in it selects nothing rather than being ignored, so a typo narrows the result to empty instead of widening it — check a trait against the grammar before storing a selection. In a query written as text this is `with_type(traits="is_monitorable")`, and there a name outside the grammar is rejected outright. A trait may also be a type alias, spelled `alias:` where `` is one of the aliases the grammar lists among the entity types, e.g. `alias:table`. It selects every type the alias stands for, worked out each time the selection runs like any other trait. A selection written as `with_type("table")` is stored this way and reads back with `traits: ["alias:table"]`; writing that back keeps the same selection. In a query written as text an alias is always `with_type("table")`, never `traits="alias:table"`. | ### 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 | ### 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. | ### 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 | ### 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 | ### DeleteCommentRequest (synq.incidents.v1.DeleteCommentRequest) | Field | Type | Description | | - | - | - | | incident\_id | [ string](#string) | ID of the incident the comment is on. | | comment\_id | [ string](#string) | ID of the comment to delete, as returned by PostComment or read from the incident's comments. | | actor | [ Actor](#actor) | Actor deleting the comment. Must match the actor that posted it. | ### DeleteCommentResponse (synq.incidents.v1.DeleteCommentResponse) ### 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 | ### BatchGetEntityOverlaysRequest (synq.overlays.v1.BatchGetEntityOverlaysRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | The entities to ask about: 1 to 1000 ids, no duplicates. | An `entity_id` is opaque. Take one from any listing or search response, or from `synq.entities.resolve.v1.IdentifierResolveService` if what you hold is a warehouse table name or a model name, and pass it back unchanged. Do not build one yourself or parse one apart — the format carries no meaning you can rely on and is not part of this contract. | ### BatchGetEntityOverlaysResponse (synq.overlays.v1.BatchGetEntityOverlaysResponse) | Field | Type | Description | | - | - | - | | entities | [repeated EntityOverlays](#entityoverlays) | One entry per requested entity, in the order they were requested. | ### BatchGetOverlayMemberCountsRequest (synq.overlays.v1.BatchGetOverlayMemberCountsRequest) | Field | Type | Description | | - | - | - | | overlay\_entity\_ids | [repeated string](#string) | The overlays to count: 1 to 1000 ids, no duplicates. | Opaque ids, as returned by `BatchGetEntityOverlays` or by the listing calls of the service that defines the overlay. Data products and owners may be mixed freely in one request. | ### BatchGetOverlayMemberCountsResponse (synq.overlays.v1.BatchGetOverlayMemberCountsResponse) | Field | Type | Description | | - | - | - | | overlays | [repeated OverlayMemberCount](#overlaymembercount) | One entry per requested overlay, in the order they were requested. | ### CoverageSelection (synq.overlays.v1.CoverageSelection) CoverageSelection names the assets a coverage question is asked about. It is a candidate set, not a filter on overlays: nothing outside it is considered, and an asset inside it is reported whether anything claims it or not. `with_type("dbt_model")` asks about your models, `in_folder(...)` asks about one part of the warehouse, and an empty candidate set is a valid question with the answer zero. Choose the candidate types deliberately — it is the difference between a useful answer and an unreadable one. The two dimensions want different sets. Data products group the things you monitor, so a product-coverage question usually asks about tables, views and models; left unrestricted the answer is mostly monitors, tests and recon cases, which belong to no product by design and bury the assets you were looking for. Owner coverage is the opposite: a check very often should have someone responsible for it, so include those types when asking about owners. So a governance audit is normally several narrow selections rather than one broad one — which is also what `GetCoverageSummary` takes, one per bucket. A selection resolving to more than 100,000 assets is rejected with INVALID\_ARGUMENT naming the limit; narrow it and ask again. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.resolver\_ql | [ string](#string) | The candidate query in resolver query language. The fuller of the two forms — everything the structured query expresses is expressible here, and several filters are only expressible here. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.public\_query | [ Query](#query) | The candidate query in structured form, as the filter builder produces it. Use `resolver_ql` for anything it cannot express. | ### CoverageSummary (synq.overlays.v1.CoverageSummary) CoverageSummary is one selection's totals. The counts overlap rather than partition: an asset in a product and with an owner is in `with_dataproduct`, in `with_owner` and in `with_both`. Only `with_neither` is disjoint from the rest. So the uncovered counts are `total - with_dataproduct` and `total - with_owner`, and "in a product but unowned" is `with_dataproduct - with_both`. | Field | Type | Description | | - | - | - | | key | [ string](#string) | The key of the selection this row answers for, echoed back. | | total | [ int64](#int64) | Candidates in the selection. | | with\_dataproduct | [ int64](#int64) | Candidates in at least one data product. | | with\_owner | [ int64](#int64) | Candidates with at least one owner. | | with\_both | [ int64](#int64) | Candidates in at least one data product *and* with at least one owner. | | with\_neither | [ int64](#int64) | Candidates nothing claims — the gap a coverage audit is looking for. | ### EntityOverlays (synq.overlays.v1.EntityOverlays) EntityOverlays is one entity and the overlays claiming it, one list per kind. Kinds are separate lists rather than one tagged list because what you can do with an id depends on its kind: an owner id reads through the owners service, a data-product id through the data-products service. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The entity this entry answers for, echoed back from the request. | | owner\_entity\_ids | [repeated string](#string) | Owners responsible for this entity — the parties an alert about it reaches. Read their names and contact channels with `synq.owners.v1.OwnersService`. | Empty when no owner claims the entity, and also when your credential may not read owners. Order is not significant and may change between calls; sort if you display them. | \| dataproduct\_entity\_ids | [repeated string](#string) | Data products this entity belongs to. Read their names and definitions with `synq.dataproducts.v2.DataproductsService`. Empty when the entity is in no data product, and also when your credential may not read data products. Order is not significant and may change between calls; sort if you display them. | ### GetCoverageSummaryRequest (synq.overlays.v1.GetCoverageSummaryRequest) | Field | Type | Description | | - | - | - | | selections | [repeated NamedSelection](#namedselection) | The candidate sets to count: 1 to 20, with distinct keys. | | freshness | [ Freshness](#freshness) | Where the answer is computed from. Defaults to the recomputed membership. | `FRESHNESS_LIVE` re-resolves every definition once for the whole request, not once per selection, so several selections cost little more than one. | ### GetCoverageSummaryResponse (synq.overlays.v1.GetCoverageSummaryResponse) | Field | Type | Description | | - | - | - | | summaries | [repeated CoverageSummary](#coveragesummary) | One entry per requested selection, in the order they were requested. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_members\_computed\_at.members\_computed\_at | [optional Timestamp](#timestamp) | When the recomputation behind these totals last ran to completion — the start of the most recent successful pass over the workspace's overlays. | Absent under `FRESHNESS_LIVE`, and absent when the workspace has no overlay of a readable kind, or none has been computed yet. | ### ListEntityCoverageRequest (synq.overlays.v1.ListEntityCoverageRequest) | Field | Type | Description | | - | - | - | | selection | [ CoverageSelection](#coverageselection) | The assets to report on. Required. | | filter | [ CoverageFilter](#coveragefilter) | Which coverage state to keep. Defaults to all candidates. | A filter naming a kind your credential may not read is PERMISSION\_DENIED rather than an empty list. | \| freshness | [ Freshness](#freshness) | Where the answer is computed from. Defaults to the recomputed membership. | \| pagination | [ Pagination](#pagination) | Pagination over the candidates matching `filter`. | ### ListEntityCoverageResponse (synq.overlays.v1.ListEntityCoverageResponse) | Field | Type | Description | | - | - | - | | entities | [repeated EntityOverlays](#entityoverlays) | One page of matching candidates, each with the overlays claiming it. | The same message `BatchGetEntityOverlays` returns: a row under `COVERAGE_FILTER_WITHOUT_DATAPRODUCT` has an empty `dataproduct_entity_ids` and may still name owners, which is how "owned but in no product" reads without a second call. | \| total\_count | [ int64](#int64) | How many candidates match `filter` across every page. Independent of pagination — the number to show beside a list, not the length of it. | \| page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. | \| rendered\_resolver\_ql | [ string](#string) | The candidate selection rendered back to canonical resolver query language, whichever form it was sent in. Useful to log what was actually asked, and to lift a query built with the structured form into one you can hand-edit. Empty when the selection has no resolver-QL representation; the answer is unaffected. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_members\_computed\_at.members\_computed\_at | [optional Timestamp](#timestamp) | When the recomputation behind this answer last ran to completion — the start of the most recent successful pass over the workspace's overlays. Every overlay is recomputed on each pass, so this is the age of the whole answer rather than of any one overlay in it. This is the number to alert on: it stops advancing as soon as the recomputation stops succeeding, whether or not any membership has changed. Absent under `FRESHNESS_LIVE` (nothing was read from an index), and absent when no overlay of a readable kind exists in the workspace, or none has been computed yet (there is no membership to be stale). | ### NamedSelection (synq.overlays.v1.NamedSelection) NamedSelection is one candidate set and the label you want its row keyed by. | Field | Type | Description | | - | - | - | | key | [ string](#string) | Your own label for this selection, echoed back on the matching summary. It is never interpreted — use whatever names the bucket in your dashboard. Must be unique within the request. | | selection | [ CoverageSelection](#coverageselection) | The assets this row counts. Required. | ### OverlayMemberCount (synq.overlays.v1.OverlayMemberCount) | Field | Type | Description | | - | - | - | | overlay\_entity\_id | [ string](#string) | The overlay this entry answers for, echoed back from the request. | | member\_count | [ int64](#int64) | How many distinct entities belong to it. | Zero covers every case where there is nothing to count: an overlay with no members, an id that does not exist, and an id your credential may not read. If you need to tell those apart, read the overlay itself through the service that defines it. | ### 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. | ### 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. | ### 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) | Table name for storing SQL test audit logs (e.g., 'sql\_test\_audit'). Auto-creation quotes the value as a single identifier, so a schema-qualified name only works against a table you have created yourself. | ### 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. | ### 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. | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.db2 | [ Db2CloudConf](#db2cloudconf) | IBM Db2 for Linux, UNIX and Windows 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. | ### 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) | Database the connection opens with, so unqualified table names in a query resolve against it. It is not a scrape filter: metadata is read from system tables and covers every database the credentials can see, whatever this says. | | 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) | Name this ClickHouse is published under, and the top element of every path and breadcrumb its tables appear in — `prod`, `staging`, `eu-analytics`. ClickHouse has no container above a database, so something has to name the service; left empty that is the connection host, which is correct but unreadable for a ClickHouse Cloud endpoint. It is not a database and does not restrict what is scraped. Changing it republishes every table under new paths, so pick one per service and keep it. | | [**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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_cluster.cluster | [optional ClickhouseClusterConf](#clickhouseclusterconf) | How ClickHouse system tables are read. Omit to keep reading across a cluster named "default", which every ClickHouse Cloud service provides. | ### ClickhouseCloudConf.AdditionalParametersEntry (synq.integrations.v1.ClickhouseCloudConf.AdditionalParametersEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ string](#string) | none | ### ClickhouseClusterConf (synq.integrations.v1.ClickhouseClusterConf) How metadata reads address ClickHouse system tables. System tables are per-node, so on a service with more than one replica a plain read reflects whichever replica answered rather than the whole warehouse. | Field | Type | Description | | - | - | - | | mode | [ ClickhouseClusterMode](#clickhouseclustermode) | none | | name | [ string](#string) | Cluster to read through, as named under remote\_servers in the ClickHouse configuration. `SELECT DISTINCT cluster FROM system.clusters` lists what a server has. Empty means "default". Ignored in single-node mode. | ### 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`. | ### 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. | ### 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) | Table name for storing SQL test audit logs (e.g., 'sql\_test\_audit'). Auto-creation quotes the value as a single identifier, so a schema-qualified name only works against a table you have created yourself. | ### 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. | ### 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. | ### 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. | ### 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). | ### 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. | ### 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. | ### Db2CloudConf (synq.integrations.v1.Db2CloudConf) IBM Db2 for Linux, UNIX and Windows (Db2 LUW) connection. Each integration opens one database, the one you would name in `CONNECT TO `. An instance can hold several databases, each with its own SYSCAT catalog views, so add an integration for every database you want to monitor. The keyword in parentheses after each field is the matching keyword of a Db2 CLI connection string, db2cli.ini or db2dsdriver.cfg, and values are the same, so you can copy them from a data source you already use. Db2 for z/OS and Db2 for i are not supported. Fields are optional so an update can carry only what changes (omit = leave unchanged). The password is write-only (masked on reads); omit it to keep the stored one or send a new value to rotate it. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_hostname.hostname | [optional string](#string) | Host name or IP address of the Db2 server (HOSTNAME). | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_port.port | [optional int32](#int32) | TCP/IP port of the instance (PORT): the value of the SVCENAME database manager configuration parameter, or SSL\_SVCENAME when security is "SSL" (`db2 get dbm cfg`). Defaults to 50000, or 50001 when security is "SSL". | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_database.database | [optional string](#string) | Database name or alias (DATABASE), as in `CONNECT TO `. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user.user | [optional string](#string) | Authorization ID to connect with (UID). Db2 checks it through the instance's security plugin: against the server's operating system by default, or against LDAP when an LDAP plugin is configured. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_password.password | [optional string](#string) | Password of the authorization ID (PWD). Write-only, masked on reads. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_security.security | [optional string](#string) | Set to "SSL" to connect over SSL/TLS (SECURITY=SSL). The instance needs SSL\_SVCENAME set and SSL listed in DB2COMM. Leave empty for a plain TCP/IP connection. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_ssl\_server\_certificate\_pem.ssl\_server\_certificate\_pem | [optional string](#string) | The server's certificate, or the certificate of the CA that signed it, in PEM format: the text starting with "-----BEGIN CERTIFICATE-----". The .arm file you get from the instance's keystore with `gsk8capicmd_64 -cert -extract` holds exactly this. Needs security set to "SSL". Leave empty to check the server against the public certificate authorities. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_authentication.authentication | [optional string](#string) | How the authorization ID and password travel to the server (AUTHENTICATION). The values match the database manager configuration parameter of the same name: - "SERVER" (default): sent unencrypted. Use it with security "SSL" on an untrusted network. - "SERVER\_ENCRYPT": sent encrypted. The instance's AUTHENTICATION must accept encrypted credentials, for example SERVER\_ENCRYPT. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fetch\_query\_logs.fetch\_query\_logs | [optional bool](#bool) | Read query history from the package cache (MON\_GET\_PKG\_CACHE\_STMT). The authorization ID needs EXECUTE on that table function. | | [**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. | ### ScopeAuthorization (synq.v1.ScopeAuthorization) | Field | Type | Description | | - | - | - | | scopes | [repeated Scope](#scope) | none | ### 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. | ### 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. | ### 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.db2 | [ Db2Identifier](#db2identifier) | 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 | ### Db2Identifier (synq.platforms.v1.Db2Identifier) IBM Db2 for Linux, UNIX and Windows. An integration connects to one database, so host and database together identify it. | Field | Type | Description | | - | - | - | | host | [ string](#string) | Host name of the Db2 server | | database | [ string](#string) | Database name or alias, as in `CONNECT TO ` | ### 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) ### 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 | ### 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 | ### BatchGetDeliveriesRequest (synq.deliveries.v1.BatchGetDeliveriesRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | Delivery ids to fetch (1–200, unique), as returned by `ListDeliveries`, `Redeliver` or `SendTestDelivery`. | ### BatchGetDeliveriesResponse (synq.deliveries.v1.BatchGetDeliveriesResponse) | Field | Type | Description | | - | - | - | | deliveries | [map DeliveriesEntry](#deliveriesentry) | The deliveries found, keyed by id. Ids that do not exist are absent. | ### BatchGetDeliveriesResponse.DeliveriesEntry (synq.deliveries.v1.BatchGetDeliveriesResponse.DeliveriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ Delivery](#delivery) | none | ### GetDeliveryRequest (synq.deliveries.v1.GetDeliveryRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Delivery id. | ### GetDeliveryResponse (synq.deliveries.v1.GetDeliveryResponse) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_delivery.delivery | [optional Delivery](#delivery) | The delivery. Absent when there is none with that id. | ### ListAttemptsRequest (synq.deliveries.v1.ListAttemptsRequest) | Field | Type | Description | | - | - | - | | delivery\_id | [ string](#string) | Delivery whose attempts to list. | ### ListAttemptsResponse (synq.deliveries.v1.ListAttemptsResponse) | Field | Type | Description | | - | - | - | | attempts | [repeated Attempt](#attempt) | Every attempt made, oldest first. Empty for a delivery that sent nothing, and for one still waiting on its first attempt. | ### ListDeliveriesRequest (synq.deliveries.v1.ListDeliveriesRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Restrict to one integration. Omit for the whole workspace's feed. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_event\_id.event\_id | [optional string](#string) | Restrict to one event — every integration it reached, and what each did with it. This is the `event_id` from a received webhook payload. Setting it searches everything still retained, ignoring `since` and `until`. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_subject\_id.subject\_id | [optional string](#string) | Restrict to the issue or incident the delivery was about. Takes the same identifier the rest of the API uses for that object. Setting it searches everything still retained, ignoring `since` and `until`. | | event\_types | [repeated string](#string) | Restrict to these event types, by `synq.webhooks.v1.Event.EventType` name. Empty matches every type. | | outcomes | [repeated Outcome](#outcome) | Restrict to these outcomes. Empty matches every outcome. | | status\_codes | [repeated int32](#int32) | Restrict to deliveries whose most recent attempt returned one of these HTTP statuses. Empty matches every status. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_since.since | [optional Timestamp](#timestamp) | Only deliveries for events at or after this time. Defaults to the start of the retention window, and is ignored when `event_id` or `subject_id` names what to return. Note that this bounds the event time, which for an issue is when the issue began rather than when the delivery was sent. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_until.until | [optional Timestamp](#timestamp) | Only deliveries for events strictly before this time. Defaults to now, and is ignored when `event_id` or `subject_id` names what to return. | | pagination | [ Pagination](#pagination) | Pagination. Deliveries are returned newest event first; pass the `last_id` of the previous page as the cursor. | | include\_routing | [ bool](#bool) | Also return `matched_alert_configs` and `correlation_key` on each delivery. Off by default: it costs a second read per delivery, and a feed rarely needs it. `BatchGetDeliveries` always returns them. | ### ListDeliveriesResponse (synq.deliveries.v1.ListDeliveriesResponse) | Field | Type | Description | | - | - | - | | deliveries | [repeated Delivery](#delivery) | The matching deliveries, newest event first. | | page\_info | [ PageInfo](#pageinfo) | Cursor for the next page. | ### OutcomeCount (synq.deliveries.v1.OutcomeCount) | Field | Type | Description | | - | - | - | | outcome | [ Outcome](#outcome) | none | | count | [ int32](#int32) | none | ### RedeliverRequest (synq.deliveries.v1.RedeliverRequest) | Field | Type | Description | | - | - | - | | delivery\_id | [ string](#string) | Delivery to send again. | ### RedeliverResponse (synq.deliveries.v1.RedeliverResponse) | Field | Type | Description | | - | - | - | | delivery\_id | [ string](#string) | Id of the delivery created by the replay. Poll `BatchGetDeliveries` with it to follow the outcome. | ### SendTestDeliveryRequest (synq.deliveries.v1.SendTestDeliveryRequest) | Field | Type | Description | | - | - | - | | integration\_id | [ string](#string) | Integration to send the test to. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_message.message | [optional string](#string) | Message to carry in the test payload, so a test can be recognised on the receiving end. Defaults to a generic one. | ### SendTestDeliveryResponse (synq.deliveries.v1.SendTestDeliveryResponse) | Field | Type | Description | | - | - | - | | delivery\_id | [ string](#string) | Id of the delivery created. Poll `BatchGetDeliveries` with it to follow the outcome. | ### SkipReasonCount (synq.deliveries.v1.SkipReasonCount) | Field | Type | Description | | - | - | - | | skip\_reason | [ SkipReason](#skipreason) | none | | count | [ int32](#int32) | none | ### StatusClassCount (synq.deliveries.v1.StatusClassCount) | Field | Type | Description | | - | - | - | | status\_class | [ StatusClass](#statusclass) | none | | count | [ int32](#int32) | none | ### SummariseDeliveriesRequest (synq.deliveries.v1.SummariseDeliveriesRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_integration\_id.integration\_id | [optional string](#string) | Restrict to one integration. Omit to summarise the whole workspace. | | since | [ Timestamp](#timestamp) | Start of the window, on event time. Required — a summary of everything kept is rarely the question, and always the most expensive one. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_until.until | [optional Timestamp](#timestamp) | End of the window, on event time. Defaults to now. | ### SummariseDeliveriesResponse (synq.deliveries.v1.SummariseDeliveriesResponse) | Field | Type | Description | | - | - | - | | since | [ Timestamp](#timestamp) | The window actually summarised, after defaults were applied. | | until | [ Timestamp](#timestamp) | none | | total | [ int32](#int32) | Deliveries in the window, whatever became of them. | | by\_outcome | [repeated OutcomeCount](#outcomecount) | Counts per outcome. Outcomes with no deliveries are omitted. | | by\_status\_class | [repeated StatusClassCount](#statusclasscount) | Counts per HTTP status class of the most recent attempt. Deliveries that were never attempted are omitted rather than counted as a class. | | by\_skip\_reason | [repeated SkipReasonCount](#skipreasoncount) | Counts per reason for sending nothing. Only over the deliveries counted as `OUTCOME_SKIPPED` or `OUTCOME_NOT_ROUTED`. | ### Attempt (synq.deliveries.v1.Attempt) Attempt is one try at handing a delivery to its destination, recorded as it happened: what was sent, what came back, and how long it took. A delivery can produce more than one outgoing request — an integration that creates an object and then annotates it makes two — and each request is retried on its own. Attempts of the same request share `request_id` and count up in `attempt`. | Field | Type | Description | | - | - | - | | delivery\_id | [ string](#string) | The delivery this attempt belongs to. | | attempt | [ int32](#int32) | Which try this was for `request_id`, starting at 1. | | request\_id | [ string](#string) | Opaque identifier of the outgoing request. Group attempts by it to follow one request's retries; compare it to tell two requests of the same delivery apart. | | attempted\_at | [ Timestamp](#timestamp) | When the attempt started. | | duration | [ Duration](#duration) | How long it took, whether it succeeded or failed. | | error | [ string](#string) | Why the attempt never produced a response — a connection failure, a TLS error, a timeout. Empty when a response was received, however it read. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) transport.http | [ HttpAttempt](#httpattempt) | none | ### Header (synq.deliveries.v1.Header) Header is one HTTP header of an attempt. A header whose value carries a credential is never returned, on either the request or the response side. That covers headers you configured as secret, credentials held for the destination, and the standard credential-bearing names (`Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, `X-Auth-Token`) whatever their contents — a destination echoing its own authorization header back is withheld too. Signature headers are returned in full: `X-Coalesce-Signature` is a digest of the body and `X-Coalesce-Timestamp` is a timestamp, neither of which is the signing secret, and the exact bytes are what you need to reproduce a verification that failed. | Field | Type | Description | | - | - | - | | name | [ string](#string) | Header name, as sent. | | value | [ string](#string) | Header value. Empty when `withheld` is set. | | withheld | [ bool](#bool) | Whether the value was withheld. The header itself is still reported, so the record shows which headers were present. | | fingerprint | [ string](#string) | Short digest of a withheld value, stable for the same value. Enough to answer "is this the same token as the one that worked yesterday" by comparing two deliveries, without disclosing either value. | | secret\_version | [ string](#string) | Which version of the stored secret the withheld value was read from, so a delivery can be attributed to a specific secret across a rotation. Empty for values that come from no stored secret. | ### HttpAttempt (synq.deliveries.v1.HttpAttempt) HttpAttempt is one HTTP request and the response it got. Credential-bearing headers are never returned, whichever side they appear on — see `Header`. | Field | Type | Description | | - | - | - | | method | [ string](#string) | Method used, upper-case. | | url | [ string](#string) | Full URL the request was sent to, query string included. | | request\_headers | [repeated Header](#header) | Headers as sent. | | request\_body | [ string](#string) | Body as sent. A value the destination requires to be secret — a routing key, for instance — is replaced by a marker naming the field it stood in, so the record shows that a value was sent rather than implying none was. | | request\_bytes | [ int32](#int32) | Size of the body actually sent, in bytes, before any such substitution. | | status\_code | [ int32](#int32) | HTTP status returned. Zero when no response arrived; `error` on the attempt then says why. | | response\_headers | [repeated Header](#header) | Headers the destination returned. | | response\_body | [ string](#string) | Body the destination returned, cut short past a fixed size — see `response_truncated`. | | response\_bytes | [ int32](#int32) | Size of the response body as the destination sent it, before truncation. | | response\_truncated | [ bool](#bool) | Whether `response_body` was cut short. When set, `response_bytes` is the full size and `response_body` holds the leading bytes. | ### Delivery (synq.deliveries.v1.Delivery) Delivery is one event as it was addressed to one integration: what it was about, whether it went, and what happened when it did. One event reaches every integration subscribed to it, so an event that fans out to three integrations produces three deliveries. They share `event_id` and each has its own `id`. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Opaque identifier of this delivery, composed by the service. Pass it back to `BatchGetDeliveries`, `ListAttempts` and `Redeliver`; do not parse it or build one yourself, as its composition can change. | | event\_id | [ string](#string) | Identifier of the event this delivery carries, shared by every integration the same event reached. Filter `ListDeliveries` on it to answer "which of my integrations did this event reach, and what did each of them do with it". It is also the `event_id` in the webhook payload a receiver got, so a customer holding a received webhook can find its delivery from it. | | integration\_id | [ string](#string) | The integration this delivery was addressed to. | | event\_type | [ string](#string) | Name of the `synq.webhooks.v1.Event.EventType` the delivery carries — for example `EVENT_TYPE_ISSUE_CREATED`. Empty when the event has no representation for this kind of integration. | | subject | [ DeliverySubject](#deliverysubject) | What the event is about, so a delivery can be found from the issue or incident a question is asked about. | | created\_at | [ Timestamp](#timestamp) | When the event happened. This is the event time, not the time it was sent — `last_attempt_at` is that. Deliveries are listed newest event first. | | outcome | [ Outcome](#outcome) | What became of the delivery. | | skip\_reason | [ SkipReason](#skipreason) | Why nothing was sent. Set exactly when `outcome` is `OUTCOME_SKIPPED` or `OUTCOME_NOT_ROUTED`. | | attempt\_count | [ int32](#int32) | How many attempts have been made so far, across every request this delivery produced. Zero for a delivery that sent nothing, and for one still queued. | | last\_attempt\_at | [ Timestamp](#timestamp) | When the most recent attempt started. Unset until the first attempt. | | next\_attempt\_at | [ Timestamp](#timestamp) | When the next attempt is due. Set only while `outcome` is `OUTCOME_PENDING`; an attempt can still start slightly later than this under load. | | duration | [ Duration](#duration) | How long the attempts took in total. Useful as "how long did this take to land" rather than as a measure of one request. | | status\_code | [ int32](#int32) | HTTP status of the most recent attempt. Zero when no response was received — either nothing has been sent yet, or the request failed before one arrived, in which case the attempt carries the transport error. | | redelivery\_of | [ string](#string) | The delivery this one replays, set when it was produced by `Redeliver`. Empty for a first delivery. | | matched\_alert\_configs | [repeated MatchedAlertConfig](#matchedalertconfig) | Which alert configurations selected this integration for this event — the answer to "why did I get this". More than one when several configurations match the same event, because their alerts are merged into a single delivery per integration. Empty for deliveries not produced by alerting, such as a test delivery. | Always populated by `BatchGetDeliveries`; populated by `ListDeliveries` only when the request sets `include_routing`. | \| correlation\_key | [ string](#string) | The key the destination deduplicates on — a PagerDuty `dedup_key`, an Opsgenie `alias` — so an incident in your own tool can be traced back to the delivery that opened it. Empty for destinations that create no such object. Populated on the same terms as `matched_alert_configs`. | ### DeliverySubject (synq.deliveries.v1.DeliverySubject) DeliverySubject is the object an event is about. | Field | Type | Description | | - | - | - | | type | [ SubjectType](#subjecttype) | Which kind of object `id` refers to. | | id | [ string](#string) | Identifier of the issue or incident, as the rest of the API uses it. For a test delivery this is the event id, since a test is about nothing else. | | title | [ string](#string) | Title at the time the delivery was decided, kept so a delivery stays readable after the issue is renamed or closed. | | url | [ string](#string) | Link to the object in the app. Empty when the subject has no page. | ### MatchedAlertConfig (synq.deliveries.v1.MatchedAlertConfig) MatchedAlertConfig names one alert configuration that selected an integration for an event. | Field | Type | Description | | - | - | - | | alert\_config\_id | [ string](#string) | Identifier of the alert configuration. | | name | [ string](#string) | Its name when the delivery was decided, so the delivery stays attributable after the configuration is renamed or deleted. | | fqn | [ string](#string) | Fully-qualified name, set only for configurations managed as code. | | ownership\_id | [ string](#string) | The ownership the configuration belongs to. Empty for workspace-level configurations. | | owner\_path | [ string](#string) | The owner the integration was reached through. Empty when the configuration names the integration directly rather than routing to an owner. | ### 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. | ### 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) \_retriage\_instruction\_response.retriage\_instruction\_response | [optional RetriageInstructionResponse](#retriageinstructionresponse) | How this conclusion used the retriage instructions a person gave for the issue. Set only when the triage that produced it was given instructions. | | [**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 ### RetriageInstructionResponse (synq.agent.sre.v1.RetriageInstructionResponse) RetriageInstructionResponse ties a conclusion to the retriage instructions that produced it, so the instructions and what the agent did with them are read side by side. | Field | Type | Description | | - | - | - | | instructions | [repeated string](#string) | The instructions the triage was given, verbatim, in the order they were submitted. | | response | [ string](#string) | Markdown statement of how the instructions changed the analysis, or why they did not, including the answer when an instruction asked a question. Empty when the agent concluded without addressing them. | ### 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. ### 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 | ### 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 | ### 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. | ### 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 | ### 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. ### 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. ### 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) ### 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 | ### 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. | | thinking\_effort | [ string](#string) | How long the thinking model deliberates before each answer: "none" (answer without thinking first), "low", "medium" or "high". Empty leaves it to the deployment default. It is a cost decision, not a capability one — the agent works at every level. | Free-form rather than an enum because the levels belong to whichever provider serves the model, and they keep being added. The value reaches the provider as given, so a level this build has never heard of works; one the model refuses is dropped for that request and logged. | ### 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. | ### 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 | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.db2 | [ Db2Conf](#db2conf) | none | ### 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. | | login | [ string](#string) | Login the connection runs its queries as, spelled as the platform's query history names the user: a user name, a service account's email, a service principal's client id. Empty when the configuration names none and only the credential knows it, such as an access token. | ### Log (synq.agent.dwh.v1.Log) | Field | Type | Description | | - | - | - | | time | [ Timestamp](#timestamp) | none | | message | [ string](#string) | none | | level | [ LogLevel](#loglevel) | 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. | ### ClickhouseClusterConf (synq.agent.dwh.v1.ClickhouseClusterConf) How metadata reads address ClickHouse system tables. System tables are per-node, so on a service with more than one replica a plain read reflects whichever replica answered rather than the whole warehouse. | Field | Type | Description | | - | - | - | | mode | [ ClickhouseClusterMode](#clickhouseclustermode) | none | | name | [ string](#string) | Cluster to read through, as named under remote\_servers in the ClickHouse configuration. `SELECT DISTINCT cluster FROM system.clusters` lists what a server has. Empty means "default". Ignored in single-node mode. | ### 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 the connection opens with, so unqualified table names in a query resolve against it. It does not restrict what is scraped: metadata is read from system tables and covers every database the user can see, whatever this says. Leave it empty to open on "default". | | username | [ string](#string) | Username for authentication | | password | [ string](#string) | Password for authentication | | allow\_insecure | [ bool](#bool) | Whether to use disable SSL for connection | | settings | [map SettingsEntry](#settingsentry) | ClickHouse server settings applied to every connection, written as they would be in a DSN query string (e.g. "max\_execution\_time": "300"). Values are typed the way ClickHouse types them in a connection string: "true" and "false" become 1 and 0, whole numbers become integers, anything else is passed through as text. A name given here replaces the value the agent would otherwise use. | | cluster | [ ClickhouseClusterConf](#clickhouseclusterconf) | How ClickHouse system tables are read. Omit to keep reading across a cluster named "default", which every ClickHouse Cloud service provides. | | instance\_name | [ string](#string) | Name this ClickHouse is published under, and the top element of every path and breadcrumb its tables appear in — `prod`, `staging`, `eu-analytics`. | ClickHouse has no container above a database, so something has to name the service itself. Left empty, that is the connection host, which is correct but unreadable for a ClickHouse Cloud endpoint; a name given here replaces it. Two connections to the same service must give the same name, and a name is the identity of everything scraped through it: changing it republishes those tables under new paths, and the old ones are no longer produced. Pick one per service and keep it. | ### ClickhouseConf.SettingsEntry (synq.agent.dwh.v1.ClickhouseConf.SettingsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ string](#string) | none | ### 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 | ### Db2Conf (synq.agent.dwh.v1.Db2Conf) IBM Db2 for Linux, UNIX and Windows (Db2 LUW) configuration. Each connection opens one database, the one you would name in `CONNECT TO `. An instance can hold several databases, each with its own SYSCAT catalog views, so add a connection for every database you want to monitor. The keyword in parentheses after each field is the matching keyword of a Db2 CLI connection string, db2cli.ini or db2dsdriver.cfg. Values are the same, so you can copy them from a data source you already use. You don't need to install a Db2 client, Data Server Driver or clidriver. Db2 for z/OS and Db2 for i are not supported. | Field | Type | Description | | - | - | - | | hostname | [ string](#string) | Host name or IP address of the Db2 server (HOSTNAME). | | port | [ int32](#int32) | TCP/IP port of the instance (PORT): the value of the SVCENAME database manager configuration parameter, or SSL\_SVCENAME when security is "SSL" (`db2 get dbm cfg`). Defaults to 50000, or 50001 when security is "SSL". | | database | [ string](#string) | Database name or alias (DATABASE), as in `CONNECT TO `. | | user | [ string](#string) | Authorization ID to connect with (UID). Db2 checks it through the instance's security plugin: against the server's operating system by default, or against LDAP when an LDAP plugin is configured. | | password | [ string](#string) | Password of the authorization ID (PWD). | | security | [ string](#string) | Set to "SSL" to connect over SSL/TLS (SECURITY=SSL). The instance needs SSL\_SVCENAME set and SSL listed in DB2COMM. Leave empty for a plain TCP/IP connection. | | ssl\_server\_certificate\_file | [ string](#string) | Path to the server's certificate, or the certificate of the CA that signed it, in PEM format (SSLServerCertificate). The .arm file you get from the instance's keystore with `gsk8capicmd_64 -cert -extract` works as is. The file must exist on the machine that connects to Db2. When it can't, paste the certificate into ssl\_server\_certificate\_pem instead. Needs security set to "SSL". Leave both empty to check the server against the system trust store. | | ssl\_server\_certificate\_pem | [ string](#string) | Content of the same certificate, starting with "-----BEGIN CERTIFICATE-----", for when you can't point to a file. Needs security set to "SSL". | | authentication | [ string](#string) | How the authorization ID and password travel to the server (AUTHENTICATION). The values match the database manager configuration parameter of the same name: - "SERVER" (default): sent unencrypted. Use it with security "SSL" on an untrusted network. - "SERVER\_ENCRYPT": sent encrypted. The instance's AUTHENTICATION must accept encrypted credentials, for example SERVER\_ENCRYPT. | ### 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 4. integrated\_auth: the Windows or Kerberos identity of the machine running the connection | 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. | | integrated\_auth | [ bool](#bool) | Sign in with the identity of the user running the connection instead of a SQL Server login, the same as `sqlcmd -E` (Windows Authentication). On Windows this uses the logged-in user's credentials (SSPI). On macOS and Linux it uses the Kerberos ticket from `kinit`: the credential cache named by KRB5CCNAME (a file), or /tmp/krb5cc\_\, with the Kerberos configuration from KRB5\_CONFIG or /etc/krb5.conf. Leave username, password, access\_token and fed\_auth empty. | ### 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 | ### 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 | ### 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 | ### 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. | ### 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. | ### ValidateSuiteRequest (synq.agent.recon.v1.ValidateSuiteRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) input.yaml | [ string](#string) | A suite in the YAML format of synq-recon. Each issue then has the position of its problem in the YAML text. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) input.suite | [ ReconciliationSuite](#reconciliationsuite) | A suite in the format that Coalesce Quality stores. The request does not apply the validation rules of ReconciliationSuite. Thus an incorrect suite gets to ValidateSuite, and the response has one issue for each rule that the suite does not obey. | ### ValidateSuiteResponse (synq.agent.recon.v1.ValidateSuiteResponse) | Field | Type | Description | | - | - | - | | valid | [ bool](#bool) | True when no issue has the ERROR severity. A suite with only warnings is valid. | | issues | [repeated SuiteValidationIssue](#suitevalidationissue) | All the problems in the suite. The errors come first, then the warnings. Empty when the suite has no problems. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_suite.suite | [optional ReconciliationSuite](#reconciliationsuite) | The suite from the yaml input. It is not set when the request gives the suite as a proto, or when the YAML text does not give a suite. | ### 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 and row count 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. | ### 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. | ### 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. | `updated_by.via` tells where the save came from. It is VIA\_API for a save through the public API, for example from `synq-recon upload-config`. It is VIA\_UNSPECIFIED for a save in the Coalesce Quality app. | \| state\_at | [ Timestamp](#timestamp) | When this version was created. To save an edit of this version only if no other save changed the suite, send this value as UpsertSuiteConfigRequest.expected\_state\_at. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | The summary of the change that the save gave. It is not set when the save gave no summary. | ### SuiteConfigConflict (synq.agent.recon.v1.SuiteConfigConflict) The error details of the FAILED\_PRECONDITION error that an UpsertSuiteConfigRequest gets when expected\_state\_at is not the latest version of the suite. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_current.current | [optional SuiteConfig](#suiteconfig) | The latest version of the suite. It is not set when the suite was deleted. | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_expected\_state\_at.expected\_state\_at | [optional Timestamp](#timestamp) | Save the suite only if this is still its latest version. Set it to the `state_at` of the SuiteConfig that the edit started from. | If a different save changed the suite after that version, or if someone deleted the suite, the request does not save. It gets FAILED\_PRECONDITION with a SuiteConfigConflict detail, which has the latest version. If you do not set it, the save replaces the latest version. | \| create\_only | [ bool](#bool) | Save the suite only if no suite has this name. This prevents an upload that replaces a suite by accident. If the name is in use, the request gets ALREADY\_EXISTS. You can use the name of a deleted suite. | ### UpsertSuiteConfigResponse (synq.agent.recon.v1.UpsertSuiteConfigResponse) | Field | Type | Description | | - | - | - | | suite\_config | [ SuiteConfig](#suiteconfig) | The stored suite config. | ### 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 | ### 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) | Field | Type | Description | | - | - | - | | messages | [repeated IngestMessage](#ingestmessage) | Messages for the user who reported the run, such as a warning about part of the audit log that was not stored, or a link to the run in the app. Show each one as it is. Empty when there is nothing to say. | ### IngestMessage (synq.agent.recon.v1.IngestMessage) IngestMessage is something to tell the user who reported a run. | Field | Type | Description | | - | - | - | | severity | [ IngestMessageSeverity](#ingestmessageseverity) | How prominently to show the message. | | text | [ string](#string) | The message, as one or more plain sentences. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_url.url | [optional string](#string) | A link that goes with the message, for example to the run in the app. | ### 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. | ### 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. | ### SuiteValidationFailure (synq.agent.recon.v1.SuiteValidationFailure) The error details of an INVALID\_ARGUMENT error that a request gets because of the contents of its suite. It lists all issues with the ERROR severity, so that the caller can show each issue next to its field. | Field | Type | Description | | - | - | - | | issues | [repeated SuiteValidationIssue](#suitevalidationissue) | none | ### SuiteValidationIssue (synq.agent.recon.v1.SuiteValidationIssue) One problem in a reconciliation suite. | Field | Type | Description | | - | - | - | | severity | [ SuiteValidationSeverity](#suitevalidationseverity) | none | | field\_path | [ string](#string) | The field that has the problem. The path uses the field names of ReconciliationSuite, for example `reconciliations[2].comparison.columns[0].numeric_scale` or `execution.timeout`. The index of a list item is its position in the suite. | A field that only YAML has uses its YAML key, for example `reconciliations[0].setup_file`. The path is empty when the problem is about the full suite, or when the YAML text is not valid YAML. | \| message | [ string](#string) | A description of the problem for the person who edits the suite. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_position.position | [optional YamlPosition](#yamlposition) | The position of the problem in the YAML text. It is set only when the request gives the suite as YAML. It points to the key of the field in field\_path. If the YAML does not have that key, for example because a required field is missing, it points to the nearest key that contains the field. | ### YamlPosition (synq.agent.recon.v1.YamlPosition) A line and a column in a YAML document. Both start at 1. | Field | Type | Description | | - | - | - | | line | [ int32](#int32) | none | | column | [ int32](#int32) | none | ### CaseCategories (synq.agent.recon.v1.CaseCategories) CaseCategories declares the categories for a single reconciliation case, overriding what the deployment declares. The two dimensions are independent, so a case can override one and inherit the other. Per field: * absent : inherit the deployment's declaration * present, empty string : declare nothing for this case, even when the deployment declares a value — the category then falls to the reserved annotation or the workspace's categorisation rules * present, non-empty : set this case's category An entry with neither field set therefore means the same as no entry at all, and is dropped rather than stored. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | none | ### 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. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Categories to declare for the reconciliation checks this promotion publishes. See SuiteDeployment.category / .governance\_category for what they mean and how they interact with annotations and categorisation rules. On a re-promote these behave as a patch of the previous deployment's values, per field: - absent : keep whatever the previous deployment declared - present, empty string : clear the declaration, falling back to the reserved annotation or the workspace rules - present, non-empty : set or replace the declaration So a re-promote that says nothing about categories never silently drops one. Use UpdateDeploymentCategories to change them without re-promoting. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | none | \| case\_categories | [map CaseCategoriesEntry](#casecategoriesentry) | Initial per-case category overrides, keyed by case `name`. Keys omitted on a re-promote keep the previous deployment's override; see CaseCategories for how a single dimension is inherited or cleared. Overrides for cases the promoted snapshot doesn't contain are rejected with INVALID\_ARGUMENT, so a renamed or deleted case surfaces as an error rather than a silently dead override. | ### PromoteSuiteRequest.CaseCategoriesEntry (synq.agent.recon.v1.PromoteSuiteRequest.CaseCategoriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CaseCategories](#casecategories) | none | ### 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) \_promoted\_at.promoted\_at | [optional Timestamp](#timestamp) | When this deployment reached production, and who put it there — taken from the most recent promotion in its history, not from whatever happened last. Read these rather than state\_at / last\_actor whenever the question is "when did this go live and on whose authority". Pausing, rescheduling, editing annotations or changing categories all restamp state\_at / last\_actor and leave these two untouched, so a surface that renders the promotion from state\_at reports the wrong time and often the wrong person. A re-promote is a promotion, so it restamps both. Unpromoting does not clear them: an inactive deployment still reports when it was last live. Both are absent only for a deployment whose history holds no promotion event. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_promoted\_by.promoted\_by | [optional Actor](#actor) | 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. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Technical category declared for every reconciliation check this deployment publishes — the "what kind of check is this, mechanically" dimension the catalog groups and filters checks by (for example "nullness", "uniqueness", "freshness"), which is what lets one category cover the same check written as a dbt test, a SQLMesh audit or a reconciliation. Declared on the promotion rather than in the suite file, because a reconciliation only becomes a check once it is promoted: the suite file says what to reconcile, the promotion says how it behaves in production — the same reason `schedule` lives here and not in the file. Absent means this deployment declares no category. The category is then taken from a reserved `quality.check_category` annotation on the suite, the case or the deployment overlay (see deployment\_annotations), and failing that from the workspace's own categorisation rules. Setting this field outranks both. Free-form: the vocabulary is whatever the workspace already uses, not a fixed enum. Always read and write it together with governance\_category — the two dimensions resolve independently and a surface that exposes one must expose both. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Governance category declared for every reconciliation check this deployment publishes — the "what is this check for" dimension, orthogonal to `category` (for example "completeness", "accuracy", "timeliness"). It is the dimension a data-governance function tracks coverage against. Same declaration point, same precedence and same free-form vocabulary as `category`; resolved independently of it, so declaring one never suppresses the other's annotation. | \| case\_categories | [map CaseCategoriesEntry](#casecategoriesentry) | Per-case overrides of the two fields above, keyed by case `name` from the suite config. Cases without an entry use the deployment-wide declaration. Worth overriding when the cases of one suite are the same kind of check but serve different governance purposes — a case comparing row counts is about completeness while a case comparing values is about accuracy, and they can carry different governance categories while sharing the deployment's technical one. | ### SuiteDeployment.CaseCategoriesEntry (synq.agent.recon.v1.SuiteDeployment.CaseCategoriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CaseCategories](#casecategories) | none | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | The declared categories in force at this point in time. Snapshot semantics, like the fields above: every history entry carries the values in force right after the event was recorded, not just the CATEGORIES\_CHANGED ones. Absent means no category was declared at that time. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | none | | case\_categories | [map CaseCategoriesEntry](#casecategoriesentry) | Per-case category overrides in force at this point in time. Snapshot semantics, like the map above. | ### SuiteDeploymentHistoryEntry.CaseCategoriesEntry (synq.agent.recon.v1.SuiteDeploymentHistoryEntry.CaseCategoriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CaseCategories](#casecategories) | none | ### 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 | ### UpdateDeploymentCategoriesRequest (synq.agent.recon.v1.UpdateDeploymentCategoriesRequest) | Field | Type | Description | | - | - | - | | suite\_id | [ string](#string) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Patch of the declared categories. Field presence is meaningful and the two fields are independent: - absent : leave the current value unchanged - present, empty string : clear the declaration - present, non-empty : set or replace the declaration | A request that sets nothing at all is accepted and changes nothing. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | none | \| case\_categories | [map CaseCategoriesEntry](#casecategoriesentry) | Patch of the per-case overrides, keyed by case `name`. Keys present in the request replace that case's override; keys absent are left untouched, so this never resets overrides the caller didn't mention. Send an entry with both fields absent to drop a case's override and go back to inheriting the deployment's declaration. Unknown case names are rejected with INVALID\_ARGUMENT. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_change\_summary.change\_summary | [optional string](#string) | none | \| actor | [ Actor](#actor) | Actor performing the category update. Required. | ### UpdateDeploymentCategoriesRequest.CaseCategoriesEntry (synq.agent.recon.v1.UpdateDeploymentCategoriesRequest.CaseCategoriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CaseCategories](#casecategories) | none | ### UpdateDeploymentCategoriesResponse (synq.agent.recon.v1.UpdateDeploymentCategoriesResponse) | 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 | ### 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" | ### 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. | ### 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. | | columns | [repeated string](#string) | Columns of the query's result to compare. When set, only these columns are read from the query; the rest of its SELECT list is ignored. Only with query — a table takes its columns inside table. Mutually exclusive with exclude\_columns. | | exclude\_columns | [repeated string](#string) | Columns of the query's result to leave out of the comparison. Every other column is read (resolved at runtime from the query's result shape). Only with query — a table takes its exclusions inside table. Mutually exclusive with columns. | ### 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. | | numeric\_columns | [repeated NumericComparison](#numericcomparison) | The precision each decimal and floating-point column was compared at, in column order. A MATCH on such a column is a match at this precision. | ### NumericComparison (synq.agent.recon.v1.NumericComparison) NumericComparison records the precision one numeric column was compared at. | Field | Type | Description | | - | - | - | | column | [ string](#string) | Column name as the source side reports it. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) precision.decimal\_places | [ int32](#int32) | Both sides were rounded to this many decimal places. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) precision.significant\_digits | [ int32](#int32) | Both sides were compared at this many significant digits, as floating-point values are by default. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) precision.exact | [ bool](#bool) | Both sides were compared at the full precision the column holds. | | configured | [ bool](#bool) | True when the precision was set by the suite's comparison settings, false when it was derived from the column types on both sides. | ### 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 | | threshold\_evaluation | [ ThresholdEvaluation](#thresholdevaluation) | Threshold evaluation of the row count difference, keyed by the measure "COUNT(\*)". Set only in ROW\_COUNT mode with row\_count.thresholds configured. A difference that is not exceeded is within tolerance. | ### 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 | ### 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 the key columns if not set. With no key columns either, the whole dataset is compared as a single group, with no GROUP BY. | 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. | ### ColumnComparison (synq.agent.recon.v1.ColumnComparison) ColumnComparison holds the comparison settings of one column. | Field | Type | Description | | - | - | - | | column | [ string](#string) | Column name as the source side reports it, matched case-insensitively. With a column\_mapping, this is the source column of the pair. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_numeric\_scale.numeric\_scale | [optional NumericScale](#numericscale) | How many decimal places this column is compared at, or exact. Overrides the reconciliation's and the suite's numeric\_scale. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_timestamp\_precision.timestamp\_precision | [optional TimestampPrecision](#timestampprecision) | How much of a second this timestamp column is compared to. Overrides the reconciliation's and the suite's timestamp\_precision. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source\_time\_zone.source\_time\_zone | [optional string](#string) | The time zone the source side holds this column's wall clock in. Overrides the reconciliation's and the suite's source\_time\_zone. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_target\_time\_zone.target\_time\_zone | [optional string](#string) | The time zone the target side holds this column's wall clock in. Overrides the reconciliation's and the suite's target\_time\_zone. | ### ComparisonConfig (synq.agent.recon.v1.ComparisonConfig) ComparisonConfig controls how column values are compared in ROW\_CHECKSUM mode. It has no effect in ROW\_COUNT and AGGREGATE modes. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_numeric\_scale.numeric\_scale | [optional NumericScale](#numericscale) | How many decimal places decimal and floating-point columns are compared at, or exact. When not set, a decimal column is compared at the scale both sides share, and a floating-point column at the digits both sides hold. Integer, text, timestamp and other columns are not affected. | | columns | [repeated ColumnComparison](#columncomparison) | Settings for individual columns, overriding the settings above. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_timestamp\_precision.timestamp\_precision | [optional TimestampPrecision](#timestampprecision) | How much of a second timestamp columns are compared to, timestamp key columns included. When not set, a timestamp is compared at the precision both sides hold, the coarser of the two. Date, numeric, text and other columns are not affected. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_source\_time\_zone.source\_time\_zone | [optional string](#string) | The time zone the source side's timestamps without a time zone hold their wall clock in, as an IANA name such as Europe/Warsaw. When not set, they are read as UTC. A timestamp with a time zone already says which instant it is and is not affected. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_target\_time\_zone.target\_time\_zone | [optional string](#string) | The time zone the target side's timestamps without a time zone hold their wall clock in, as source\_time\_zone does for the source side. | ### 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 and fails with a timeout error. It is not retried, since a query that took this long will usually take it again. Covers setup and teardown statements too. To bound the whole reconciliation rather than each query, use its timeout or the suite's execution.reconciliation\_timeout. Default: no per-query limit. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_max\_retries.max\_retries | [optional int32](#int32) | Maximum retry attempts for transient query failures. Setup and teardown statements are never retried, since they need not be safe to run twice. 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. | ### ExecutionConfig (synq.agent.recon.v1.ExecutionConfig) ExecutionConfig holds the suite's execution settings. Every field is optional, and an absent field leaves the runner's default in place. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_timeout.timeout | [optional Duration](#duration) | Maximum wall-clock time for a single run of the suite (the quick check plus any bisection drill). A run that exceeds it is cancelled and the reconciliations still running are reported as failed. Server-side runs clamp the value to a supported range. | Precedence, most specific first: the per-run override, the deployment's execution\_timeout, this field, the runner default. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_concurrency.concurrency | [optional int32](#int32) | Maximum number of reconciliations run in parallel. 1 (the default) runs them one after another. Each parallel reconciliation issues its own queries, so this multiplies the load on the source and target warehouses. Server-side runs clamp the value to a supported maximum. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_reconciliation\_timeout.reconciliation\_timeout | [optional Duration](#duration) | Maximum wall-clock time for a single reconciliation of the suite: its setup, quick check and any drill. A reconciliation that exceeds it is stopped and recorded as failed with a timeout error, and the run moves on to the next one, so one slow query cannot use up the whole run's timeout. It never extends the run: whichever of the two runs out first applies. A reconciliation's own timeout takes precedence. Unset means only the run's timeout bounds a reconciliation. | ### 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. | ### NumericScale (synq.agent.recon.v1.NumericScale) NumericScale is the precision a numeric column is compared at. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.places | [ int32](#int32) | Round both sides to this many decimal places before comparing, whatever their types. A value that differs only beyond the last place matches. Use it to tolerate a known rounding by a loader, or to compare a floating-point column with a decimal one. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) value.exact | [ bool](#bool) | Compare at the full precision the column holds. A decimal is compared at its declared scale, which must be known and the same on both sides, otherwise the reconciliation fails rather than rounding either side. A floating-point column is compared digit for digit, which needs both sides on the same kind of database: across two different ones the run fails with a message instead. Must be true when set. | ### 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, where it only stands in for group\_columns when those are unset. | | 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). | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_timeout.timeout | [optional Duration](#duration) | Maximum wall-clock time for this reconciliation: its setup, quick check and any drill. Overrides the suite's execution.reconciliation\_timeout. A reconciliation that exceeds it is recorded as failed with a timeout error and the run moves on to the next one. It never extends the run's own timeout. For a bound on each individual query, use error\_handling.query\_timeout. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_row\_count.row\_count | [optional RowCountConfig](#rowcountconfig) | Row count comparison settings. Only used when mode is ROW\_COUNT. Sets the tolerance a difference in row counts may stay within. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_comparison.comparison | [optional ComparisonConfig](#comparisonconfig) | How column values are compared in ROW\_CHECKSUM mode. Overrides the suite's comparison settings. When not set, the suite's apply, and without those every column is compared at the precision its types on both sides allow. | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution.execution | [optional ExecutionConfig](#executionconfig) | How runs of this suite execute: the wall-clock budget of a run and how many reconciliations run at the same time. Read by every run of the suite, local or server-side; a run-level override (a CLI flag, the execution\_timeout on a trigger or on a deployment) takes precedence. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_comparison.comparison | [optional ComparisonConfig](#comparisonconfig) | Default comparison settings for every reconciliation in the suite. A reconciliation's own comparison settings take precedence, field by field. | ### 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. | ### RowCountConfig (synq.agent.recon.v1.RowCountConfig) RowCountConfig defines row count comparison settings. Used when mode is ROW\_COUNT. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_thresholds.thresholds | [optional ThresholdConfig](#thresholdconfig) | Tolerance for the difference between the source and target row counts. A difference within it reports MISMATCHED\_WITHIN\_THRESHOLD instead of MISMATCHED, and no drill runs for it. Same semantics as aggregate thresholds, applied to COUNT(\*): a difference is accepted when it is within absolute or within percentage, computed against percentage\_basis. When not set, the counts must be equal. | ### 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. | ### 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. | ### 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. | ### 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 | ### 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 | ### CheckRelationship (synq.entities.custom.v1.CheckRelationship) | Field | Type | Description | | - | - | - | | check | [ Identifier](#identifier) | none | | checked | [ Identifier](#identifier) | none | | checked\_columns | [repeated string](#string) | none | ### CheckRelationshipWriteResult (synq.entities.custom.v1.CheckRelationshipWriteResult) CheckRelationshipWriteResult reports what one requested check relationship did to the stored graph. | Field | Type | Description | | - | - | - | | check\_relationship | [ CheckRelationship](#checkrelationship) | The check relationship this result answers for, as sent, with `entity_id` filled in on both endpoints. | The pair of entities the endpoints resolve to is what the relationship is held under, so compare these two ids rather than the identifiers you sent to tell whether two of them are the same relationship. `checked_columns` is part of the payload, not of that pair: restating the same pair with a different column list replaces the stored one. | \| outcome | [ RelationshipWriteOutcome](#relationshipwriteoutcome) | What the write did to that relationship. | ### DeleteCheckRelationshipsRequest (synq.entities.custom.v1.DeleteCheckRelationshipsRequest) | Field | Type | Description | | - | - | - | | check\_relationships | [repeated CheckRelationship](#checkrelationship) | none | ### DeleteCheckRelationshipsResponse (synq.entities.custom.v1.DeleteCheckRelationshipsResponse) | Field | Type | Description | | - | - | - | | results | [repeated CheckRelationshipWriteResult](#checkrelationshipwriteresult) | One result per check relationship in the request, in request order. | ### ListCheckRelationshipsRequest (synq.entities.custom.v1.ListCheckRelationshipsRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every check relationship in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListCheckRelationshipsResponse (synq.entities.custom.v1.ListCheckRelationshipsResponse) | Field | Type | Description | | - | - | - | | check\_relationships | [repeated CheckRelationship](#checkrelationship) | none | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole workspace. | ### UpsertCheckRelationshipsRequest (synq.entities.custom.v1.UpsertCheckRelationshipsRequest) | Field | Type | Description | | - | - | - | | check\_relationships | [repeated CheckRelationship](#checkrelationship) | none | ### UpsertCheckRelationshipsResponse (synq.entities.custom.v1.UpsertCheckRelationshipsResponse) | Field | Type | Description | | - | - | - | | results | [repeated CheckRelationshipWriteResult](#checkrelationshipwriteresult) | One result per check relationship in the request, in request order. | ### 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) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every entity in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListEntitiesResponse (synq.entities.custom.v1.ListEntitiesResponse) | Field | Type | Description | | - | - | - | | entities | [repeated Entity](#entity) | none | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole workspace. | ### 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) | Field | Type | Description | | - | - | - | | results | [repeated RelationshipWriteResult](#relationshipwriteresult) | One result per relationship in the request, in request order. | ### ListRelationshipsRequest (synq.entities.custom.v1.ListRelationshipsRequest) | Field | Type | Description | | - | - | - | | ids | [repeated Identifier](#identifier) | Return relationships for the given entity\_id. Either upstream or downstream. Leave empty to return every relationship in the workspace: an edge hangs off endpoints a caller may not know up front, so enumerating them by id requires already knowing every entity an edge can touch. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every matching relationship in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListRelationshipsResponse (synq.entities.custom.v1.ListRelationshipsResponse) | Field | Type | Description | | - | - | - | | relationships | [repeated Relationship](#relationship) | none | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole result set. | ### Relationship (synq.entities.custom.v1.Relationship) | Field | Type | Description | | - | - | - | | upstream | [ Identifier](#identifier) | none | | downstream | [ Identifier](#identifier) | none | ### RelationshipWriteResult (synq.entities.custom.v1.RelationshipWriteResult) RelationshipWriteResult reports what one requested relationship did to the stored graph. | Field | Type | Description | | - | - | - | | relationship | [ Relationship](#relationship) | The relationship this result answers for, as sent, with `entity_id` filled in on both endpoints. | An edge is held between the two entities the endpoints resolve to, not between the identifiers as written, and one entity accepts several spellings — a warehouse name that differs only in case or punctuation usually names the same table. So compare these two ids, rather than the identifiers you sent, to tell whether two relationships are the same edge. | \| outcome | [ RelationshipWriteOutcome](#relationshipwriteoutcome) | What the write did to that edge. | ### UpsertRelationshipsRequest (synq.entities.custom.v1.UpsertRelationshipsRequest) | Field | Type | Description | | - | - | - | | relationships | [repeated Relationship](#relationship) | none | ### UpsertRelationshipsResponse (synq.entities.custom.v1.UpsertRelationshipsResponse) | Field | Type | Description | | - | - | - | | results | [repeated RelationshipWriteResult](#relationshipwriteresult) | One result per relationship in the request, in request order. | ### 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) ### 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) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every type in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListTypesResponse (synq.entities.custom.v1.ListTypesResponse) | Field | Type | Description | | - | - | - | | types | [repeated Type](#type) | List of entities. | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole workspace. | ### UpsertTypeRequest (synq.entities.custom.v1.UpsertTypeRequest) | Field | Type | Description | | - | - | - | | type | [ Type](#type) | Entity to create or update. | ### UpsertTypeResponse (synq.entities.custom.v1.UpsertTypeResponse) ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) feature.column\_lineage | [ ColumnLineage](#columnlineage) | 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. Leave unset to list the features of every custom entity in the workspace. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every matching feature in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListEntityFeaturesResponse (synq.entities.custom.v1.ListEntityFeaturesResponse) | Field | Type | Description | | - | - | - | | features | [repeated Feature](#feature) | List of features for the entity. | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole result set. | ### UpsertEntityFeatureRequest (synq.entities.custom.v1.UpsertEntityFeatureRequest) | Field | Type | Description | | - | - | - | | feature | [ Feature](#feature) | The feature to create or update. | ### UpsertEntityFeatureResponse (synq.entities.custom.v1.UpsertEntityFeatureResponse) ### 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) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_pagination.pagination | [optional Pagination](#pagination) | Pagination. Omitting this, or sending a zero page\_size, returns every group in one response — there is no server-side default page size. A group carries every one of its member identifiers, so a workspace with large groups is worth paging even though the group count is small. Pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListEntityGroupsResponse (synq.entities.custom.v1.ListEntityGroupsResponse) | Field | Type | Description | | - | - | - | | entities\_groups | [repeated Group](#group) | none | | page\_info | [ PageInfo](#pageinfo) | Paging information for this response. Always populated. Repeat the request passing page\_info.last\_id as pagination.cursor until last\_id comes back empty to walk the whole workspace. | ### 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 | ### ColumnEdge (synq.entities.custom.features.v1.ColumnEdge) ColumnEdge is one column of one upstream entity feeding one column of the entity this feature belongs to. | Field | Type | Description | | - | - | - | | upstream | [ Identifier](#identifier) | The entity the data comes from. Any entity: another custom entity, or a table, model or dashboard from a connected platform. An upstream that does not exist yet is remembered and the edge appears once it does. | | upstream\_column | [ string](#string) | Column of the upstream entity the data comes from. | | column | [ string](#string) | Column of this entity the data flows into. | ### ColumnLineage (synq.entities.custom.features.v1.ColumnLineage) ColumnLineage declares column-level lineage flowing INTO a custom entity, for the cases SQL cannot express: an upstream that is itself a custom entity, or a component whose transformation is not written in SQL at all. Use it when `SqlDefinition` does not fit — when there is no SQL to give at all, or when you would rather state the result than have it derived. A component whose transformation is written in Python, or a hand-maintained mapping, has no SQL for a parser to read. If the component DOES have SQL, prefer `SqlDefinition`: a name in it that is not a database object — another custom entity, a queue, a service — is bound to the entity it stands for with `SqlDefinition.references`, and the column lineage is then derived from the SQL and stays correct as the SQL changes. The declaration is complete and replaces the previous one whole: an edge missing from a write is withdrawn, and deleting the feature withdraws all of them. Only one ColumnLineage feature is allowed per entity, so re-writing it under the same `feature_id` is how it is edited. Declaring a column edge also declares the table-level edge it implies, so the entity appears downstream of each upstream named here whether or not a Relationship says so too. Column lineage is only ever shown along a table-level edge, which is why the two travel together. An entity that has BOTH this feature and a `SqlDefinition` is served from this declaration in the SQL-lineage view — an explicit statement takes precedence over lineage derived from SQL. Declare column lineage here only for what the SQL cannot say, or state the entity's whole column lineage here and treat this as the authority for it. | Field | Type | Description | | - | - | - | | state\_at | [ Timestamp](#timestamp) | Time when this lineage was declared, will default to `now` if not set. A later declaration replaces an earlier one, so an explicit time is how a backfill avoids overwriting a fresher declaration. | | edges | [repeated ColumnEdge](#columnedge) | Column-level edges into this entity. Every edge names one upstream entity and one column on each side. | ### 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. | ### 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. | ### 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. | ### 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. | | references | [repeated SqlTableReference](#sqltablereference) | Names in this SQL that are not database objects, each bound to the entity it stands for. A reference the SQL makes to one of these names resolves to that entity instead of being looked up in the database and dropped. | Use it for the upstreams and downstreams a database cannot address: another custom entity, a queue, a service, an API. A name that IS a database object needs no binding — it resolves on its own. The bindings are part of the definition and replace with it: a binding dropped from a later write is gone, and the lineage it produced is withdrawn. | ### SqlTableReference (synq.entities.custom.features.v1.SqlTableReference) SqlTableReference binds one name, as the SQL writes it, to the entity that name stands for. | Field | Type | Description | | - | - | - | | instance\_name | [ string](#string) | The name as the SQL writes it. Matched case-insensitively; a part left empty defaults from the definition's `database_context`, exactly as an unqualified table reference in the SQL does. So a binding of just `object_name: "orders_topic"` under a definition whose database is `kafka` matches both `FROM kafka.orders_topic` and `FROM orders_topic`. | | database\_name | [ string](#string) | none | | schema\_name | [ string](#string) | none | | object\_name | [ string](#string) | none | | entity | [ Identifier](#identifier) | The entity this name stands for. Any entity: another custom entity, or a table, model or dashboard from a connected platform. An entity that does not exist yet is remembered and the edge appears once it does. | ### 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 technical category of the check — what kind of check this is, mechanically (e.g. "nullness", "uniqueness", "freshness"), so the same check expressed on another platform shares one category. | Presence is meaningful on update: omit the field to leave the current value untouched, send an empty string to clear it, send a non-empty string to set or replace it. Leaving it unset means the check is uncategorised for this dimension and the workspace's categorisation rules decide it from package + kind; the `quality.check_category` annotation on the entity is read as the lower-precedence fallback. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Explicit governance category of the check — what the check is for, the data-quality dimension a governance function tracks coverage against (e.g. "Completeness", "Accuracy", "Timeliness"). Resolves independently of `category` and follows the same presence semantics: omitted leaves it unchanged, empty clears it, non-empty sets it. Unset means uncategorised for this dimension; the `quality.governance_category` annotation on the entity is the lower-precedence fallback. | ### 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. | ### BatchGetEntityAnnotationsRequest (synq.entities.annotations.v1.BatchGetEntityAnnotationsRequest) BatchGetEntityAnnotationsRequest is the request message for the BatchGetEntityAnnotations method. | Field | Type | Description | | - | - | - | | ids | [repeated Identifier](#identifier) | The entities to read annotations for. Each entry is validated by Identifier's own rules — its `id` oneof is `required`, and protovalidate recurses into the elements of a repeated message field — so an identifier naming nothing is refused here. There is no per-item `required` to add beside it: `repeated.items.required` is unenforceable and buf lint rejects it, and it would have nothing to catch, because an entry on the wire is always a message rather than a null. | ### BatchGetEntityAnnotationsResponse (synq.entities.annotations.v1.BatchGetEntityAnnotationsResponse) BatchGetEntityAnnotationsResponse is the response message for the BatchGetEntityAnnotations method. | Field | Type | Description | | - | - | - | | entity\_annotations | [repeated EntityAnnotations](#entityannotations) | One entry per requested entity that carries any annotation. An entity with none is omitted rather than returned empty, so the response says which of the requested entities are annotated at all. | ### EntityAnnotations (synq.entities.annotations.v1.EntityAnnotations) EntityAnnotations is the annotations one entity carries. | Field | Type | Description | | - | - | - | | id | [ Identifier](#identifier) | The entity, echoed back in the spelling it was requested in. | | annotations | [repeated Annotation](#annotation) | Annotations the entity carries, one entry per name, ordered by name. | Read over the entity's whole identity group rather than the one id asked for: a dbt model, the warehouse table it builds and a catalog entity virtualising the same table are one entity to a reader, and which of them an annotation was published against is a property of the producer, not of the thing being annotated. | ### 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. Spellings of a name or a value that differ only in case are counted together and returned under one of the spellings entities carry, the same for every value of a name. | ### 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. | ### 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. | ### 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'. | ### 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. | ### 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) | Short label for the custom entity type, shown beside the type's icon, in type filters, and on the type badge of every entity of this type. | It is the only name a custom type has, so keep it short enough to read as a caption rather than a description — "Kafka Topic", not a sentence. | \| 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). | ### 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 | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_precision.precision | [optional int64](#int64) | Declared precision of an exact numeric column (NUMERIC, DECIMAL, NUMBER), in decimal digits. Set whichever category the column reads as, so a NUMBER(38,0) is NUMERIC\_CATEGORY\_INTEGER with precision 38 and scale 0. Unset for every other column, and for an exact numeric whose size the data warehouse does not report. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scale.scale | [optional int64](#int64) | Declared scale of an exact numeric column, set together with precision. Unset is not a scale of 0: it means the scale is not known. | | numeric\_category | [ NumericCategory](#numericcategory) | What kind of number the column holds. Unspecified for a non-numeric column, and for one whose type is not recognised. | ### 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 | ### 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. | A value is something entities are filtered and searched by, not free-form metadata, so keep it to a label a person would pick out of a list. The limit is set to hold an identifier or a link the annotated system generated — truncating one of those produces a value that no longer resolves, and no longer matches the filter it exists for. Put prose in the entity description instead. | ### 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 | ### Db2TableIdentifier (synq.entities.v1.Db2TableIdentifier) IBM Db2 for Linux, UNIX and Windows table identifier. | Field | Type | Description | | - | - | - | | host | [ string](#string) | Host name of the Db2 server | | database | [ string](#string) | Database name or alias, as in `CONNECT TO ` | | schema | [ string](#string) | Db2 schema (e.g. "DB2INST1") | | table | [ string](#string) | Db2 table or view | ### 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. Every identifier the API RETURNS also carries `entity_id`, the entity's opaque id. Read it when you just need to name the entity again — it is one string for every platform, where the structured variants below only cover the platforms that have one. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | Opaque id of the entity, set on every identifier the API returns. Round-trip it verbatim; the format is not part of this contract and may change, and it is never constructed by hand. | OUTPUT ONLY. On a request this field is ignored — the structured variant is what resolves. That is what lets you hand an identifier straight back unchanged, or edit its structured fields, without the two disagreeing about which entity you meant. To name an entity BY opaque id on a request, set the `synq_path` variant to that id: it carries exactly this string, and it is also how an entity whose platform has no structured variant is named. | \| [**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 | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) id.db2\_table | [ Db2TableIdentifier](#db2tableidentifier) | IBM Db2 LUW 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 | ### 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 | | definer\_platform | [ DataPlatformType](#dataplatformtype) | Data platform of the entity that defines this code — dbt, SQLMesh, Snowflake, and so on. `definer_entity_type` says what kind of thing defines the code; this says which tool it belongs to. | Use it to order the code an entity has when it has more than one piece: a warehouse table modelled by a transformation framework carries both the framework's source and the warehouse's own DDL, and the framework source is what a reader normally wants first. | \| has\_execution\_error | [ bool](#bool) | True when the definer failed to produce this code the last time it ran — a model that did not compile, a routine whose body could not be read. The `content` is then the last body that was captured, which may be stale or empty; `execution_error` says what went wrong. | \| execution\_error | [ string](#string) | Message describing the failure `has_execution_error` reports. Empty when there is no failure, and may also be empty when the producer recorded a failure without a message. | \| is\_truncated | [ bool](#bool) | True when `content` holds only the first part of the file. Files above the ingestion size cap are stored as a prefix, and a client showing this code should say so rather than presenting the prefix as the whole body. `original_size_bytes` gives the untruncated size. | \| original\_size\_bytes | [ uint64](#uint64) | Size in bytes of the code before any truncation. Read it together with `is_truncated`, which is what makes it meaningful: where `content` was cut, this is the size of the whole body, and a truncated body always has one. Zero where nothing measured the source, which is the normal case for code that is not read from a file and never happens for a truncated body. | ### CodeSourceError (synq.entities.v1.CodeSourceError) CodeSourceError reports one source that could not be read while the rest of the response was assembled. That source's code is missing or incomplete in `codes`; every other source in the response is complete. Retry the same request to pick the missing source up — these are transient by nature. A request in which every source failed returns an error instead. | Field | Type | Description | | - | - | - | | source | [ CodeSource](#codesource) | Which source was unavailable. | | message | [ string](#string) | Human-readable reason, for logging and for telling a reader why part of the code is missing. Not a stable string; do not branch on it. | ### 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. Set it to the name the entity is known by in the system it comes from, rather than shortening it to fit — the limit is set wide enough to carry a generated name whole. | | 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 | ### 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. | ### 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. | ### 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. See ColumnRemovalChangeType.column\_id. | | native\_type | [ string](#string) | Data type of the new column. | | ordinal\_position | [ int32](#int32) | Position where the column was added in the schema. | | human\_name | [ string](#string) | Name of the column as it appears in the source system. See ColumnRemovalChangeType.human\_name. | ### 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. See ColumnRemovalChangeType.column\_id. | | previous\_native\_type | [ string](#string) | Previous data type of the column. | | current\_native\_type | [ string](#string) | New data type of the column. | | human\_name | [ string](#string) | Name of the column as it appears in the source system. See ColumnRemovalChangeType.human\_name. | | ordinal\_position | [ int32](#int32) | Position of the changed column in the current version of the schema. | ### 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. Normalized to lower case with special characters stripped, so several columns of one schema can share it. | | native\_type | [ string](#string) | Native data type of the removed column. | | ordinal\_position | [ int32](#int32) | Original position of the column in the schema. | | human\_name | [ string](#string) | Name of the column as it appears in the source system, which is what distinguishes two columns sharing a column\_id. Empty when the source system reported no distinct name, and on changes recorded before this field existed. | ### 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. | ### 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). | ### 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 | ### 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 | ### 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 | ### ActivitySelection (synq.entities.activity.v1alpha.ActivitySelection) ActivitySelection picks the entities a read is about: a data product, an owner, a saved filter or any other query. A data product is `in_product(...)` in resolver\_ql, an owner `in_owner(...)`. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.resolver\_ql | [ string](#string) | The entities in resolver query language, the fuller of the two forms. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) selection.public\_query | [ Query](#query) | The entities in structured form, as the filter builder produces it. | ### ActorGroupRef (synq.entities.activity.v1alpha.ActorGroupRef) ActorGroupRef names one group of GetActivityOverview. Its summary has exactly the group's queries, so it can be narrower than the actor of the same name: a login a service account holds can land with another account first, and Coalesce Quality's queries land in the COALESCE group. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) group.service\_account\_id | [ string](#string) | The SERVICE\_ACCOUNT group of this service account, a built-in one included. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) group.issuer | [ DataPlatformType](#dataplatformtype) | The TOOL group of this tool. | | built\_in | [ bool](#bool) | Output only: service\_account\_id names a built-in account. | ### ActorRef (synq.entities.activity.v1alpha.ActorRef) ActorRef names who an actor summary is about. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.platform\_user\_id | [ string](#string) | One login, on every tool that issued its queries. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.issuer\_entity\_id | [ string](#string) | A job, task or step that issues queries or runs what builds an entity: what it maintains. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.issuer | [ DataPlatformType](#dataplatformtype) | A tool, from the tag its queries carry. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.service\_account\_id | [ string](#string) | The logins a service account holds, a built-in one included, such as `built_in.fivetran`. `built_in.coalesce-quality` is the same actor as coalesce. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.person\_identity | [ string](#string) | The logins linked to this person, such as "synq:\" or "email:\
". | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.coalesce | [ bool](#bool) | Coalesce Quality and Coalesce Catalog: every query that carried Coalesce Quality's tag, on any login, and every query of a login either connects as. What the overview's COALESCE group counts. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.group | [ ActorGroupRef](#actorgroupref) | One group of GetActivityOverview, exactly the logins the overview lands in it: what ActorGroup.actor names for a service account or a tool. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.person\_identities | [ PersonIdentities](#personidentities) | One person through every identity of theirs, each login counted once. | ### GridDay (synq.entities.activity.v1alpha.GridDay) GridDay is one weekday of a weekday and hour grid. | Field | Type | Description | | - | - | - | | iso\_weekday | [ uint32](#uint32) | 1 is Monday, 7 is Sunday. | | hours | [repeated uint64](#uint64) | 24 counts, one per local hour. | | occurrences | [ uint32](#uint32) | How many local dates with this weekday overlap the window, to average by. | ### IssuerCount (synq.entities.activity.v1alpha.IssuerCount) IssuerCount is one issuing tool's part of a point. | Field | Type | Description | | - | - | - | | issuer | [ DataPlatformType](#dataplatformtype) | DATA\_PLATFORM\_TYPE\_UNSPECIFIED is access whose query carried no tool's tag. | | count | [ uint64](#uint64) | none | ### NotCountedActivity (synq.entities.activity.v1alpha.NotCountedActivity) NotCountedActivity is access a read saw and left out. | Field | Type | Description | | - | - | - | | coalesce\_logins | [ uint64](#uint64) | Access by the logins Coalesce Quality connects as, on queries that carried no Coalesce Quality tag. A tagged query is in coalesce\_quality\_queries instead. | | writers\_own\_reads | [ uint64](#uint64) | Reads by a login of an entity it wrote the same UTC day. | | intermediate | [ uint64](#uint64) | Reads in an hour the entity was an intermediate table. | | coalesce\_quality\_queries | [ uint64](#uint64) | Coalesce Quality's own queries, on any login, such as a monitor or a SQL test reading the entity. Never counted. | | excluded\_by\_policy | [ uint64](#uint64) | Reads by logins whose service account does not count toward popularity, such as a loader or an orchestrator. | | excluded\_by\_lens | [ uint64](#uint64) | Access the asked lens does not look at, such as a BI tool's reads under DEVELOPMENT. | ### PersonIdentities (synq.entities.activity.v1alpha.PersonIdentities) PersonIdentities names one person by the identities of theirs a caller holds: what synq.users.v1.UsersService.GetUserIdentities returns for them, such as "synq:\", their "email:\
" and the "platform\_user:\" logins linked to them, and the BI viewers those resolve. Only a login that is somebody's own, or nobody's, is the person's: a login a service account holds never is. | Field | Type | Description | | - | - | - | | identities | [repeated string](#string) | none | ### PlatformShares (synq.entities.activity.v1alpha.PlatformShares) PlatformShares are the shares of the queries on one platform. | Field | Type | Description | | - | - | - | | platform | [ DataPlatformType](#dataplatformtype) | none | | compute\_unit | [ ComputeUnit](#computeunit) | none | | shares | [ QueryShares](#queryshares) | none | ### PlatformWeights (synq.entities.activity.v1alpha.PlatformWeights) PlatformWeights are the weights of the queries on one platform. | Field | Type | Description | | - | - | - | | platform | [ DataPlatformType](#dataplatformtype) | DATA\_PLATFORM\_TYPE\_UNSPECIFIED is the queries whose platform is not known. | | compute\_unit | [ ComputeUnit](#computeunit) | What weights.compute\_ms counts. | | weights | [ QueryWeights](#queryweights) | none | ### PoolRank (synq.entities.activity.v1alpha.PoolRank) PoolRank is an entity's place in one pool. | Field | Type | Description | | - | - | - | | pool | [ PopularityPool](#popularitypool) | none | | platform | [ DataPlatformType](#dataplatformtype) | The platform and instance the pool is on, as far as the pool names them. | | instance | [ string](#string) | none | | reads | [ uint64](#uint64) | The entity's reads in this pool. | | percentile | [ double](#double) | The share of the pool's other entities with fewer reads, from 0 to 1. Entities with equal reads share the lower place, and the only entity of a pool has 1. | | pool\_size | [ uint32](#uint32) | The entities in the pool: those with counted reads in the window. | ### QueryShares (synq.entities.activity.v1alpha.QueryShares) QueryShares are the weights of each query split equally over the entities it touched, so they add up across entities. Equal is a convention, as no platform reports cost per table. An unset figure is one no query reported. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_ms.execution\_ms | [optional double](#double) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_compute\_ms.compute\_ms | [optional double](#double) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_scanned.bytes\_scanned | [optional double](#double) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_billed.bytes\_billed | [optional double](#double) | none | ### QueryWeights (synq.entities.activity.v1alpha.QueryWeights) QueryWeights are whole weights summed over queries. An unset figure is one no query reported, and zero is a value. Nothing here is a credit or a price. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_execution\_ms.execution\_ms | [optional uint64](#uint64) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_compute\_ms.compute\_ms | [optional uint64](#uint64) | In the unit of the platform the weights are for. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_scanned.bytes\_scanned | [optional uint64](#uint64) | What the queries scanned. Never a cost: a platform can bill differently from what it scanned. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_bytes\_billed.bytes\_billed | [optional uint64](#uint64) | Set only where the platform bills by bytes read. | ### SeriesPoint (synq.entities.activity.v1alpha.SeriesPoint) SeriesPoint is one step of a series. A series is dense: a step with nothing counted is a point with count 0, and covered or covered\_hours say whether it was seen at all. | Field | Type | Description | | - | - | - | | start | [ Timestamp](#timestamp) | none | | count | [ uint64](#uint64) | none | | by\_issuer | [repeated IssuerCount](#issuercount) | With SERIES\_SPLIT\_ISSUER only: each tool's count, highest first, then by issuer. | | covered | [ bool](#bool) | On an hourly point: whether the hour's query history was read. | | covered\_hours | [ uint32](#uint32) | On a daily point: how many of the day's hours were read. A day has 23 or 25 hours when the time zone changes its offset. | | partial | [ bool](#bool) | On a daily point: the day is not wholly inside the window. | ### WeekGrid (synq.entities.activity.v1alpha.WeekGrid) WeekGrid is when access happens in the week: seven days, Monday first. | Field | Type | Description | | - | - | - | | days | [repeated GridDay](#gridday) | none | ### ActorActivity (synq.entities.activity.v1alpha.ActorActivity) ActorActivity is one thing that touched an entity in one direction and measure, with its count. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.issuer\_entity\_id | [ string](#string) | A job, task or step, such as "dbt model M writes this". | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.service\_account\_id | [ string](#string) | A service account, a built-in one included. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.issuer | [ DataPlatformType](#dataplatformtype) | A tool, from the tag on queries no job is named for, such as "Looker reads this". | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.platform\_user\_id | [ string](#string) | none | | count | [ uint64](#uint64) | none | | logins | [ uint32](#uint32) | The distinct logins behind the count. 1 for a login. | | last\_seen\_at | [ Timestamp](#timestamp) | none | | basis | [ LoginBasis](#loginbasis) | For a login only. | | person\_identity | [ string](#string) | For a login with basis OWN\_LOGIN, VIEWER\_EMAIL or VIEWER\_TOOL\_USER: the identity of its person, such as "email:\
", empty when none resolves. A member whose identities hold the login's "platform\_user:\" wins over it: that is a platform user alias, and the caller applies it. | | active\_days | [ uint32](#uint32) | The distinct UTC days with counted access. | | shares | [ QueryShares](#queryshares) | The summed shares of the queries behind the count. | | purpose | [ Purpose](#purpose) | What it acts for: a service account's purpose, else the purpose of the tool that issued its queries. Unspecified for a login, and for a tool with no known purpose. | | cadence | [ WriteCadence](#writecadence) | How often it accessed the entity in the window. | | built\_in | [ bool](#bool) | Set when service\_account\_id names a built-in account. | | entity\_id | [ string](#string) | For a service account, its entity id, which resolves to its name like any other entity. | ### ActorComputeTotals (synq.entities.activity.v1alpha.ActorComputeTotals) ActorComputeTotals is an actor's queries on one compute of one platform instance. | Field | Type | Description | | - | - | - | | platform\_root\_id | [ string](#string) | none | | compute\_id | [ string](#string) | none | | platform | [ DataPlatformType](#dataplatformtype) | DATA\_PLATFORM\_TYPE\_UNSPECIFIED when the instance's platform is not known. | | compute\_unit | [ ComputeUnit](#computeunit) | none | | queries | [ uint64](#uint64) | none | | weights | [ QueryWeights](#queryweights) | none | ### ActorEntityActivity (synq.entities.activity.v1alpha.ActorEntityActivity) ActorEntityActivity is what an actor did to one entity in one direction and measure. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | direction | [ ActivityDirection](#activitydirection) | none | | measure | [ ActivityMeasure](#activitymeasure) | none | | count | [ uint64](#uint64) | none | | shares | [ QueryShares](#queryshares) | none | | last\_seen\_at | [ Timestamp](#timestamp) | none | | active\_days | [ uint32](#uint32) | none | ### ActorFileOperation (synq.entities.activity.v1alpha.ActorFileOperation) ActorFileOperation is an actor's queries of one file operation on one location. | Field | Type | Description | | - | - | - | | operation | [ FileOperation](#fileoperation) | none | | location\_entity\_id | [ string](#string) | The stage or location the files moved through, empty when none is known. A temporary stage a tool makes per run is one location. | | queries | [ uint64](#uint64) | none | | weights | [repeated PlatformWeights](#platformweights) | The whole weights of the queries per platform, by platform. | ### ActorGroup (synq.entities.activity.v1alpha.ActorGroup) ActorGroup is the queries of the logins that land in one group. | Field | Type | Description | | - | - | - | | kind | [ ActorGroupKind](#actorgroupkind) | none | | actor | [ ActorRef](#actorref) | The actor to ask GetActorSummary about, whose summary has the same queries, compute and logins as the group. Unset for PEOPLE, LOGINS and UNATTRIBUTED. | | logins | [ uint32](#uint32) | The distinct logins behind the queries. | | queries | [ uint64](#uint64) | none | | weights | [repeated PlatformWeights](#platformweights) | The group's weights per platform, by platform. | | daily | [repeated SeriesPoint](#seriespoint) | The queries per day in the asked time zone, and when in the week. Under a selection, the reads, inputs and writes of the selected entities. | | grid | [ WeekGrid](#weekgrid) | none | | reads | [ uint64](#uint64) | The group's access to entities, per entity a query touched, so a query that read three tables is three reads. Under a selection, of the selected entities only. Only with include\_flows or a selection. | | inputs | [ uint64](#uint64) | none | | writes | [ uint64](#uint64) | none | | entities\_read | [ uint32](#uint32) | The entities it read or input, and wrote, entities that are the same counted once. | | entities\_written | [ uint32](#uint32) | none | | shares | [repeated PlatformShares](#platformshares) | Under a selection: the group's share of its queries' weights on the selected entities, by platform. Unset without one, where weights is the whole. | ### ActorIssuerEntity (synq.entities.activity.v1alpha.ActorIssuerEntity) ActorIssuerEntity is one job behind an actor's queries: the queries it issued and what it wrote. | Field | Type | Description | | - | - | - | | issuer\_entity\_id | [ string](#string) | none | | issuer | [ DataPlatformType](#dataplatformtype) | The tool that issued its queries. | | queries | [ uint64](#uint64) | none | | weights | [repeated PlatformWeights](#platformweights) | The whole weights of its queries per platform, by platform. | | writes | [ uint64](#uint64) | Its writes, one per entity each write query touched, and the entities it wrote, entities that are the same counted once. | | entities\_written | [ uint32](#uint32) | none | ### ActorTotals (synq.entities.activity.v1alpha.ActorTotals) ActorTotals is an actor's whole window. | Field | Type | Description | | - | - | - | | queries | [ uint64](#uint64) | Its queries, whatever they touched. | | weights | [repeated PlatformWeights](#platformweights) | The whole weights of its queries, per platform, by platform. | | reads | [ uint64](#uint64) | Access to entities, per direction. | | inputs | [ uint64](#uint64) | none | | writes | [ uint64](#uint64) | Write queries. Runs are never part of it. | | runs | [ uint64](#uint64) | The runs of what a job builds. | | entities\_read | [ uint32](#uint32) | The distinct entities it read, and wrote or built. | | entities\_written | [ uint32](#uint32) | none | | active\_days | [ uint32](#uint32) | The distinct UTC days with any access. | | outside\_entities | [ QueryShares](#queryshares) | The whole weight less the entity shares, never below 0: what the queries spent outside entities, such as on a pipeline's staging tables. Each figure is a sum across platforms. | ### ActorWrittenSchema (synq.entities.activity.v1alpha.ActorWrittenSchema) ActorWrittenSchema is what an actor wrote in one schema. | Field | Type | Description | | - | - | - | | schema | [ WarehouseSchema](#warehouseschema) | none | | entities\_written | [ uint32](#uint32) | The entities it wrote there, entities that are the same counted once each. | | writes | [ uint64](#uint64) | none | | cadence | [ WriteCadence](#writecadence) | How often it wrote there in the window. | ### BatchGetEntityUsageRequest (synq.entities.activity.v1alpha.BatchGetEntityUsageRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | none | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | top\_k | [ uint32](#uint32) | At most this many roles of each kind, such as the three tools that read the entity most. Unset is 3. | ### BatchGetEntityUsageResponse (synq.entities.activity.v1alpha.BatchGetEntityUsageResponse) | Field | Type | Description | | - | - | - | | entities | [repeated EntityUsage](#entityusage) | One per distinct asked id, in the order each was first asked. | | from | [ Timestamp](#timestamp) | The window read, \[from, to). | | to | [ Timestamp](#timestamp) | none | ### BatchGetPopularityRequest (synq.entities.activity.v1alpha.BatchGetPopularityRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | none | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour, so the window holds closed hours only. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | pool | [ PopularityPool](#popularitypool) | The pools to rank in. Unset is SYSTEM. | | lens | [ ActivityLens](#activitylens) | Which access counts, in the counts and the ranks alike. Unset is CONSUMPTION. Under DEVELOPMENT a measure's reads hold what was read to build it too. | ### BatchGetPopularityResponse (synq.entities.activity.v1alpha.BatchGetPopularityResponse) | Field | Type | Description | | - | - | - | | entities | [repeated EntityPopularity](#entitypopularity) | One per distinct asked id, in the order each was first asked. | | from | [ Timestamp](#timestamp) | The window read, \[from, to). | | to | [ Timestamp](#timestamp) | none | | covered\_hours | [ uint32](#uint32) | Hours of the window whose query history was read. An hour that was not read counts nothing either way. | | ranks\_unavailable | [ bool](#bool) | Set when the ranks could not be computed. The counts are still served, and every rank list is empty. | | ranks\_pending | [ bool](#bool) | Set when the ranks of the default window are not ready for every asked entity yet. The counts are served, and an entity has no ranks until they are. | | ranks\_window\_to | [ Timestamp](#timestamp) | The end of the window the ranks were computed for, exclusive, when it differs from to: the ranks of the default window are computed once a day, for the window ending at 00:00 UTC. | ### CurrentReading (synq.entities.activity.v1alpha.CurrentReading) CurrentReading is a platform's own current figure for an entity, such as "40 views in the last 28 days". Compare it only with readings of the same shape and window. | Field | Type | Description | | - | - | - | | shape | [ ActivityShape](#activityshape) | TRAILING\_WINDOW or LATEST\_VALUE. | | window\_days | [ uint32](#uint32) | M of "N in the last M days". Zero for a LATEST\_VALUE reading. | | count | [ uint64](#uint64) | N. | | observed\_at | [ Timestamp](#timestamp) | When the figure was read from the platform. | | direction | [ ActivityDirection](#activitydirection) | none | ### DirectionActors (synq.entities.activity.v1alpha.DirectionActors) | Field | Type | Description | | - | - | - | | direction | [ ActivityDirection](#activitydirection) | none | | measure | [ ActivityMeasure](#activitymeasure) | none | | total | [ uint64](#uint64) | The direction's count: every counted access, whoever it was. The lists below overlap, and a login can be left off one by its policy, so they do not add up to it. | | issuer\_entities | [repeated ActorActivity](#actoractivity) | none | | service\_accounts | [repeated ActorActivity](#actoractivity) | The workspace's service accounts first, then the built-in ones, each by count. | | tools | [repeated ActorActivity](#actoractivity) | none | | logins | [repeated ActorActivity](#actoractivity) | Every login, whatever issued its queries, except those whose policy keeps them off the frequent users list. A login known two ways is listed once per basis. | | unattributed | [ uint64](#uint64) | The count no login is named for. | ### DirectionSeries (synq.entities.activity.v1alpha.DirectionSeries) DirectionSeries is one direction's access over the window. | Field | Type | Description | | - | - | - | | direction | [ ActivityDirection](#activitydirection) | none | | measure | [ ActivityMeasure](#activitymeasure) | none | | total | [ uint64](#uint64) | none | | hourly | [repeated SeriesPoint](#seriespoint) | One point per UTC hour of the window. Empty for a measure platforms only report per day, such as VIEWS. | | daily | [repeated SeriesPoint](#seriespoint) | One point per day the window overlaps, in the asked time zone. | | grid | [ WeekGrid](#weekgrid) | Unset for a measure reported only per day. | ### EntityActors (synq.entities.activity.v1alpha.EntityActors) | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | actors | [repeated DirectionActors](#directionactors) | One per direction and measure with counted access: READ, INPUT, WRITE, then in measure order. INPUT is counted only under the DEVELOPMENT lens. | | not\_counted | [ NotCountedActivity](#notcountedactivity) | none | ### EntityPopularity (synq.entities.activity.v1alpha.EntityPopularity) | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | measures | [repeated MeasurePopularity](#measurepopularity) | One per measure with counted reads or writes, or with a current reading, in measure order. | | not\_counted | [ NotCountedActivity](#notcountedactivity) | Access the read saw and did not count. | ### EntityUsage (synq.entities.activity.v1alpha.EntityUsage) EntityUsage is how one entity is used. An entity is answered with the entities it is the same as, such as a dbt model and the table it builds, and with the other side of a share, so asking for the model or for its table gives the same roles. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | roles | [repeated UsageRole](#usagerole) | In role order, then by count, highest first. | | covered\_hours | [ uint32](#uint32) | Hours of the window whose query history was read. An hour that was not read counts nothing. | | window\_hours | [ uint32](#uint32) | The hours of the window. | ### GetActivityOverviewRequest (synq.entities.activity.v1alpha.GetActivityOverviewRequest) | Field | Type | Description | | - | - | - | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | time\_zone | [ string](#string) | The IANA time zone days and grid cells are in. Unset is UTC. | | pool | [ PopularityPool](#popularitypool) | The pool most\_read is ranked in. Unset is SYSTEM. | | measure | [ ActivityMeasure](#activitymeasure) | The measure most\_read reads. Unset is QUERIES. | | top\_k | [ uint32](#uint32) | At most this many most\_read rows. Unset is 20. | | selection | [ ActivitySelection](#activityselection) | Only these entities, such as a data product's. Unset is the whole workspace. A selection of more than 50,000 entities, counting the entities each is the same as, is refused with INVALID\_ARGUMENT. | Under a selection a group is its access to the selected entities, never its whole cost: its shares of its queries' weights, not the weights, so the groups add up to what the selection costs. A query that read three selected tables is three reads and its weight is counted once, so queries and weights are unset and reads, inputs and writes count the access. most\_read lists the selected entities, each with its rank in the whole pool. | \| include\_flows | [ bool](#bool) | Also count each group's reads, inputs and writes and the entities it read and wrote, and the live and touched tables. Without a selection they read the access to every entity, which can take seconds on a large workspace, so a client shows the groups first and asks for these in a second call. A selection always counts them, as they are its groups. | ### GetActivityOverviewResponse (synq.entities.activity.v1alpha.GetActivityOverviewResponse) | Field | Type | Description | | - | - | - | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | time\_zone | [ string](#string) | The time zone used, "UTC" when none was asked. | | covered\_hours | [ uint32](#uint32) | Hours of the window whose query history was read. | | queries | [ uint64](#uint64) | Every query of the workspace, Coalesce Quality's included, as they cost compute too. | | weights | [repeated PlatformWeights](#platformweights) | The workspace's weights per platform, by platform. | | groups | [repeated ActorGroup](#actorgroup) | By compute, highest first, then queries. | | most\_read | [repeated MostRead](#mostread) | The most read entities under CONSUMPTION, by reads. | | entities\_read | [ uint32](#uint32) | The entities with counted reads under CONSUMPTION, entities that are the same counted once. | | ranks\_unavailable | [ bool](#bool) | Set when the ranks could not be computed. The groups are still served, and most\_read is empty. | | entities\_live | [ uint32](#uint32) | The live warehouse tables and views of the workspace or the selection, entities that are the same counted once, and those of them anyone but Coalesce Quality read, input or wrote in the window, through them or through a table a share shows in another account, so "2,530 of 7,196 tables in use". A table on a platform with no query history in the window counts in neither. Only with include\_flows or a selection. | | entities\_touched | [ uint32](#uint32) | none | | shares | [repeated PlatformShares](#platformshares) | Under a selection: the selected entities' share of each platform's weights, by platform. Unset without one, where weights is the whole. | | flows\_included | [ bool](#bool) | Set when the groups' reads, inputs and writes and the live and touched tables were counted, with include\_flows or a selection. Unset, they read 0 because they were not asked for, and a client shows them as loading while it asks again with include\_flows. | ### GetActorSummaryRequest (synq.entities.activity.v1alpha.GetActorSummaryRequest) | Field | Type | Description | | - | - | - | | actor | [ ActorRef](#actorref) | none | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | time\_zone | [ string](#string) | The IANA time zone days and grid cells are in. Unset is UTC. | | top\_k | [ uint32](#uint32) | At most this many entities per direction. Unset is 20. | ### GetActorSummaryResponse (synq.entities.activity.v1alpha.GetActorSummaryResponse) | Field | Type | Description | | - | - | - | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | time\_zone | [ string](#string) | The time zone used, "UTC" when none was asked. | | platform\_user\_ids | [repeated string](#string) | The logins the actor resolved to, sorted. Empty without the platform users scope. | | totals | [ ActorTotals](#actortotals) | none | | computes | [repeated ActorComputeTotals](#actorcomputetotals) | Ordered by platform instance, then compute. | | entities | [repeated ActorEntityActivity](#actorentityactivity) | At most top\_k per direction, READ, INPUT, then WRITE, each by count. For a job, a WRITE row of measure RUNS counts the runs of what it builds, never write queries. | | hourly | [repeated SeriesPoint](#seriespoint) | The actor's queries per UTC hour, split by issuer. | | daily | [repeated SeriesPoint](#seriespoint) | none | | grid | [ WeekGrid](#weekgrid) | none | | issuer\_entities | [repeated ActorIssuerEntity](#actorissuerentity) | The jobs behind the actor's queries, such as a DAG, a dbt model, a Streamlit app, or a monitor or SQL test of Coalesce Quality's: by queries, highest first, then writes. At most top\_k. | | written\_schemas | [repeated ActorWrittenSchema](#actorwrittenschema) | What the actor wrote itself, per warehouse schema, by writes, highest first. Runs it orchestrated are not writes. The entities whose schema is not known are one entry with schema unset, last. | | file\_operations | [repeated ActorFileOperation](#actorfileoperation) | The actor's queries that moved files, per operation and location, such as the files it put to a stage, by queries, highest first. | ### GetEntityActivitySeriesRequest (synq.entities.activity.v1alpha.GetEntityActivitySeriesRequest) | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. 28 gives every weekday four times. | | lens | [ ActivityLens](#activitylens) | none | | measure | [ ActivityMeasure](#activitymeasure) | Unset is QUERIES. | | time\_zone | [ string](#string) | The IANA time zone days and grid cells are in, such as "Europe/Warsaw". Unset is UTC. The window itself stays in whole UTC hours. | | split | [ SeriesSplit](#seriessplit) | none | ### GetEntityActivitySeriesResponse (synq.entities.activity.v1alpha.GetEntityActivitySeriesResponse) | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | from | [ Timestamp](#timestamp) | The window read, \[from, to). | | to | [ Timestamp](#timestamp) | none | | time\_zone | [ string](#string) | The time zone used, "UTC" when none was asked. | | directions | [repeated DirectionSeries](#directionseries) | The lens's directions, then WRITE, each only when it has counted access. | | not\_counted | [ NotCountedActivity](#notcountedactivity) | none | ### ListAccessSignalsRequest (synq.entities.activity.v1alpha.ListAccessSignalsRequest) | Field | Type | Description | | - | - | - | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | selection | [ ActivitySelection](#activityselection) | Only these entities, such as a data product's. Unset is the whole workspace. A selection of more than 50,000 entities, counting the entities each is the same as, is refused with INVALID\_ARGUMENT. | | signal | [ AccessSignal](#accesssignal) | none | | pagination | [ Pagination](#pagination) | Without a page size every entity is returned. | ### ListAccessSignalsResponse (synq.entities.activity.v1alpha.ListAccessSignalsResponse) | Field | Type | Description | | - | - | - | | signal | [ AccessSignal](#accesssignal) | none | | entities | [repeated SignalEntity](#signalentity) | One page of the entities that raise the signal. BUILT\_NEVER\_READ by build compute, highest first, READ\_WITHOUT\_VIEWER by shared reads and WRITTEN\_OUTSIDE\_PIPELINE by outside writes, each then by entity id. UNTOUCHED by schema, then entity id, those with no known schema last. | | total | [ uint32](#uint32) | How many entities raise the signal, on every page. | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | page\_info | [ PageInfo](#pageinfo) | none | | schemas | [repeated SchemaSignal](#schemasignal) | UNTOUCHED: every schema with untouched tables and views, by how many, highest first. | | tools | [repeated ToolSharedReads](#toolsharedreads) | READ\_WITHOUT\_VIEWER: the counted reads of every entity per tool, and those of them through a shared login, by shared reads, highest first. | ### ListActorsRequest (synq.entities.activity.v1alpha.ListActorsRequest) | Field | Type | Description | | - | - | - | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | selection | [ ActivitySelection](#activityselection) | Only the access to these entities, such as a data product's. Unset is the whole workspace. Under a selection an actor is its access to the selected entities: its reads, inputs and writes and its shares of their cost, with no queries and no weights. A selection of more than 50,000 entities, counting the entities each is the same as, is refused with INVALID\_ARGUMENT. | | kinds | [repeated ActorKind](#actorkind) | Only actors of these kinds. Empty is every kind the caller may see. | | sort | [ ActorSort](#actorsort) | none | | platform | [ DataPlatformType](#dataplatformtype) | The platform ACTOR\_SORT\_COMPUTE sorts on and compute\_fraction is of. Required with it. | | pagination | [ Pagination](#pagination) | Without a page size every actor is returned. | ### ListActorsResponse (synq.entities.activity.v1alpha.ListActorsResponse) | Field | Type | Description | | - | - | - | | actors | [repeated ListedActor](#listedactor) | In the asked order. | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | page\_info | [ PageInfo](#pageinfo) | none | | people\_hidden | [ bool](#bool) | Set when the caller may not see people and logins: no PERSON or LOGIN actor is listed. | ### ListEntityActorsRequest (synq.entities.activity.v1alpha.ListEntityActorsRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | none | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | top\_k | [ uint32](#uint32) | At most this many entries per list. Unset returns every entry. | | lens | [ ActivityLens](#activitylens) | Which access counts. Unset is CONSUMPTION, under which each direction's total is what BatchGetPopularity counts. | | directions | [repeated ActivityDirection](#activitydirection) | Only these directions. Empty is every direction the lens serves. | | measures | [repeated ActivityMeasure](#activitymeasure) | Only these measures. Empty is every measure. | ### ListEntityActorsResponse (synq.entities.activity.v1alpha.ListEntityActorsResponse) | Field | Type | Description | | - | - | - | | entities | [repeated EntityActors](#entityactors) | One per distinct asked id, in the order each was first asked. | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | logins\_hidden | [ bool](#bool) | Set when the caller may not see logins: every logins list is empty. Every count is still served. | ### ListPersonActivityRequest (synq.entities.activity.v1alpha.ListPersonActivityRequest) | Field | Type | Description | | - | - | - | | identities | [repeated string](#string) | The identities of one person, as synq.users.v1 gives them, such as "synq:\", "email:\
" or "platform\_user:\". | | until | [ Timestamp](#timestamp) | The window ends at the start of this hour, exclusive. Unset is the current hour. | | window\_days | [ uint32](#uint32) | The window's length in days, back from until. Unset is 30. | | directions | [repeated ActivityDirection](#activitydirection) | Only these directions. Empty keeps every one. | | pagination | [ Pagination](#pagination) | Without a page size every entity is returned. | ### ListPersonActivityResponse (synq.entities.activity.v1alpha.ListPersonActivityResponse) | Field | Type | Description | | - | - | - | | entities | [repeated PersonEntityActivity](#personentityactivity) | Ordered by count, highest first, then entity id, direction and measure. | | platform\_user\_ids | [repeated string](#string) | The logins the identities resolved to, sorted. | | from | [ Timestamp](#timestamp) | none | | to | [ Timestamp](#timestamp) | none | | page\_info | [ PageInfo](#pageinfo) | none | ### ListedActor (synq.entities.activity.v1alpha.ListedActor) ListedActor is one actor of ListActors over the window. | Field | Type | Description | | - | - | - | | kind | [ ActorKind](#actorkind) | none | | actor | [ ActorRef](#actorref) | The actor to ask GetActorSummary about. Without a selection its summary has the same totals. | | built\_in | [ bool](#bool) | Set when actor names a built-in account. | | entity\_id | [ string](#string) | For a service account, its entity id, which resolves to its name like any other entity. | | logins | [ uint32](#uint32) | The distinct logins behind its queries and its access. | | totals | [ ActorTotals](#actortotals) | As GetActorSummary has them. Under a selection, the access to the selected entities only: queries, weights, runs and outside\_entities are unset. | | shares | [repeated PlatformShares](#platformshares) | Under a selection: its share of what the selected entities cost, by platform. | | issuers | [repeated IssuerCount](#issuercount) | Its queries per issuing tool, highest first, then by issuer, such as how much of a person's work ran through dbt. Empty under a selection. | | compute\_fraction | [ double](#double) | With a platform: its compute on the platform over the platform's whole compute, or over what the selected entities cost on it, from 0 to 1. The actors overlap, so their fractions do not add up to 1. | ### MeasurePopularity (synq.entities.activity.v1alpha.MeasurePopularity) MeasurePopularity is one measure's answer. For RUNS, writes is the runs of what builds the entity, each counted once whatever orchestrators ran it, last\_written\_at the last run and write\_cadence how often it runs. RUNS has no reads, no logins and no ranks. | Field | Type | Description | | - | - | - | | measure | [ ActivityMeasure](#activitymeasure) | none | | reads | [ uint64](#uint64) | Counted reads, and the distinct logins among them. A login is not a person. A read with no login counts in reads, never in reader\_logins. | | reader\_logins | [ uint32](#uint32) | none | | last\_read\_at | [ Timestamp](#timestamp) | none | | writes | [ uint64](#uint64) | none | | writer\_logins | [ uint32](#uint32) | none | | last\_written\_at | [ Timestamp](#timestamp) | none | | write\_cadence | [ WriteCadence](#writecadence) | none | | member\_entity\_ids | [repeated string](#string) | The entities the same as the asked one whose access answered. | | ranks | [repeated PoolRank](#poolrank) | The entity's rank in each pool of the asked kind where it has reads. Empty when it has none. | | readings | [repeated CurrentReading](#currentreading) | The platform's own current figures for the entity, one per direction, shape and window. They are not in reads or writes: a trailing window or a latest value cannot be split into the hours of the window. | ### MostRead (synq.entities.activity.v1alpha.MostRead) MostRead is one entity's place in one pool. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The entity, or the smallest id among the entities it is the same as. | | reads | [ uint64](#uint64) | none | | rank | [ PoolRank](#poolrank) | none | ### PersonEntityActivity (synq.entities.activity.v1alpha.PersonEntityActivity) PersonEntityActivity is what a person's logins did to one entity in one direction and measure. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | direction | [ ActivityDirection](#activitydirection) | none | | measure | [ ActivityMeasure](#activitymeasure) | none | | count | [ uint64](#uint64) | none | | last\_seen\_at | [ Timestamp](#timestamp) | none | ### SchemaSignal (synq.entities.activity.v1alpha.SchemaSignal) SchemaSignal is one schema's untouched tables and views. | Field | Type | Description | | - | - | - | | schema | [ WarehouseSchema](#warehouseschema) | none | | entities | [ uint32](#uint32) | none | ### SignalEntity (synq.entities.activity.v1alpha.SignalEntity) SignalEntity is one entity a signal names: an entity with the entities it is the same as, the tables a share shows in other accounts included, by the smallest id among them, or for UNTOUCHED the table or view itself. A read of any of them is a read of all, as in popularity. Only the fields of the signal asked are set. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | write\_queries | [ uint64](#uint64) | BUILT\_NEVER\_READ: the pipeline's write queries and its runs, two measures that never add up, its share of the queries' cost by platform, and when it last wrote. | | write\_runs | [ uint64](#uint64) | none | | build\_shares | [repeated PlatformShares](#platformshares) | none | | last\_written\_at | [ Timestamp](#timestamp) | none | | schema | [ WarehouseSchema](#warehouseschema) | UNTOUCHED: where it lives. Unset when its address is not known. | | reads | [ uint64](#uint64) | READ\_WITHOUT\_VIEWER: its counted reads, and those through a shared login. | | shared\_reads | [ uint64](#uint64) | none | | outside\_writes | [ uint64](#uint64) | WRITTEN\_OUTSIDE\_PIPELINE: the writes no pipeline explains, and the distinct logins behind them. | | writing\_logins | [ uint32](#uint32) | none | ### ToolSharedReads (synq.entities.activity.v1alpha.ToolSharedReads) ToolSharedReads is one tool's counted reads, and the part of them through a shared login. | Field | Type | Description | | - | - | - | | issuer | [ DataPlatformType](#dataplatformtype) | none | | reads | [ uint64](#uint64) | none | | shared\_reads | [ uint64](#uint64) | none | | share | [ double](#double) | shared\_reads over reads, from 0 to 1. | ### UsageRole (synq.entities.activity.v1alpha.UsageRole) UsageRole is one actor in one role of an entity. Coalesce Quality's own queries are never a role. | Field | Type | Description | | - | - | - | | role | [ UsageRoleKind](#usagerolekind) | none | | level | [ UsageLevel](#usagelevel) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.issuer\_entity\_id | [ string](#string) | For ENTITY: the job, task, step, model or app, such as "dbt model M builds this". | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) actor.service\_account\_id | [ string](#string) | For SERVICE\_ACCOUNT: the service account, a built-in one included. | | issuer | [ DataPlatformType](#dataplatformtype) | The tool, such as Fivetran, Airflow, dbt or Looker Studio. Unspecified on a PEOPLE, LOGINS or UNKNOWN role, and on a service account whose queries name no tool. | | built\_in | [ bool](#bool) | Set when service\_account\_id names a built-in account. | | entity\_id | [ string](#string) | For a service account, its entity id, which resolves to its name like any other entity. | | evidence | [ UsageEvidence](#usageevidence) | none | | count | [ uint64](#uint64) | Runs, writes or reads, as evidence says. 0 for IDENTITY. | | actors | [ uint32](#uint32) | The people behind a PEOPLE role, a person once however many logins they used, or the logins behind a LOGINS role. | | last\_seen\_at | [ Timestamp](#timestamp) | none | | cadence | [ WriteCadence](#writecadence) | How often the actor did it in the window. NONE for IDENTITY. | | counts\_for\_popularity | [ bool](#bool) | On a READ or REVERSE\_ETL role: whether some of its reads count toward popularity. False when the service account's popularity policy leaves them all out, and always false on the other roles. | | more | [ uint32](#uint32) | How many roles of this kind top\_k cut, set on the last one kept. | ### WarehouseSchema (synq.entities.activity.v1alpha.WarehouseSchema) WarehouseSchema is a schema of one warehouse instance, as the warehouse names it. | Field | Type | Description | | - | - | - | | instance | [ string](#string) | The instance, such as a Snowflake account or a BigQuery project. | | database | [ string](#string) | none | | schema | [ string](#string) | none | ### BatchOrchestrationRequest (synq.entities.orchestration.v1.BatchOrchestrationRequest) | Field | Type | Description | | - | - | - | | entities | [repeated Identifier](#identifier) | Entities to query for orchestration relationships (e.g., Airflow tasks, dbt Cloud job steps, Coalesce jobs, dbt models, tables) | ### BatchOrchestrationResponse (synq.entities.orchestration.v1.BatchOrchestrationResponse) | Field | Type | Description | | - | - | - | | orchestrations | [repeated Orchestration](#orchestration) | Orchestration relationships for each requested entity, in the order of the request. An entity requested twice is answered once, and an entity the workspace does not hold is left out. | ### Orchestration (synq.entities.orchestration.v1.Orchestration) Orchestration represents the orchestration relationships for a given entity: what ran it (upstream) and what it ran (downstream), in the last 31 days. A group that is both is in both lists. Groups are ordered by how many times they ran, most first. | Field | Type | Description | | - | - | - | | entity | [ OrchestrationGroup](#orchestrationgroup) | The entity being queried along with its other identities. For example, if querying a dbt model, this group includes both the model and the table it creates, as they represent the same logical concept. | | downstream | [repeated OrchestrationGroup](#orchestrationgroup) | Downstream: the entities this job, job step or task ran in the last 31 days. Each group contains all identities of the entity that ran. Examples: - If entity is an Airflow task: groups containing \[dbt model, table], or the dbt seeds and snapshots it ran - If entity is an Airflow DAG: groups containing its tasks - If entity is a dbt Cloud job step: groups containing \[dbt model, table] - If entity is a Coalesce job: groups containing its Coalesce nodes | | upstream | [repeated OrchestrationGroup](#orchestrationgroup) | Upstream: the jobs, job steps and tasks that ran this entity in the last 31 days. Each group contains all identities of the job, job step or task. Examples: - If entity is a dbt model or table: groups containing the Airflow task or dbt Cloud job step that ran it - If entity is a Coalesce node: groups containing the Coalesce job that ran it - If entity is an Airflow task: groups containing its Airflow DAG | ### 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 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 | ### BatchGetCheckCategoriesRequest (synq.entities.checks.v2.BatchGetCheckCategoriesRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | Checks to read (1–500, unique). | ### BatchGetCheckCategoriesResponse (synq.entities.checks.v2.BatchGetCheckCategoriesResponse) | Field | Type | Description | | - | - | - | | categories | [map CategoriesEntry](#categoriesentry) | Category state keyed by check id. Ids that do not exist are absent. | ### BatchGetCheckCategoriesResponse.CategoriesEntry (synq.entities.checks.v2.BatchGetCheckCategoriesResponse.CategoriesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CheckCategories](#checkcategories) | none | ### DeleteCheckCategoriesRequest (synq.entities.checks.v2.DeleteCheckCategoriesRequest) | Field | Type | Description | | - | - | - | | categories | [repeated CheckCategoryDeletion](#checkcategorydeletion) | The checks to clear. Every entry must name a distinct check. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is making the change. See UpsertCheckCategoriesRequest.actor. | ### DeleteCheckCategoriesResponse (synq.entities.checks.v2.DeleteCheckCategoriesResponse) ### ListCategoriesRequest (synq.entities.checks.v2.ListCategoriesRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dimension.dimension | [optional CategoryDimension](#categorydimension) | Restrict to one dimension. Omit to return both. | ### ListCategoriesResponse (synq.entities.checks.v2.ListCategoriesResponse) | Field | Type | Description | | - | - | - | | categories | [repeated CategoryInfo](#categoryinfo) | Every category name in use, sorted by name within each dimension. | | dimensions | [repeated DimensionSummary](#dimensionsummary) | Coverage per dimension, so "N of M checks categorised" can be rendered without summing the entries above. | ### ListCategorisationFiltersRequest (synq.entities.checks.v2.ListCategorisationFiltersRequest) | Field | Type | Description | | - | - | - | | selected | [ CategorisationFacets](#categorisationfacets) | The values already chosen, if any. Each returned list is narrowed to values that co-occur with this selection. | ### ListCategorisationFiltersResponse (synq.entities.checks.v2.ListCategorisationFiltersResponse) | Field | Type | Description | | - | - | - | | available | [ CategorisationFacets](#categorisationfacets) | The values available given `selected`. | ### ListCheckCategoriesRequest (synq.entities.checks.v2.ListCheckCategoriesRequest) | Field | Type | Description | | - | - | - | | technical\_filter | [ CategorisationFilter](#categorisationfilter) | Keep only checks that are, or are not, categorised on the technical dimension. | | governance\_filter | [ CategorisationFilter](#categorisationfilter) | Keep only checks that are, or are not, categorised on the governance dimension. | | technical\_override\_filter | [ OverrideFilter](#overridefilter) | Keep only checks whose technical category was, or was not, set explicitly. | | governance\_override\_filter | [ OverrideFilter](#overridefilter) | Keep only checks whose governance category was, or was not, set explicitly. | | rule\_ids | [repeated string](#string) | Keep only checks currently categorised by one of these rules, on either dimension. This is the paginated companion to ChecksCategorisationRulesService.ListRuleMatches, which reports exact counts and a sample per rule. | | technical\_categories | [repeated string](#string) | Keep only checks whose effective technical category is one of these. | | governance\_categories | [repeated string](#string) | Keep only checks whose effective governance category is one of these. | | attributes | [ CategorisationFacets](#categorisationfacets) | Keep only checks with these attributes — the same platform / entity type / package / kind selection a categorisation rule matches on, so a listing can be narrowed to exactly the checks a candidate rule would consider. | | entity\_ids | [repeated string](#string) | Keep only these checks. Combines with the other filters, so it answers "which of these checks are uncategorised" in a single call. | | pagination | [ Pagination](#pagination) | Pagination. Defaults to 200 checks per page. | ### ListCheckCategoriesResponse (synq.entities.checks.v2.ListCheckCategoriesResponse) | Field | Type | Description | | - | - | - | | categories | [repeated CheckCategories](#checkcategories) | The matching checks, ordered by entity id. | | page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. Empty when this is the last page. | ### UpsertCheckCategoriesRequest (synq.entities.checks.v2.UpsertCheckCategoriesRequest) | Field | Type | Description | | - | - | - | | categories | [repeated CheckCategoryUpdate](#checkcategoryupdate) | The checks to categorise. Every entry must name a distinct check. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is making the change, when the caller acts on someone's behalf — an agent, a bot, an automation. Recorded as the editor and shown back on reads. Omit it when the caller's own credentials already identify them. | ### UpsertCheckCategoriesResponse (synq.entities.checks.v2.UpsertCheckCategoriesResponse) | Field | Type | Description | | - | - | - | | categories | [repeated CheckCategories](#checkcategories) | The resolved category state of each updated check, in request order. | ### CategorisationRule (synq.entities.checks.v2.CategorisationRule) A rule that assigns a category to every check it matches. Rules are how a workspace categorises at scale: they apply to the checks that exist today and to every check ingested afterwards, so nobody has to revisit individual checks as tools publish new ones. Rules resolve independently per dimension, and exactly one rule wins a check. Rules are tried in this order, and the first whose matcher matches assigns the category: 1. Scope first. Every workspace rule is tried before any platform-provided one, whatever their priorities are — so a workspace rule at priority 0 still beats a global rule at priority 1000. This is what makes your own rules an override of the defaults rather than a competitor to them. 2. Then priority, highest number first. `priority` is a rank, not a position: 10 is tried before 1. 3. Then, among rules of equal scope and priority, most recently updated first, and finally by id. `resolution_order` reports the resulting position, so you never have to reproduce this ordering yourself. A category a rule computes is used only when the check has neither a category set explicitly on it nor one its producer declared. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Client-supplied UUID identifying the rule. | | dimension | [ CategoryDimension](#categorydimension) | The dimension this rule categorises along. | | scope | [ RuleScope](#rulescope) | Whether the rule belongs to the workspace or is a platform default. | | title | [ string](#string) | Human-readable title, shown wherever the rule is credited for a category. | | category | [ string](#string) | The category assigned to matching checks. | | matcher | [ CheckMatcher](#checkmatcher) | Which checks the rule applies to. | | priority | [ int32](#int32) | Rank within the rule's scope: the highest number is tried first. Ties are broken as described above. | | resolution\_order | [ int32](#int32) | Position of this rule in the order rules are tried for its dimension, counting from 0 across both scopes — 0 is the rule that gets first refusal on every check. Output-only, and recomputed whenever any rule in the dimension changes. | | updated\_by | [ Actor](#actor) | Who last edited the rule: display name, and the account or channel they acted through. Absent on a platform-provided rule, which nobody in your workspace edited, and on a rule whose editor could not be resolved to anything a reader would recognise. Output-only. | | etag | [ string](#string) | Optimistic-concurrency token: pass it back on UpsertRule or DeleteRule to have the write rejected if the rule changed in the meantime. Form: `W/"-"`. | | created\_at | [ Timestamp](#timestamp) | When the rule was created. Output-only. | | updated\_at | [ Timestamp](#timestamp) | When the rule was last updated. Output-only. | ### CheckCategories (synq.entities.checks.v2.CheckCategories) The category state of a single check, on both dimensions. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The check this describes. Treat it as opaque: acquire it from a listing or from IdentifierResolveService and pass it back unchanged. | | technical | [ ResolvedCategory](#resolvedcategory) | Technical category — what kind of check this is, mechanically. | | governance | [ ResolvedCategory](#resolvedcategory) | Governance category — what the check is for. | | check | [ CheckSummary](#checksummary) | What the check is, so a listing is actionable on its own. Absent for a check that carries an explicit category but is not (or is no longer) present in the catalogue. | | etag | [ string](#string) | Optimistic-concurrency token covering the categories set explicitly on this check. Pass it back on UpsertCheckCategories or DeleteCheckCategories to have the write rejected if someone changed them in the meantime. Empty when the check carries no explicit category. Form: `W/"-"`. | | updated\_by | [ Actor](#actor) | Who last set the explicit categories: display name, and the account or channel they acted through. Absent when no explicit categories are set, and when the setter could not be resolved to anything a reader would recognise. | | updated\_at | [ Timestamp](#timestamp) | When the explicit categories were last changed. Absent when none are set. | ### CheckCategoryDeletion (synq.entities.checks.v2.CheckCategoryDeletion) One check whose explicit categories should be cleared, on both dimensions. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The check to clear. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard, with the same meaning as on CheckCategoryUpdate. | ### CheckCategoryUpdate (synq.entities.checks.v2.CheckCategoryUpdate) The categories to set explicitly on one check. Each dimension is updated independently, and presence is meaningful: omit a field to leave that dimension as it is, send an empty string to clear it so the check falls back to its producer-declared or rule-computed value, send a non-empty string to set or replace it. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The check to categorise. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_technical.technical | [optional string](#string) | Technical category to set — what kind of check this is, mechanically. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance.governance | [optional string](#string) | Governance category to set — what the check is for. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict if the check's explicit categories changed since this etag was read. Pass an empty string to require that the check has no explicit category yet, which turns the write into a create-only operation. | ### ComputedCategory (synq.entities.checks.v2.ComputedCategory) What the workspace's categorisation rules compute for a check on one dimension, whatever ends up in effect. | Field | Type | Description | | - | - | - | | category | [ string](#string) | The category the rule assigns. | | rule\_id | [ string](#string) | The rule that assigns it. Pass it to BatchGetRules to read the rule, or to ListCheckCategories to list every check the rule categorised. | | rule\_title | [ string](#string) | Title of that rule, so it can be named without a second call. | ### ResolvedCategory (synq.entities.checks.v2.ResolvedCategory) The category a check resolves to on one dimension, together with where that value came from. Reading `source` matters as much as reading `category`: a value that came from a rule changes when the rules change, while one set explicitly on the check stays until someone clears it. | Field | Type | Description | | - | - | - | | category | [ string](#string) | The category in effect. Empty when the check is uncategorised on this dimension. | | source | [ CategorySource](#categorysource) | Which of the three sources produced `category`. | | override | [ string](#string) | The category set explicitly on the check, if any. Populated whatever the effective value is, so you can tell an explicit category apart from the one it replaced. Empty when none is set. | | rule\_id | [ string](#string) | The rule that computed the category. Populated only when `source` is CATEGORY\_SOURCE\_RULE; pass it to BatchGetRules to read the rule, or to ListCheckCategories to list every check the rule categorised. | | rule\_title | [ string](#string) | Title of the rule named by `rule_id`, so "categorised by …" can be rendered without a second call. | | rule\_scope | [ RuleScope](#rulescope) | Whether the rule that won is one of the workspace's own or a platform-provided default. Populated only when `source` is CATEGORY\_SOURCE\_RULE. | | computed | [ ComputedCategory](#computedcategory) | What the categorisation rules compute for this check, populated whenever a rule matches it at all. | When `source` is CATEGORY\_SOURCE\_RULE this is the value in effect and repeats `category`. When a category set explicitly on the check, or one its producer declared, is standing in front of the rules, this is what the check falls back to once that is cleared — the one part of the resolution a client cannot work out from the fields above. Absent when no rule matches. | ### AnnotationMatch (synq.entities.checks.v2.AnnotationMatch) A condition on one annotation of a check. Annotations are the key/value metadata a producer attaches to a check — a dbt test's `meta` entries, for example — which makes them the way to categorise by something only your own team knows, such as a domain or an owning squad. | Field | Type | Description | | - | - | - | | key | [ string](#string) | Annotation key to look up on the check. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) match.exists | [ bool](#bool) | Matches when the key is present, whatever its value. Set it to true; a false value is not a negation and is rejected. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) match.equals | [ string](#string) | Matches when the value equals this string exactly. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) match.in | [ AnnotationValues](#annotationvalues) | Matches when the value is one of these. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) match.regex | [ string](#string) | Matches when the value matches this RE2 regular expression. | ### AnnotationValues (synq.entities.checks.v2.AnnotationValues) A list of accepted annotation values. | Field | Type | Description | | - | - | - | | values | [repeated string](#string) | none | ### CheckAttributesMatcher (synq.entities.checks.v2.CheckAttributesMatcher) Selects checks by their attributes. A check matches when every populated field matches it; an empty field places no constraint, so an entirely empty matcher matches every check in the workspace. This is the form to reach for first: it is what the rule editor writes, what reads back legibly, and what ListCategorisationFilters offers values for. | Field | Type | Description | | - | - | - | | facets | [ CategorisationFacets](#categorisationfacets) | Platform, entity type, package and kind the check must be one of. | | names | [repeated string](#string) | Patterns matched against the check's name. `*` stands for any sequence of characters, including none; every other character matches literally. A check matches when at least one pattern matches. An empty list matches any name. | | annotation\_matches | [repeated AnnotationMatch](#annotationmatch) | Conditions on the check's annotations. A check must satisfy every entry. | ### CheckMatcher (synq.entities.checks.v2.CheckMatcher) Which checks a categorisation rule applies to. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) matcher.attributes | [ CheckAttributesMatcher](#checkattributesmatcher) | Select checks by their attributes. Covers almost every rule and is the only form the rule editor can render. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) matcher.expression | [ string](#string) | A CEL expression returning a boolean, for the rare predicate the attribute matcher cannot express — combining alternatives across dimensions, or matching on a substring of a name. See [https://github.com/google/cel-spec](https://github.com/google/cel-spec) for the language. | Variables available to the expression: platform, asset\_type, package, kind, name, description (string) is\_platform\_native (bool) annotations (map\) Platform and entity-type enum value names are available as string constants. For example: platform == PLATFORM\_DBT && kind.startsWith("not\_null") | ### CheckSummary (synq.entities.checks.v2.CheckSummary) Enough of a check to recognise it and act on it without a second call. Every field is output-only and reflects the check as the tool that produced it described it — a dbt test, a monitor, a reconciliation case. Nothing here is editable through the categorisation API; to change any of it, change it in the tool that publishes the check. | Field | Type | Description | | - | - | - | | name | [ string](#string) | Name of the check, as its producer names it. Always the last element of `full_name` when that is populated; kept as its own field so a client that only needs the label never has to index into an array. | | full\_name | [repeated string](#string) | Full display path down to the check, root first and leaf last — suitable for rendering a breadcrumb as-is, the same order and meaning as `synq.entities.folders.v1.Folder.full_name`: `["prod", "analytics", "orders", "not_null_customer_id"]`. | The leading segments are the producer's own containers — a dbt project, a warehouse database and schema — so how many there are varies by platform. Drop the last element for the path to the check's parent. | \| package | [ string](#string) | Package the check comes from, e.g. "dbt", "dbt\_utils". Empty when the producer has no notion of packages. | \| kind | [ string](#string) | General kind of the check, e.g. "not\_null", "unique", "row\_count". This is the attribute categorisation rules most often match on. | \| entity\_type | [ EntityType](#entitytype) | Entity type of the check itself, e.g. ENTITY\_TYPE\_DBT\_TEST. | \| data\_platform\_type | [ DataPlatformType](#dataplatformtype) | Platform the check runs on, e.g. DATA\_PLATFORM\_TYPE\_DBT. | \| is\_platform\_native | [ bool](#bool) | Whether the check is native to its platform (a dbt test in a dbt project) rather than defined in Coalesce Quality. | \| description | [ string](#string) | Description of the check, where the producer supplied one. | \| checked\_entity\_ids | [repeated string](#string) | The entities the check validates. Empty when the check's targets could not be resolved. | \| annotations | [map AnnotationsEntry](#annotationsentry) | Free-form key/value metadata the tool that produced the check attached to it — a dbt test's `meta` entries, a SQLMesh audit's, a custom label. This is what a categorisation rule's `annotation_matches` predicate is written against, so reading them is how you find out what there is to match on in your own workspace. | ### CheckSummary.AnnotationsEntry (synq.entities.checks.v2.CheckSummary.AnnotationsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ string](#string) | none | ### BatchGetRulesRequest (synq.entities.checks.v2.BatchGetRulesRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | Rule ids to read (1–200, unique). | ### BatchGetRulesResponse (synq.entities.checks.v2.BatchGetRulesResponse) | Field | Type | Description | | - | - | - | | rules | [map RulesEntry](#rulesentry) | Rules keyed by id. Ids the caller cannot see, or that do not exist, are absent. | ### BatchGetRulesResponse.RulesEntry (synq.entities.checks.v2.BatchGetRulesResponse.RulesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ CategorisationRule](#categorisationrule) | none | ### DeleteRuleRequest (synq.entities.checks.v2.DeleteRuleRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Id of the rule to delete. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is making the change. See UpsertRuleRequest.actor. | ### DeleteRuleResponse (synq.entities.checks.v2.DeleteRuleResponse) ### GetRecategorisationStatusRequest (synq.entities.checks.v2.GetRecategorisationStatusRequest) ### GetRecategorisationStatusResponse (synq.entities.checks.v2.GetRecategorisationStatusResponse) | Field | Type | Description | | - | - | - | | status | [ RecategorisationStatus](#recategorisationstatus) | Progress of the caller's workspace sweep. | ### ListRuleMatchesRequest (synq.entities.checks.v2.ListRuleMatchesRequest) | Field | Type | Description | | - | - | - | | rule\_ids | [repeated string](#string) | Rules to report on. Empty returns every rule that currently categorises at least one check. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sample\_size.sample\_size | [optional int32](#int32) | How many check ids to return per rule as a sample. Defaults to 100, and may be 0 for counts only. The counts are always exact whatever this is set to. | ### ListRuleMatchesResponse (synq.entities.checks.v2.ListRuleMatchesResponse) | Field | Type | Description | | - | - | - | | matches | [map MatchesEntry](#matchesentry) | Matches keyed by rule id. Rules that currently categorise nothing are absent. | ### ListRuleMatchesResponse.MatchesEntry (synq.entities.checks.v2.ListRuleMatchesResponse.MatchesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ RuleMatches](#rulematches) | none | ### ListRulesRequest (synq.entities.checks.v2.ListRulesRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dimension.dimension | [optional CategoryDimension](#categorydimension) | Restrict to one dimension. Omit to return both. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scope.scope | [optional RuleScope](#rulescope) | Restrict to the workspace's own rules or to the platform-provided ones. Omit to return both. | | pagination | [ Pagination](#pagination) | Pagination. Defaults to 200 rules per page. | ### ListRulesResponse (synq.entities.checks.v2.ListRulesResponse) | Field | Type | Description | | - | - | - | | rules | [repeated CategorisationRule](#categorisationrule) | Matching rules, in the order they are tried: workspace rules before platform-provided ones, then by descending priority. | | page\_info | [ PageInfo](#pageinfo) | Pagination cursor for the next page. Empty when this is the last page. | ### PreviewRuleRequest (synq.entities.checks.v2.PreviewRuleRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_id.id | [optional string](#string) | Set to an existing rule's id to preview an edit to it — the candidate replaces that rule during resolution, so the result reflects the change rather than the addition of a second rule. Omit to preview a new rule. | | dimension | [ CategoryDimension](#categorydimension) | The dimension the candidate would categorise along. | | scope | [ RuleScope](#rulescope) | Scope the candidate would be saved with. Defaults to RULE\_SCOPE\_WORKSPACE. | | title | [ string](#string) | Title the candidate would be saved with. Does not affect the outcome. | | category | [ string](#string) | The category the candidate would assign. | | matcher | [ CheckMatcher](#checkmatcher) | Which checks the candidate would apply to. | | priority | [ int32](#int32) | Priority the candidate would be saved with. It participates in resolution exactly as it would once saved, so previewing at the wrong priority reports the wrong impact. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sample\_size.sample\_size | [optional int32](#int32) | How many check ids to return in each of the response's samples — it caps `affected_entity_ids` and `explicit_category_entity_ids` independently, so either may come back at this size. Defaults to 100, and may be 0 for counts only. The counts are always exact whatever this is set to. | ### PreviewRuleResponse (synq.entities.checks.v2.PreviewRuleResponse) | Field | Type | Description | | - | - | - | | matched\_count | [ int64](#int64) | Checks whose predicate the candidate matches at all — its raw reach, whether or not it ends up winning them. | | affected\_count | [ int64](#int64) | Checks whose effective category on the candidate's dimension would actually change. This is the rule's real impact. It equals newly\_categorised\_count + reassigned\_count, and matched\_count equals this plus unchanged\_count. | | newly\_categorised\_count | [ int64](#int64) | Of the affected checks, how many have no category on this dimension today. | | reassigned\_count | [ int64](#int64) | Of the affected checks, how many already have a different category that the candidate would take over. Worth a second look before saving. | | unchanged\_count | [ int64](#int64) | Checks the candidate matches whose effective category would not change. The three fields below say why, and add up to this one. | | affected\_entity\_ids | [repeated string](#string) | A sample of the affected checks, ordered by entity id. | | affected\_entity\_ids\_truncated | [ bool](#bool) | True when the sample was cut short by `sample_size`. | | higher\_priority\_rule\_count | [ int64](#int64) | Of the unchanged checks, how many a rule of higher priority already wins, so the candidate never gets to assign anything. Raise the candidate's priority to take these over. | | explicit\_category\_count | [ int64](#int64) | Of the unchanged checks, how many carry a category set explicitly on the check, or declared by the tool that produced it. Either outranks every rule, so these are the checks the candidate looks like it covers and does not — no priority will win them. Clear the explicit category to hand a check back to the rules. | | same\_category\_count | [ int64](#int64) | Of the unchanged checks, how many the candidate does win, assigning the category the check already has. Nothing to do about these; the rule is simply agreeing with what is there. | | explicit\_category\_entity\_ids | [repeated string](#string) | A sample of the checks counted in `explicit_category_count`, ordered by entity id — the ones worth showing a customer, because a rule that reads as covering them does not. | | explicit\_category\_entity\_ids\_truncated | [ bool](#bool) | True when that sample was cut short by `sample_size`. | ### UpsertRuleRequest (synq.entities.checks.v2.UpsertRuleRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Client-supplied UUID identifying the rule. The same id updates the same rule; a new id creates a new rule. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_dimension.dimension | [optional CategoryDimension](#categorydimension) | The dimension the rule categorises along. Required when creating; omit to keep it on update. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scope.scope | [optional RuleScope](#rulescope) | Scope of the rule. Defaults to RULE\_SCOPE\_WORKSPACE when creating; omit to keep it on update. Platform-provided rules cannot be edited from a workspace. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_title.title | [optional string](#string) | Human-readable title, shown wherever the rule is credited for a category. Required when creating; omit to keep it on update. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | The category assigned to matching checks. Required when creating; omit to keep it on update. Prefer a name the workspace already uses — read them from ChecksCategoriesService.ListCategories. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_matcher.matcher | [optional CheckMatcher](#checkmatcher) | Which checks the rule applies to. Required when creating; omit to keep it on update. Replaces the previous matcher wholesale — there is no partial update within a matcher. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_priority.priority | [optional int32](#int32) | Rank within the rule's scope: the highest number is tried first. Defaults to 0 when creating; omit to keep it on update. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | Optional optimistic-concurrency guard. When set, the write fails with a conflict if the rule was modified since this etag was read. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_actor.actor | [optional Actor](#actor) | Who is making the change, when the caller acts on someone's behalf — an agent, a bot, an automation. Recorded as the editor and shown back on reads. Omit it when the caller's own credentials already identify them. | ### UpsertRuleResponse (synq.entities.checks.v2.UpsertRuleResponse) | Field | Type | Description | | - | - | - | | rule | [ CategorisationRule](#categorisationrule) | The stored rule after the write. | ### RuleMatches (synq.entities.checks.v2.RuleMatches) The checks one categorisation rule currently categorises — the state already applied to the workspace, not a projection of what a rule would do. The count is always exact. The sample is a readable excerpt, not the full set: to page through every check a rule categorised, call ListCheckCategories with the rule's id. | Field | Type | Description | | - | - | - | | check\_count | [ int64](#int64) | How many checks the rule categorises in the workspace. | | sample\_entity\_ids | [repeated string](#string) | A sample of those checks, ordered by entity id. | | sample\_truncated | [ bool](#bool) | True when the sample was cut short, meaning the rule categorises more checks than the sample shows. | ### CategorisationFacets (synq.entities.checks.v2.CategorisationFacets) A set of check attributes. The same four dimensions select checks in three places — the predicate of a categorisation rule, the filter on a check listing, and the values a workspace actually has — so one message carries them everywhere and a value read from one can be passed straight to the next. An empty list places no constraint on its dimension. Within a list the values are alternatives; across lists they combine. | Field | Type | Description | | - | - | - | | data\_platform\_types | [repeated DataPlatformType](#dataplatformtype) | Platforms the check runs on. | | entity\_types | [repeated EntityType](#entitytype) | Entity types of the check itself, e.g. ENTITY\_TYPE\_DBT\_TEST. | | packages | [repeated string](#string) | Packages the check comes from, e.g. "dbt\_utils". | | kinds | [repeated string](#string) | Check kinds, e.g. "not\_null", "unique". | ### CategoryInfo (synq.entities.checks.v2.CategoryInfo) One category name in a workspace's vocabulary, with how it is produced and how much of the workspace currently carries it. Category names are free-form workspace strings, not a fixed list. Offering this vocabulary in a picker rather than a text box is what keeps a workspace converging on one spelling per concept. | Field | Type | Description | | - | - | - | | name | [ string](#string) | The category name. | | dimension | [ CategoryDimension](#categorydimension) | The dimension the name belongs to. The same name can exist on both dimensions; they are separate entries. | | has\_workspace\_rule | [ bool](#bool) | At least one rule in the caller's workspace produces this category. | | has\_global\_rule | [ bool](#bool) | At least one platform-provided rule produces this category. | | check\_count | [ int64](#int64) | How many checks currently resolve to this category on this dimension, whatever produced it. A name can have rules and no checks (nothing matches yet), or checks and no rules (every one of them was categorised explicitly or by its producer). | ### DimensionSummary (synq.entities.checks.v2.DimensionSummary) How much of a workspace one dimension covers. | Field | Type | Description | | - | - | - | | dimension | [ CategoryDimension](#categorydimension) | The dimension summarised. | | categorised\_check\_count | [ int64](#int64) | Checks in the workspace with a category on this dimension. | | uncategorised\_check\_count | [ int64](#int64) | Checks in the workspace with no category on this dimension. This is the number to drive down. | ### RecategorisationStatus (synq.entities.checks.v2.RecategorisationStatus) Progress of the workspace-wide re-categorisation that follows a rule change. A rule change takes effect on newly ingested checks immediately. Checks that already exist are rewritten by a sweep, scheduled automatically whenever rules are created, updated or deleted; several edits in quick succession coalesce into one sweep. The sweep normally completes in seconds, so reading this is about confirming a change landed rather than waiting on it — until it finishes, some checks still carry the categories the previous rules gave them. | Field | Type | Description | | - | - | - | | state | [ State](#state) | Current state of the sweep. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scheduled\_at.scheduled\_at | [optional Timestamp](#timestamp) | When the pending sweep was queued. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_started\_at.started\_at | [optional Timestamp](#timestamp) | When the current or most recent sweep started. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_finished\_at.finished\_at | [optional Timestamp](#timestamp) | When the most recent sweep finished. | | scanned\_count | [ int64](#int64) | Checks examined by the current or most recent sweep. | | rewritten\_count | [ int64](#int64) | Checks whose categorisation actually changed in that sweep. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_error.last\_error | [optional string](#string) | Populated when the most recent sweep failed. The next rule change schedules a fresh sweep. | ### 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 technical category (empty = no explicit technical 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). | | updated\_by | [ Actor](#actor) | Who last set this category: display name, and the account or channel they acted through. Absent when the setter could not be resolved to anything a reader would recognise. Server-derived; 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 the server-set editor and timestamp. | ### 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. | | include\_segments | [ bool](#bool) | Include the per-segment checks of segmented monitors. | A segmented monitor publishes one check entity per distinct value of its segmentation column, so a single monitor can stand behind hundreds of them and they can outnumber an asset's other checks by an order of magnitude. They are left out by default so a coverage read stays readable, and asked for explicitly when the caller wants the individual segment ids — the same ids alerts, search results and the monitor-predictions read use. Segment checks are only ever reported on the asset the monitor runs on: they are a slice of one monitor on one asset, and never propagate downstream. The parent monitor's own check propagates as it always has, so downstream coverage is unchanged by this field. | ### 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. | ### 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) | Technical category to use for this check — what kind of check it is, mechanically, e.g. "nullness". Empty when the check declares none, in which case the category a categorisation rule computes is used instead. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Governance category to use for this check — what the check is for, e.g. "Completeness". Empty when the check declares none, in which case the category a categorisation rule computes is used instead. | ### BatchGetPlatformUsersRequest (synq.entities.platformusers.v1alpha.BatchGetPlatformUsersRequest) | Field | Type | Description | | - | - | - | | platform\_user\_ids | [repeated string](#string) | none | | window\_days | [ uint32](#uint32) | The days of query history read, back from the current hour. Unset is 30. | | view | [ PlatformUserView](#platformuserview) | none | ### BatchGetPlatformUsersResponse (synq.entities.platformusers.v1alpha.BatchGetPlatformUsersResponse) | Field | Type | Description | | - | - | - | | platform\_users | [map PlatformUsersEntry](#platformusersentry) | Keyed by platform user id. | ### BatchGetPlatformUsersResponse.PlatformUsersEntry (synq.entities.platformusers.v1alpha.BatchGetPlatformUsersResponse.PlatformUsersEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ PlatformUser](#platformuser) | none | ### LinkCandidateMember (synq.entities.platformusers.v1alpha.LinkCandidateMember) LinkCandidateMember is one workspace member a login may be linked to. | Field | Type | Description | | - | - | - | | user\_id | [ string](#string) | none | | first\_name | [ string](#string) | none | | last\_name | [ string](#string) | none | | email | [ string](#string) | none | | identities | [repeated string](#string) | The member's identities, as User.identities lists them. A login listed here by its platform\_user\_id is already linked, and is never suggested. | ### LinkSuggestion (synq.entities.platformusers.v1alpha.LinkSuggestion) LinkSuggestion is one login that may belong to one member. | Field | Type | Description | | - | - | - | | platform\_user\_id | [ string](#string) | none | | login | [ string](#string) | none | | platform | [ DataPlatformType](#dataplatformtype) | none | | platform\_root\_entity\_id | [ string](#string) | none | | user\_identity | [ string](#string) | "synq:\" of the suggested member. | | evidence | [ LinkEvidence](#linkevidence) | none | | ambiguous | [ bool](#bool) | The login matches more than one member, each listed with its own suggestion. | ### ListLinkSuggestionsRequest (synq.entities.platformusers.v1alpha.ListLinkSuggestionsRequest) | Field | Type | Description | | - | - | - | | members | [repeated LinkCandidateMember](#linkcandidatemember) | The members to match, as synq.users.v1 UsersService.ListUsers returns them. | | platform\_user\_ids | [repeated string](#string) | Only these logins. Empty considers every login. | | pagination | [ Pagination](#pagination) | Without a page size every suggestion is returned. | ### ListLinkSuggestionsResponse (synq.entities.platformusers.v1alpha.ListLinkSuggestionsResponse) | Field | Type | Description | | - | - | - | | suggestions | [repeated LinkSuggestion](#linksuggestion) | By evidence, strongest first, then login, platform user id and member. | | page\_info | [ PageInfo](#pageinfo) | none | ### ListPlatformUsersRequest (synq.entities.platformusers.v1alpha.ListPlatformUsersRequest) | Field | Type | Description | | - | - | - | | service\_account\_ids | [repeated string](#string) | Only the logins in these service accounts, built-in ones included. | | platforms | [repeated DataPlatformType](#dataplatformtype) | Only the logins on these platforms. | | platform\_root\_entity\_ids | [repeated string](#string) | Only the logins on these platform instances. | | unclassified\_only | [ bool](#bool) | Only the logins with a slice no service account takes and no person link or email links. | | suggested\_only | [ bool](#bool) | Only the logins a service account suggestion includes. | | search | [ string](#string) | A substring of the login, display name or email, ignoring case. | | window\_days | [ uint32](#uint32) | The days of query history read, back from the current hour. Unset is 30. | | platform\_user\_ids | [repeated string](#string) | Only these logins. | | sources | [repeated string](#string) | Only the logins these integrations declare. | | view | [ PlatformUserView](#platformuserview) | none | | pagination | [ Pagination](#pagination) | Without a page size every matching login is returned. | ### ListPlatformUsersResponse (synq.entities.platformusers.v1alpha.ListPlatformUsersResponse) | Field | Type | Description | | - | - | - | | platform\_users | [repeated PlatformUser](#platformuser) | none | | summary | [ PlatformUsersSummary](#platformuserssummary) | On the first page only. | | page\_info | [ PageInfo](#pageinfo) | none | | from | [ Timestamp](#timestamp) | The window read, \[from, to). | | to | [ Timestamp](#timestamp) | none | ### ApplyServiceAccountChangesRequest (synq.entities.platformusers.v1alpha.ApplyServiceAccountChangesRequest) | Field | Type | Description | | - | - | - | | changes | [ ServiceAccountChanges](#serviceaccountchanges) | none | | plan\_token | [ string](#string) | none | ### ApplyServiceAccountChangesResponse (synq.entities.platformusers.v1alpha.ApplyServiceAccountChangesResponse) | Field | Type | Description | | - | - | - | | service\_accounts | [repeated ServiceAccount](#serviceaccount) | The accounts and person links as written, with their new etags. | | person\_links | [repeated PersonLink](#personlink) | none | ### BatchGetServiceAccountsRequest (synq.entities.platformusers.v1alpha.BatchGetServiceAccountsRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | none | ### BatchGetServiceAccountsResponse (synq.entities.platformusers.v1alpha.BatchGetServiceAccountsResponse) | Field | Type | Description | | - | - | - | | service\_accounts | [map ServiceAccountsEntry](#serviceaccountsentry) | The accounts among the asked ids, keyed by id. | ### BatchGetServiceAccountsResponse.ServiceAccountsEntry (synq.entities.platformusers.v1alpha.BatchGetServiceAccountsResponse.ServiceAccountsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ ServiceAccount](#serviceaccount) | none | ### ListServiceAccountSuggestionsRequest (synq.entities.platformusers.v1alpha.ListServiceAccountSuggestionsRequest) | Field | Type | Description | | - | - | - | | window\_days | [ uint32](#uint32) | The days of query history the evidence is read over, back from the current hour. Unset is 30. | ### ListServiceAccountSuggestionsResponse (synq.entities.platformusers.v1alpha.ListServiceAccountSuggestionsResponse) | Field | Type | Description | | - | - | - | | suggestions | [repeated ServiceAccountSuggestion](#serviceaccountsuggestion) | By source, then by how much of the logins' activity carries the evidence, highest first. | ### ListServiceAccountsRequest (synq.entities.platformusers.v1alpha.ListServiceAccountsRequest) ### ListServiceAccountsResponse (synq.entities.platformusers.v1alpha.ListServiceAccountsResponse) | Field | Type | Description | | - | - | - | | service\_accounts | [repeated ServiceAccount](#serviceaccount) | The workspace's accounts by priority, highest first, then the last update, newest first, then id. Then the built-in accounts, in the order they apply, `built_in.coalesce-quality` first. | | person\_links | [repeated PersonLink](#personlink) | By priority, highest first, then the last update, newest first, then id. | ### PlanServiceAccountChangesRequest (synq.entities.platformusers.v1alpha.PlanServiceAccountChangesRequest) | Field | Type | Description | | - | - | - | | changes | [ ServiceAccountChanges](#serviceaccountchanges) | none | | window\_days | [ uint32](#uint32) | The days of query history the plan is read over, back from the current hour. Unset is 30. | ### PlanServiceAccountChangesResponse (synq.entities.platformusers.v1alpha.PlanServiceAccountChangesResponse) | Field | Type | Description | | - | - | - | | slice\_changes | [repeated SliceChange](#slicechange) | By the size of counted\_reads\_delta, largest first, then login and issuer. | | counted\_reads\_delta | [ int64](#int64) | The counted reads the change set adds, negative when it removes them. | | rank\_changes | [repeated RankChange](#rankchange) | At most 20, in the SYSTEM pool, by how far the percentile moves, largest first. Empty when the ranks could not be computed, with ranks\_unavailable set. | | ranks\_unavailable | [ bool](#bool) | none | | plan\_token | [ string](#string) | What ApplyServiceAccountChanges takes for exactly this change set. | | from | [ Timestamp](#timestamp) | The window planned over, \[from, to). | | to | [ Timestamp](#timestamp) | none | ### RankChange (synq.entities.platformusers.v1alpha.RankChange) RankChange is one entity whose rank in one pool the change set moves. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | pool | [ PopularityPool](#popularitypool) | none | | platform | [ DataPlatformType](#dataplatformtype) | none | | instance | [ string](#string) | none | | reads\_before | [ uint64](#uint64) | none | | reads\_after | [ uint64](#uint64) | none | | percentile\_before | [ double](#double) | From 0 to 1, 0 when the entity was not ranked. | | percentile\_after | [ double](#double) | none | ### ServiceAccountSuggestion (synq.entities.platformusers.v1alpha.ServiceAccountSuggestion) | Field | Type | Description | | - | - | - | | source | [ SuggestionSource](#suggestionsource) | none | | changes | [ ServiceAccountChanges](#serviceaccountchanges) | The account to create, with one matcher. Its ids are generated, so applying it twice creates it once. | | evidence | [repeated Evidence](#evidence) | Why each login is in it, one entry per login. | | confidence | [ SuggestionConfidence](#suggestionconfidence) | The least confidence of its logins' evidence. | ### SliceChange (synq.entities.platformusers.v1alpha.SliceChange) SliceChange is one login slice whose classification the change set moves. | Field | Type | Description | | - | - | - | | platform\_user\_id | [ string](#string) | none | | login | [ string](#string) | none | | issuer | [ DataPlatformType](#dataplatformtype) | The tool whose queries the slice is, DATA\_PLATFORM\_TYPE\_UNSPECIFIED for queries with no tag. | | before | [ SliceReading](#slicereading) | none | | after | [ SliceReading](#slicereading) | none | | counted\_reads\_delta | [ int64](#int64) | Reads of the slice in the window that start counting toward popularity, negative when they stop. | ### SliceReading (synq.entities.platformusers.v1alpha.SliceReading) SliceReading is how one login slice reads under a classification. | Field | Type | Description | | - | - | - | | classification | [ Classification](#classification) | none | | service\_account\_ids | [repeated string](#string) | The service accounts the slice is in, the first one deciding its group, built-in ones included. | | person\_identity | [ string](#string) | The identity of its person, for a slice a person link or the platform's email links. | | counts\_toward\_popularity | [ bool](#bool) | none | | listed\_as\_frequent\_user | [ bool](#bool) | none | ### AdvancedMatch (synq.entities.platformusers.v1alpha.AdvancedMatch) AdvancedMatch narrows a matcher by what the platform states about a login and by what the login did. Every non-empty field must match, and an empty one matches everything. | Field | Type | Description | | - | - | - | | platforms | [repeated DataPlatformType](#dataplatformtype) | The platform of the login. | | platform\_root\_entity\_ids | [repeated string](#string) | The platform instance the login lives on, such as the Snowflake account's entity id. | | user\_types | [repeated string](#string) | The kind of login the platform states, such as Snowflake's `SERVICE` or BigQuery's `serviceAccount`, ignoring case. | | email\_domains | [repeated string](#string) | The domain of the email the platform states, ignoring case. | | issuers | [repeated DataPlatformType](#dataplatformtype) | The tools whose queries the matcher takes, from the tag a tool puts on its queries. Empty takes every query of a matching login. DATA\_PLATFORM\_TYPE\_UNSPECIFIED names the queries with no tag. | | min\_issuer\_share | [ double](#double) | The least share of the login's queries in the window, from 0 to 1, that a tool named in issuers must have. Only with issuers. | | footprints | [repeated DataPlatformType](#dataplatformtype) | Loaders whose columns the tables the login writes carry, such as Fivetran's `_fivetran_synced`. | | min\_footprint\_share | [ double](#double) | The least share, from 0 to 1, of the tables the login wrote in the window that carry a loader's columns. Only with footprints. | ### BuiltInPolicyChange (synq.entities.platformusers.v1alpha.BuiltInPolicyChange) BuiltInPolicyChange sets the popularity policy of a built-in account, the one thing of a built-in account a workspace can change. | Field | Type | Description | | - | - | - | | built\_in\_id | [ string](#string) | none | | policy | [ PopularityPolicy](#popularitypolicy) | A policy with neither field set goes back to the purpose default. | ### CoalesceLoginExclusion (synq.entities.platformusers.v1alpha.CoalesceLoginExclusion) CoalesceLoginExclusion says whether a former login of Coalesce Quality is still ours. A login that a Coalesce Quality integration connects as now cannot be excluded. | Field | Type | Description | | - | - | - | | platform\_user\_id | [ string](#string) | none | | excluded | [ bool](#bool) | True takes the login out of the Coalesce Quality account, false puts it back. | ### Matcher (synq.entities.platformusers.v1alpha.Matcher) Matcher selects logins. Set the simple fields first: most service accounts need only login patterns. Every non-empty field must match. A matcher with only platform\_user\_ids, and optionally advanced.issuers, is an exact matcher: it names logins, and wins over every other matcher and over the logins Coalesce Quality connects as. platform\_user\_ids cannot be combined with any other field, and each login and issuer can be in only one exact matcher of an account. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Caller-supplied uuid, unique within the workspace. | | platform\_user\_ids | [repeated string](#string) | Exact logins, by the platform\_user\_id PlatformUsersService returns. | | logins | [repeated string](#string) | Patterns over the login, `*` for any run of characters, ignoring case, such as `FIVETRAN_*`. | | emails | [repeated string](#string) | Patterns over the email the platform states, `*` for any run of characters, ignoring case, such as `*@example.com`. On BigQuery the login is the email. | | advanced | [ AdvancedMatch](#advancedmatch) | none | | internal\_only | [ bool](#bool) | Output only: the matcher uses a condition this API cannot express. Its account reads as is, and a change to it is refused. | ### PersonLink (synq.entities.platformusers.v1alpha.PersonLink) PersonLink links logins to a person: the identity it makes from each login, such as `email:{login}@example.com`. It applies only to logins no service account takes. A person link takes only the queries a login ran with no tool's tag, unless its matcher names issuers. So a person who runs a BI tool on their own credentials keeps those queries as the tool's. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Caller-supplied uuid, unique within the workspace. | | title | [ string](#string) | none | | priority | [ int32](#int32) | Higher first, between person links. | | matcher | [ Matcher](#matcher) | Its id is the link's own, whatever is sent. platform\_user\_ids is not allowed here. | | identity\_pattern | [ string](#string) | The identity of the person, `{login}` standing for the login, lower-cased. Such as `email:{login}@example.com`, to resolve with synq.users.v1. | | etag | [ string](#string) | Output only: pass it back on a change of the link. | | updated\_by | [ Actor](#actor) | Output only. | | created\_at | [ Timestamp](#timestamp) | Output only. | | updated\_at | [ Timestamp](#timestamp) | Output only. | ### PopularityPolicy (synq.entities.platformusers.v1alpha.PopularityPolicy) PopularityPolicy says whether the reads of a service account's logins count. An unset field takes the default of the account's purpose: loader, orchestrator, transformer, observability, catalog and CI reads do not count, every other purpose's do. Coalesce Quality's own queries never count, whatever a policy says. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_counts\_toward\_popularity.counts\_toward\_popularity | [optional bool](#bool) | Whether the logins' reads count toward an entity's popularity. Unset takes the purpose default. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_listed\_as\_frequent\_user.listed\_as\_frequent\_user | [optional bool](#bool) | Whether the logins may be listed among an entity's frequent users. Unset is false, as a service account is not a person. | | counts\_toward\_popularity\_resolved | [ bool](#bool) | Output only: what applies, the policy or the purpose default. | | listed\_as\_frequent\_user\_resolved | [ bool](#bool) | Output only: what applies. | ### ServiceAccount (synq.entities.platformusers.v1alpha.ServiceAccount) ServiceAccount is a group of logins that act for one tool or purpose, such as the logins Airflow runs as. A login slice that a service account takes reads as the tool, not as a person, and counts toward popularity as the account's policy says. A login's queries are split by the tool that issued them, from the tag on each query. Each part is matched on its own, so a person's Looker Studio queries can belong to a shared Looker Studio account while the rest of their queries stay theirs. Accounts apply in order: exact matchers first, then every other matcher by the account's priority, highest first, then the last update, newest first, then the id. Built-in accounts apply after every workspace account. | Field | Type | Description | | - | - | - | | id | [ string](#string) | A caller-supplied uuid for a workspace account. A built-in account's id starts with `built_in.`, such as `built_in.fivetran`. | | name | [ string](#string) | none | | tool\_platform | [ DataPlatformType](#dataplatformtype) | The tool the logins act for, DATA\_PLATFORM\_TYPE\_UNSPECIFIED when there is none or it is not known. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_tool\_entity\_id.tool\_entity\_id | [optional string](#string) | The tool's integration entity, if the workspace has one. | | purpose | [ Purpose](#purpose) | none | | policy | [ PopularityPolicy](#popularitypolicy) | none | | priority | [ int32](#int32) | Higher first, between accounts. | | matchers | [repeated Matcher](#matcher) | none | | built\_in | [ bool](#bool) | Output only: the account is built in. Its matchers cannot be changed, and its policy is changed through ServiceAccountChanges.built\_in\_policies. | | excluded\_platform\_user\_ids | [repeated string](#string) | Output only, on `built_in.coalesce-quality`: the former logins of Coalesce Quality that a person said are no longer ours. Changed through ServiceAccountChanges.coalesce\_logins. | | etag | [ string](#string) | Output only: pass it back on a change of the account, so a concurrent change is refused rather than overwritten. | | updated\_by | [ Actor](#actor) | Output only. | | created\_at | [ Timestamp](#timestamp) | Output only. | | updated\_at | [ Timestamp](#timestamp) | Output only. | ### ServiceAccountChanges (synq.entities.platformusers.v1alpha.ServiceAccountChanges) ServiceAccountChanges is any mix of changes to a workspace's service accounts, person links and policies, planned and applied as one. | Field | Type | Description | | - | - | - | | upsert\_service\_accounts | [repeated ServiceAccount](#serviceaccount) | Each replaces the account with its id, matchers included, or creates it. Pass the etag you read to replace one. | | delete\_service\_account\_ids | [repeated string](#string) | Deleting an account deletes its matchers. Deleting one that is not there succeeds. | | upsert\_person\_links | [repeated PersonLink](#personlink) | none | | delete\_person\_link\_ids | [repeated string](#string) | none | | built\_in\_policies | [repeated BuiltInPolicyChange](#builtinpolicychange) | none | | coalesce\_logins | [repeated CoalesceLoginExclusion](#coalesceloginexclusion) | none | ### Evidence (synq.entities.platformusers.v1alpha.Evidence) Evidence is one hint about what a login is. | Field | Type | Description | | - | - | - | | kind | [ EvidenceKind](#evidencekind) | none | | platform\_user\_id | [ string](#string) | none | | login | [ string](#string) | none | | values | [repeated string](#string) | What the evidence names: the tool, the pattern, the kind, the cadence or the email. | | text | [ string](#string) | One line for a person, such as "99% Looker Studio queries" or "writes every hour". | ### LoginSlice (synq.entities.platformusers.v1alpha.LoginSlice) LoginSlice is the queries of one login that one tool issued, from the tag on each query, or the queries with no tag. Each slice is classified on its own. | Field | Type | Description | | - | - | - | | issuer | [ DataPlatformType](#dataplatformtype) | DATA\_PLATFORM\_TYPE\_UNSPECIFIED is the queries with no tool's tag. | | classification | [ Classification](#classification) | none | | service\_accounts | [repeated SliceMembership](#slicemembership) | Every service account the slice is in, the first one deciding where its queries are grouped. | | person | [ SlicePerson](#sliceperson) | For a PERSON slice. | | counts\_toward\_popularity | [ bool](#bool) | none | | listed\_as\_frequent\_user | [ bool](#bool) | none | | last\_seen\_at | [ Timestamp](#timestamp) | none | | signals | [ SliceSignals](#slicesignals) | With view FULL only. | ### PlatformUser (synq.entities.platformusers.v1alpha.PlatformUser) PlatformUser is one login on one platform instance. | Field | Type | Description | | - | - | - | | platform\_user\_id | [ string](#string) | Opaque. Pass it back as it is. | | name | [ string](#string) | The login as the platform shows it. | | platform | [ DataPlatformType](#dataplatformtype) | none | | platform\_root\_entity\_id | [ string](#string) | none | | sources | [repeated PlatformUserSource](#platformusersource) | One per integration that declared the login, by integration. | | classification | [ Classification](#classification) | none | | last\_seen\_at | [ Timestamp](#timestamp) | none | | reads | [ uint64](#uint64) | Reads and writes over the window, Coalesce Quality's own queries left out. | | writes | [ uint64](#uint64) | none | | share | [ double](#double) | Its share of the workspace's reads, inputs and writes in the window, from 0 to 1. | | weights | [repeated PlatformWeights](#platformweights) | What its queries cost, per platform. | | slices | [repeated LoginSlice](#loginslice) | One per slice, by issuer. | | identities | [repeated string](#string) | The platform\_user\_id always, which starts with `platform_user:`, and `email:
` when an integration lists an email for a login that is not a service kind. | | evidence | [repeated Evidence](#evidence) | none | | suggested | [ bool](#bool) | A service account suggestion includes the login. | ### PlatformUserSource (synq.entities.platformusers.v1alpha.PlatformUserSource) PlatformUserSource is what one integration declared about a login. | Field | Type | Description | | - | - | - | | source | [ string](#string) | The integration. | | user\_type | [ string](#string) | The kind of login the platform's user listing states, such as Snowflake's `SERVICE`. | | email | [ string](#string) | none | | display\_name | [ string](#string) | none | | coalesce\_login | [ bool](#bool) | A login the integration connects as, now or before. | | coalesce\_login\_current | [ bool](#bool) | A login the integration connects as now. | | state\_at | [ Timestamp](#timestamp) | When the integration observed what it declared. | ### PlatformUsersSummary (synq.entities.platformusers.v1alpha.PlatformUsersSummary) PlatformUsersSummary is the whole window of the workspace, whatever the filters. | Field | Type | Description | | - | - | - | | classified\_share | [ double](#double) | The share of the workspace's activity in the window whose login is classified, from 0 to 1. | | counted\_share | [ double](#double) | The share of the workspace's reads that count toward popularity, from 0 to 1. | | unclassified\_logins | [ uint32](#uint32) | none | | suggested\_logins | [ uint32](#uint32) | none | | logins | [ uint32](#uint32) | none | ### SliceMembership (synq.entities.platformusers.v1alpha.SliceMembership) SliceMembership is one service account a login slice is in, and why. | Field | Type | Description | | - | - | - | | service\_account\_id | [ string](#string) | none | | kind | [ MatchKind](#matchkind) | none | | matcher\_id | [ string](#string) | The matcher that took the slice, for MATCHER and EXACT. | ### SlicePerson (synq.entities.platformusers.v1alpha.SlicePerson) SlicePerson is the person a login slice is linked to. | Field | Type | Description | | - | - | - | | identity | [ string](#string) | Such as `email:jane@example.com`, to resolve with synq.users.v1. | | person\_link\_id | [ string](#string) | The person link that made it, empty when it is the email the platform states. | ### SliceSignals (synq.entities.platformusers.v1alpha.SliceSignals) SliceSignals are what a login slice did in the window: what the matchers and the suggestions see. | Field | Type | Description | | - | - | - | | issuer\_share | [ double](#double) | Its share of the login's queries in the window, from 0 to 1. | | reads | [ uint64](#uint64) | none | | inputs | [ uint64](#uint64) | none | | writes | [ uint64](#uint64) | none | | active\_days | [ uint32](#uint32) | none | | distinct\_entities | [ uint32](#uint32) | The distinct entities it touched, and wrote. | | written\_entities | [ uint32](#uint32) | none | | write\_cadence | [ WriteCadence](#writecadence) | How often it writes. | | read\_hours | [ uint32](#uint32) | The distinct hours it read in, how many of the 24 hours of a day they fall in, and the median gap in hours between them, 0 with fewer than two. | | read\_hours\_of\_day | [ uint32](#uint32) | none | | median\_read\_gap\_hours | [ double](#double) | none | | load\_share | [ double](#double) | The share of its queries that load files or move them on a stage, from 0 to 1. | ### 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. | | include\_joins | [ bool](#bool) | Set to return each entity's joins in `SqlDetails.joins`. Off by default: most callers want only the constructs, and an entity whose SQL joins many tables carries every column it joins on. | ### 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, exactly as requested. Every requested path is present; a path with no SQL details has an empty set of constructs and no joins. | ### BatchSqlDetailsResponse.SqlDetailsEntry (synq.entities.sql\_insights.v1.BatchSqlDetailsResponse.SqlDetailsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ SqlDetails](#sqldetails) | none | ### Join (synq.entities.sql\_insights.v1.Join) Join is one join in a SQL statement, like `LEFT JOIN customers c ON o.customer_id = c.id AND c.status = 'active'`. | Field | Type | Description | | - | - | - | | source\_entity\_id | [ string](#string) | The entity whose SQL the join was read from: the requested entity, or one that is the same object. `statement_index`, `join_index` and each condition's `location` address that entity's SQL, which can differ from the requested entity's. A join that both a model's or a node's SQL and the warehouse's definition of what it builds make is read from the model or the node, as a warehouse reports its own wrapping around the SQL a model runs. It is the same opaque identifier the request's `paths` take. | | kind | [ JoinKind](#joinkind) | The kind of join, like INNER or LEFT\_OUTER, as the SQL wrote it. Which table it keeps every row of follows the order of the tables in the FROM clause, not the order of a condition's `left` and `right`. | | conditions | [repeated JoinCondition](#joincondition) | The comparisons the join matches rows on, in the order the SQL wrote them, like `o.customer_id = c.id`. More than one is a composite key: a row matches when every condition holds. Never empty. | | filters | [repeated string](#string) | The comparisons of the same ON clause between a column and a literal, as SQL, like `c.status = 'active'`. They make the join conditional. Empty for a join written with USING, NATURAL or in a WHERE clause. | | statement\_index | [ uint32](#uint32) | Index of the statement the join was read from, among the SQL statements of `source_entity_id`, counting from 0. | | join\_index | [ uint32](#uint32) | Index of the join within its statement, counting from 0. Together with `source_entity_id` and `statement_index` it identifies the join. | ### JoinColumn (synq.entities.sql\_insights.v1.JoinColumn) JoinColumn is one side of a join condition: a column of a known entity, as the SQL reads it. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The entity the column belongs to. It is the same opaque identifier the request's `paths` take, so it can be passed back to look that entity up. | | column | [ string](#string) | The column name, lowercased. | | derivation | [ JoinSideDerivation](#joinsidederivation) | How the column reaches the comparison. | | expression | [ string](#string) | The side's SQL when `derivation` is TRANSFORMED, like `lower(c.email)`. For an OTHER operator, the whole comparison. Empty otherwise. | ### JoinCondition (synq.entities.sql\_insights.v1.JoinCondition) JoinCondition is one comparison a join matches rows on: a column of one table compared to a column of another. | Field | Type | Description | | - | - | - | | left | [ JoinColumn](#joincolumn) | The operand the SQL wrote first. For an UPDATE, DELETE or MERGE it is the table the statement writes to. | | right | [ JoinColumn](#joincolumn) | The operand the SQL wrote second. | | operator | [ JoinOperator](#joinoperator) | The comparison made between the two sides. | | location | [ SqlLocation](#sqllocation) | Where the comparison is in the SQL of the join's `source_entity_id`: the text `synq.entities.code.v1.CodeService.ListCode` returns for that entity under `CODE_SOURCE_SQL_DEFINITION`. Unset when the parser recorded no position. | ### JoinIssuer (synq.entities.sql\_insights.v1.JoinIssuer) JoinIssuer is one tool, one entity of a tool, or one kind of warehouse user with no tool, that ran queries making a join. An issuer entity, like a dbt model or a Looker dashboard, has the role that the entity of a SQL definition has in `sources`. | Field | Type | Description | | - | - | - | | platform | [ string](#string) | The tool that ran the queries, from the query's tag, as the lowercase platform name, like `looker` or `dbt_cloud`. Empty when no tag names a tool, and `kind` then says who ran them. | | entity\_id | [ string](#string) | The entity that ran the queries, when the tag names one. Empty otherwise. It is the same opaque identifier the request's `entity_id` takes. | | queries | [ uint64](#uint64) | The queries it ran that made the join. | | distinct\_logins | [ uint32](#uint32) | The distinct warehouse users that ran them. | | kind | [ JoinIssuerKind](#joinissuerkind) | Who ran the queries. Unspecified only from a server that does not classify them yet. | ### JoinKeyPart (synq.entities.sql\_insights.v1.JoinKeyPart) JoinKeyPart is one comparison of a join key, read from the side of the requested entity: `column` belongs to the requested entity, or to an entity that is the same object, and `other` to the entity it is joined with. | Field | Type | Description | | - | - | - | | column | [ JoinColumn](#joincolumn) | The requested entity's side of the comparison. | | other | [ JoinColumn](#joincolumn) | The side it is compared with. | | kind | [ JoinKind](#joinkind) | The kind of join, seen from `column`'s side. A join the SQL writes as `other RIGHT JOIN column` reads as LEFT\_OUTER here, as it keeps every row of `column`'s table. It is the kind of the pattern's first join type, and `JoinPattern.join_types` lists every one. | | operator | [ JoinOperator](#joinoperator) | The comparison, read as `column other`. | | leads | [ bool](#bool) | Set for the side with a role of its own in an ASOF, UPDATE\_FROM, DELETE\_USING or MERGE join: the side whose rows look for a match in an ASOF join, or the table the statement writes to. | | join\_type | [ JoinType](#jointype) | The join type, seen from `column`'s side, as a semantic layer names it. OTHER for a kind with no join type of its own, and `native_join_type` then names it. | | native\_join\_type | [ string](#string) | The kind's own name when `join_type` is OTHER, like `RIGHT_OUTER` or `ASOF`. Empty otherwise. | ### JoinPattern (synq.entities.sql\_insights.v1.JoinPattern) JoinPattern is one way to join the requested entity: a join key, and the SQL that joins on it. The same key written in several SQL definitions, or joined with several join types, is one pattern listing each of them. | Field | Type | Description | | - | - | - | | key | [repeated JoinKeyPart](#joinkeypart) | The comparisons of the key, read from the requested entity's side and ordered by its column. More than one is a composite key: a row matches when every comparison holds. Never empty. | | filters | [repeated string](#string) | The comparisons between a column and a literal that the same ON clauses add, as SQL, like `c.status = 'active'`. They make the join conditional. Each is listed once, in the order first seen. | | evidence\_kinds | [repeated JoinEvidenceKind](#joinevidencekind) | Where the pattern was seen. | | sources | [repeated JoinPatternSource](#joinpatternsource) | Each join, in the SQL of a table, view or model in the workspace, that joins on this key. Ordered by `entity_id`. Entities that are the same object are listed once: a join both a dbt model and the view it builds make is listed from the model, as `BatchSqlDetails` reads it. | | query\_log | [ JoinQueryLogEvidence](#joinquerylogevidence) | How queries in the query history made the join in the requested window, over every join type in `join_types`. A warehouse user is counted once. Set when `evidence_kinds` holds QUERY\_LOG. | | join\_types | [repeated JoinPatternType](#joinpatterntype) | Each join type the key is joined with, the most used first: by the SQL definitions that use it, then by queries. The `kind`, `join_type` and `native_join_type` of the key's comparisons are those of the first. | ### JoinPatternSource (synq.entities.sql\_insights.v1.JoinPatternSource) JoinPatternSource is one join in the SQL of one entity that joins on the pattern's key. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The entity whose SQL makes the join. It is the same opaque identifier the request's `entity_id` takes. | | statement\_index | [ uint32](#uint32) | Index of the statement the join is in, among the SQL statements of `entity_id`, counting from 0. | | join\_index | [ uint32](#uint32) | Index of the join within its statement, counting from 0. It is the `join_index` of the same join in `BatchSqlDetails` for `entity_id`. | ### JoinPatternType (synq.entities.sql\_insights.v1.JoinPatternType) JoinPatternType is one join type that a pattern's key is joined with, and the evidence of that join type only. | Field | Type | Description | | - | - | - | | kind | [ JoinKind](#joinkind) | The kind of join, seen from the requested entity's side, as `JoinKeyPart.kind` is. | | join\_type | [ JoinType](#jointype) | The join type, seen from the requested entity's side, as a semantic layer names it. | | native\_join\_type | [ string](#string) | The kind's own name when `join_type` is OTHER, like `RIGHT_OUTER`. Empty otherwise. | | keeps | [ JoinKeeps](#joinkeeps) | Which side keeps the rows that find no match on the other side. | | filters | [repeated string](#string) | The comparisons between a column and a literal that the ON clauses of this join type add, as SQL. Each is listed once, in the order first seen. | | sources | [repeated JoinPatternSource](#joinpatternsource) | The joins of the pattern's `sources` that use this join type, in the same order. | | query\_log | [ JoinQueryLogEvidence](#joinquerylogevidence) | How queries in the query history made the join with this join type. Set when queries made it. | ### JoinQueryLogEvidence (synq.entities.sql\_insights.v1.JoinQueryLogEvidence) JoinQueryLogEvidence sums the queries that made a join in the requested window. A query counts once per join, also for a composite key. | Field | Type | Description | | - | - | - | | queries | [ uint64](#uint64) | The queries that made the join. | | distinct\_logins | [ uint32](#uint32) | The distinct warehouse users that ran them. A query that names no user adds none. | | first\_hour | [ Timestamp](#timestamp) | The first and the last hour the join was seen in, each the start of its UTC hour. | | last\_hour | [ Timestamp](#timestamp) | none | | issuers | [repeated JoinIssuer](#joinissuer) | Who ran the queries, most queries first. | | sample\_query\_id | [ string](#string) | The warehouse's id of a query of the last hour that made the join. | ### JoinQueryLogLeftOut (synq.entities.sql\_insights.v1.JoinQueryLogLeftOut) JoinQueryLogLeftOut counts the queries left out of the query history evidence, of the joins that pass every other filter of the request. A query counts once, however many patterns its join makes. The thresholds never count them. | Field | Type | Description | | - | - | - | | coalesce\_quality\_queries | [ uint64](#uint64) | Queries that Coalesce Quality's tag marks, by any warehouse user. | | coalesce\_logins | [ uint64](#uint64) | The other queries of the warehouse users Coalesce connects as, for Coalesce Quality or Coalesce Catalog. | | service\_accounts | [ uint64](#uint64) | Queries of the warehouse users that `exclude_service_accounts` leaves out. | ### JoinQueryLogRequest (synq.entities.sql\_insights.v1.JoinQueryLogRequest) JoinQueryLogRequest says which hours of query history to read joins from, and which joins seen only there to leave out. | Field | Type | Description | | - | - | - | | from | [ Timestamp](#timestamp) | The window, from `from` up to but not including `to`. Each end is taken at the start of its UTC hour. It spans at most 92 days. | | to | [ Timestamp](#timestamp) | none | | min\_queries | [ uint64](#uint64) | A pattern seen only in the query history is listed when it reaches any of these thresholds that is set. 0 sets none, and with none set every pattern is listed. A pattern that a SQL definition makes is always listed. | | min\_logins | [ uint32](#uint32) | none | | include\_coalesce\_quality | [ bool](#bool) | Set to keep the queries Coalesce ran: those Coalesce Quality's tag marks, and those of the warehouse users Coalesce connects as. Leave unset to leave them out, as popularity does, and count them in `query_log_left_out`. | | exclude\_service\_accounts | [ bool](#bool) | Set to leave out the queries of every warehouse user in a service account, and count them in `query_log_left_out`. | ### ListJoinPatternsRequest (synq.entities.sql\_insights.v1.ListJoinPatternsRequest) ListJoinPatternsRequest names the table to list join patterns for. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The synq path of the table, view or model to list the join patterns of, as the `paths` of `BatchSqlDetailsRequest` take it. | | column | [ string](#string) | Set to return only the patterns whose key compares this column of the entity, like `customer_id`. Matched case-insensitively. Leave empty for every column. | | other\_entity\_id | [ string](#string) | Set to return only how the entity is joined with this other entity, which answers "how do I join these two tables". A key that also compares a third table keeps only its comparisons with this one. Like `entity_id`, it matches every entity that is the same object. Leave empty for joins with any entity. | | query\_log | [ JoinQueryLogRequest](#joinquerylogrequest) | Set to also list the joins that queries in the warehouse's query history made in a window, with QUERY\_LOG evidence. Leave unset for the joins that SQL definitions make only. | | bare\_only | [ bool](#bool) | Set to return only the patterns whose every side is a plain column, with no expression around it, like `lower(email)` or a cast. | ### ListJoinPatternsResponse (synq.entities.sql\_insights.v1.ListJoinPatternsResponse) ListJoinPatternsResponse lists the join patterns of the requested entity. | Field | Type | Description | | - | - | - | | patterns | [repeated JoinPattern](#joinpattern) | The join patterns. Those that a SQL definition makes come first, then those of the query history only, by distinct logins, the last hour seen and queries. Empty when no SQL in the workspace joins the entity, or none was parsed yet. | | query\_log\_covered\_hours | [ uint32](#uint32) | How many hours of the `query_log` window the query history covered in full. 0 with no QUERY\_LOG pattern means that no query history was read for the window, not that no query made a join. | | query\_log\_left\_out | [ JoinQueryLogLeftOut](#joinquerylogleftout) | The queries left out of the query history evidence. Set when the request sets `query_log`. | | entity\_ids | [repeated string](#string) | The requested entity first, then every entity that is the same object, like the table a dbt model builds. The patterns already include the joins of each of them, so asking about another one of these returns the same patterns. | ### 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 reports how many of the workspace's entities use each SQL construct. | 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). | | joins | [repeated Join](#join) | How building this entity joins other tables: every join whose key compares a column of one known entity with a column of another. A join is left out when none of its key's comparisons can be tied to one column of a known entity on both sides, and a comparison that cannot is left out of its join's `conditions`. | The joins come from the entity's own SQL and from the SQL of every entity that is the same object, like a dbt model, the table it builds and that table in a catalog. Each of them is answered with the same list. A join found in more than one of those SQLs is listed once: two joins are the same when their conditions compare the same columns with the same operators and the same expressions, a column of the dbt model and the same column of the table it builds counting as one. The join kind does not tell joins apart. A model's or a node's joins come first, in the order its SQL makes them, then the joins only a warehouse's definition of the same object makes. Empty unless the request set `include_joins`, and for an entity whose SQL was not parsed yet or joins nothing. | ### SqlLocation (synq.entities.sql\_insights.v1.SqlLocation) SqlLocation is a range of SQL text. Lines and columns are 1-based and inclusive. | Field | Type | Description | | - | - | - | | start\_line | [ int64](#int64) | First line of the range. | | start\_column | [ int64](#int64) | Column of the first character on the first line. | | end\_line | [ int64](#int64) | Last line of the range. | | end\_column | [ int64](#int64) | Column of the last character on the last line. | ### 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 | ### 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 | | unavailable\_sources | [repeated CodeSourceError](#codesourceerror) | Sources that could not be read while assembling this response. Empty on a complete response, which is the normal case. | Code is composed from several independent sources, so one of them being briefly unavailable degrades the response rather than failing it: the codes that were read are returned, and the source that was not is named here. Retry to pick up what is missing. An empty `codes` always means the entity has no code, never that a source was unavailable — a request that could read nothing at all returns an error rather than an empty response, because the two are otherwise indistinguishable. | ### ListEntityTraitDefsRequest (synq.entities.typedefs.v1.ListEntityTraitDefsRequest) ### ListEntityTraitDefsResponse (synq.entities.typedefs.v1.ListEntityTraitDefsResponse) | Field | Type | Description | | - | - | - | | entity\_trait\_defs | [repeated EntityTraitDef](#entitytraitdef) | Every trait a selection query can filter by, ordered by name. | ### ListEntityTypeDefsRequest (synq.entities.typedefs.v1.ListEntityTypeDefsRequest) ### ListEntityTypeDefsResponse (synq.entities.typedefs.v1.ListEntityTypeDefsResponse) | Field | Type | Description | | - | - | - | | entity\_type\_defs | [repeated EntityTypeDef](#entitytypedef) | Every entity type in your workspace, built-in and your own, ordered by entity type value. Your own types sort together after the built-in ones, and two calls against an unchanged workspace return the same order. | ### ListExecutionTypeDefsRequest (synq.entities.typedefs.v1.ListExecutionTypeDefsRequest) ### ListExecutionTypeDefsResponse (synq.entities.typedefs.v1.ListExecutionTypeDefsResponse) | Field | Type | Description | | - | - | - | | execution\_type\_defs | [repeated ExecutionTypeDef](#executiontypedef) | Every kind of run, ordered by execution type value. | ### ListPlatformDefsRequest (synq.entities.typedefs.v1.ListPlatformDefsRequest) ### ListPlatformDefsResponse (synq.entities.typedefs.v1.ListPlatformDefsResponse) | Field | Type | Description | | - | - | - | | platform\_defs | [repeated PlatformDef](#platformdef) | Every platform, ordered by platform value. | ### EntityTraitDef (synq.entities.typedefs.v1.EntityTraitDef) EntityTraitDef describes one trait a selection query can filter entities by. A trait names a property a type has rather than a type itself, so a selection can ask for "everything a monitor can run on" instead of listing the forty-odd types that satisfy it today. The set of types it stands for is worked out each time the query runs, so a selection saved this way covers a new platform's types as soon as Coalesce Quality supports them, and you never have to revisit it. In a query written as text this is `with_type(traits="is_monitorable")`; in a structured query it is the `traits` field on `synq.queries.v1.WithType`. Read this list rather than keeping your own. Traits are added as the platform grows, and a name that is not in the list selects NOTHING — so a stale copy narrows a selection to empty rather than failing where you would notice. | Field | Type | Description | | - | - | - | | name | [ string](#string) | The trait's name, and the exact string a query carries: `is_monitorable`. Stable and safe to store. Matching ignores case. | | short\_name | [ string](#string) | The trait's name for display: "Monitorable", "Warehouse table". | | description | [ string](#string) | A sentence explaining what the trait means and what selecting on it gets you. | | entity\_types | [repeated EntityType](#entitytype) | Every entity type that carries this trait today. | It is this server's current answer, not a definition — the point of selecting by trait is that this set grows without your query changing. Use it to show or preview what a selection covers, never to expand a trait into types and store that instead. | ### EntityTypeDef (synq.entities.typedefs.v1.EntityTypeDef) EntityTypeDef describes one kind of entity that exists in your workspace — a BigQuery table, a dbt model, an Airflow DAG, or a type you defined yourself. Use it to turn the `entity_type` that other endpoints return into something you can show a person or make a decision about: a name to display, the platform it came from, and what Coalesce Quality does with it. The built-in types and your own custom types both come back here, in this same shape. A custom type is the one with a non-zero `type_id`. | Field | Type | Description | | - | - | - | | entity\_type | [ EntityType](#entitytype) | The entity type, matching the `entity_type` other endpoints return for an entity of this kind. Compare against it directly. | If your generated code is older than the server, a type it does not know arrives as an unrecognised number — `name` still identifies it. | \| name | [ string](#string) | A stable name for the type that never changes, safe to store and to compare against. Built-in types use the enum spelling, e.g. `ENTITY_TYPE_BQ_TABLE`. Your own types are named `CUSTOM_TYPE_`, e.g. `CUSTOM_TYPE_20`, which stays the same even if you rename the type. Prefer this over the numeric value whenever you store a reference to a type. It is also the name a selection query spells the type by, lowercased and without the `ENTITY_TYPE_` prefix: `with_type("bq_table")` for a built-in, `with_type("custom_type_20")` for one of your own. Matching there ignores case, so this value can be passed through as it is. | \| short\_name | [ string](#string) | The type's name without its platform: "Table", "View", "DAG". Use it where the platform is already clear from the surrounding context. For a type you defined yourself, this is the name you gave it. | \| short\_plural\_name | [ string](#string) | The plural of `short_name`, for counts and headings: "Tables", "Views". Empty for a type you defined yourself, since you gave it a single name — fall back to `short_name`. | \| full\_name | [ string](#string) | The type's name including its platform: "BigQuery Table", "Snowflake View". Use it where a type appears on its own, so that a table from two different warehouses still reads clearly. For a type you defined yourself, this is the same as `short_name`. | \| full\_plural\_name | [ string](#string) | The plural of `full_name`: "BigQuery Tables". Empty under the same condition as `short_plural_name`. | \| description | [ string](#string) | A sentence explaining the type, where there is one. Often empty. | \| platform | [ DataPlatformType](#dataplatformtype) | The platform this type belongs to — the warehouse, BI tool or orchestrator it comes from. Pair it with ListPlatformDefs to show that platform's name. A type you defined yourself belongs to no external platform, so it reports Coalesce Quality itself. | \| traits | [ Traits](#traits) | What Coalesce Quality knows about entities of this type. For a built-in type this is everything it knows. For a type you defined yourself it is the traits that can be declared on a custom type, each reported whether you set it or not; the traits Coalesce Quality works out on its own for built-in types are not reported for a custom type, so read those with a default. | \| type\_id | [ int32](#int32) | The id of a type you defined yourself, and 0 for a built-in type. It is the same `type_id` that appears on your entities of this type, and the id you pass to synq.entities.custom.v1.TypesService to change the type or fetch its icon. A non-zero value is how you tell your own types from the built-in ones. | ### ExecutionTypeDef (synq.entities.typedefs.v1.ExecutionTypeDef) ExecutionTypeDef describes one kind of run Coalesce Quality records against an entity — a dbt invocation, a warehouse query job, a detected schema change. Use it to name the `execution_type` that execution and run endpoints return. | Field | Type | Description | | - | - | - | | execution\_type | [ ExecutionType](#executiontype) | The execution type, matching the `execution_type` other endpoints return. | | name | [ string](#string) | A stable name for the execution type that never changes, safe to store: the enum spelling, e.g. `EXECUTION_TYPE_DBT_INVOCATION`. | | short\_name | [ string](#string) | The execution type's name for display: "Query Job", "Schema Change", "dbt". | | platform | [ DataPlatformType](#dataplatformtype) | The platform this kind of run comes from. Unset for the kinds Coalesce Quality produces itself, such as a detected schema change. | | traits | [ Traits](#traits) | What Coalesce Quality knows about this kind of run. Empty for a kind that has no traits of its own. | ### PlatformDef (synq.entities.typedefs.v1.PlatformDef) PlatformDef describes one platform Coalesce Quality connects to — a warehouse, a BI tool, an orchestrator, a transformation framework. Use it to show a platform's name rather than building one out of an enum value. | Field | Type | Description | | - | - | - | | platform | [ DataPlatformType](#dataplatformtype) | The platform, matching the `platform` on an EntityTypeDef and the platform fields other endpoints return. | | name | [ string](#string) | A stable name for the platform that never changes, safe to store: the enum spelling, e.g. `DATA_PLATFORM_TYPE_BIGQUERY`. | | display\_name | [ string](#string) | The platform's name as it is normally written: "BigQuery", "ClickHouse", "Microsoft SQL Server", "dbt". Use this anywhere a person will read it. | | traits | [ Traits](#traits) | What Coalesce Quality knows about the platform. `is_dwh` tells you whether it is a data warehouse — true for BigQuery and Snowflake, false for dbt or Looker. | ### Traits (synq.entities.typedefs.v1.Traits) Traits are the facts Coalesce Quality knows about a kind of thing, beyond its name — whether it is a transformation model, whether it lives in a warehouse, whether you can put a monitor on it. They come back as maps rather than as named fields so that new traits reach you without regenerating your client. Look up the ones you care about by name and ignore the rest: if (def.traits.flags\["is\_model"]) \{ ... } Common flag names are `is_model`, `is_source`, `is_dwh_table`, `is_dwh_view`, `is_bi_like`, `is_monitorable` and `is_searchable`. More are added over time, so treat the map as open-ended. A name missing from the map has no answer for this type. Read traits with a default rather than assuming false, so your code keeps working against both an older and a newer server: isModel = def.traits.flags.get("is\_model", false) | Field | Type | Description | | - | - | - | | flags | [map FlagsEntry](#flagsentry) | Yes/no traits, by name. For example `{"is_model": true, "is_dwh_table": false}`. | | strings | [map StringsEntry](#stringsentry) | Traits whose value is a piece of text, by name. For example `{"synql_alias": "table"}`. There are far fewer of these than flags, and most types have none. | ### Traits.FlagsEntry (synq.entities.typedefs.v1.Traits.FlagsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ bool](#bool) | none | ### Traits.StringsEntry (synq.entities.typedefs.v1.Traits.StringsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ string](#string) | none | ### 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. | ### 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) ### BatchGetFoldNodesRequest (synq.entities.lineage.folds.v1alpha.BatchGetFoldNodesRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | Entity ids of fold nodes, as a lineage response returns them. | ### BatchGetFoldNodesResponse (synq.entities.lineage.folds.v1alpha.BatchGetFoldNodesResponse) | Field | Type | Description | | - | - | - | | fold\_nodes | [map FoldNodesEntry](#foldnodesentry) | Fold nodes keyed by entity id. | ### BatchGetFoldNodesResponse.FoldNodesEntry (synq.entities.lineage.folds.v1alpha.BatchGetFoldNodesResponse.FoldNodesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ FoldNode](#foldnode) | none | ### BatchGetFoldsRequest (synq.entities.lineage.folds.v1alpha.BatchGetFoldsRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | none | ### BatchGetFoldsResponse (synq.entities.lineage.folds.v1alpha.BatchGetFoldsResponse) | Field | Type | Description | | - | - | - | | folds | [map FoldsEntry](#foldsentry) | Folds keyed by id. | ### BatchGetFoldsResponse.FoldsEntry (synq.entities.lineage.folds.v1alpha.BatchGetFoldsResponse.FoldsEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ LineageFold](#lineagefold) | none | ### CreateFoldRequest (synq.entities.lineage.folds.v1alpha.CreateFoldRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | Id of the new fold, a UUID. | | name | [ string](#string) | Name shown on the fold's node. | | matcher | [ FoldMatcher](#foldmatcher) | Which entities the fold shows as its node. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_enabled.enabled | [optional bool](#bool) | Whether lineage applies the fold from the start. Defaults to on. | | actor | [ Actor](#actor) | Who is making the change. Optional: the identity is completed from the calling credentials. Set it to attribute the change to a person. | ### CreateFoldResponse (synq.entities.lineage.folds.v1alpha.CreateFoldResponse) | Field | Type | Description | | - | - | - | | fold | [ LineageFold](#lineagefold) | none | ### DeleteFoldRequest (synq.entities.lineage.folds.v1alpha.DeleteFoldRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | When set, the delete is refused with ABORTED if the fold changed since this etag was read. | | actor | [ Actor](#actor) | none | ### DeleteFoldResponse (synq.entities.lineage.folds.v1alpha.DeleteFoldResponse) ### ListFoldsRequest (synq.entities.lineage.folds.v1alpha.ListFoldsRequest) ### ListFoldsResponse (synq.entities.lineage.folds.v1alpha.ListFoldsResponse) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | none | ### PreviewFoldRequest (synq.entities.lineage.folds.v1alpha.PreviewFoldRequest) | Field | Type | Description | | - | - | - | | matcher | [ FoldMatcher](#foldmatcher) | The matcher to preview. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_sample\_size.sample\_size | [optional int32](#int32) | How many sample entities to return, at most. Defaults to 20. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_fold\_id.fold\_id | [optional string](#string) | When previewing a change to an existing fold, its id, so the fold is not reported as overlapping with itself. | ### PreviewFoldResponse (synq.entities.lineage.folds.v1alpha.PreviewFoldResponse) | Field | Type | Description | | - | - | - | | entity\_count | [ int32](#int32) | How many entities in lineage the matcher folds. | | sample\_entity\_ids | [repeated string](#string) | A sample of the entity ids folded, in id order. | | edge\_count | [ int32](#int32) | How many lineage edges connect a folded entity to anything. Edges between two folded entities disappear into the fold's node. | | separated\_entity\_count | [ int32](#int32) | How many folded entities are shown today on one node with other entities that the matcher does not fold, typically the same table as a transformation model or a catalog entry sees it. Folded, such an entity moves to the fold's node and the others stay on a node of their own. | | sample\_separated\_entities | [repeated SeparatedEntity](#separatedentity) | A sample of them. | | overlapping\_fold\_ids | [repeated string](#string) | Enabled folds that already match some of the same entities. An entity matched by more than one fold goes to the oldest of them. | ### RenameFoldRequest (synq.entities.lineage.folds.v1alpha.RenameFoldRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | name | [ string](#string) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | When set, the change is refused with ABORTED if the fold changed since this etag was read. | | actor | [ Actor](#actor) | none | ### RenameFoldResponse (synq.entities.lineage.folds.v1alpha.RenameFoldResponse) | Field | Type | Description | | - | - | - | | fold | [ LineageFold](#lineagefold) | none | ### SeparatedEntity (synq.entities.lineage.folds.v1alpha.SeparatedEntity) SeparatedEntity is a folded entity and the entities it is shown with today that stay out of the fold. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | none | | separated\_from\_entity\_ids | [repeated string](#string) | none | ### SetFoldEnabledRequest (synq.entities.lineage.folds.v1alpha.SetFoldEnabledRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | enabled | [ bool](#bool) | none | | actor | [ Actor](#actor) | none | ### SetFoldEnabledResponse (synq.entities.lineage.folds.v1alpha.SetFoldEnabledResponse) | Field | Type | Description | | - | - | - | | fold | [ LineageFold](#lineagefold) | none | ### UpdateFoldMatcherRequest (synq.entities.lineage.folds.v1alpha.UpdateFoldMatcherRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | matcher | [ FoldMatcher](#foldmatcher) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_etag.etag | [optional string](#string) | When set, the change is refused with ABORTED if the fold changed since this etag was read. | | actor | [ Actor](#actor) | none | ### UpdateFoldMatcherResponse (synq.entities.lineage.folds.v1alpha.UpdateFoldMatcherResponse) | Field | Type | Description | | - | - | - | | fold | [ LineageFold](#lineagefold) | none | ### FoldMatcher (synq.entities.lineage.folds.v1alpha.FoldMatcher) FoldMatcher selects the entities a fold shows as its node. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) kind.id\_pattern | [ IdPatternMatcher](#idpatternmatcher) | Match entity ids against a pattern. | ### FoldNode (synq.entities.lineage.folds.v1alpha.FoldNode) FoldNode is one node lineage showed for a fold: the fold as it was applied, and the entities the node stands for. The node's entity id is derived from all of that, so it names exactly one set of members. When the fold or its members change, lineage shows the fold under a new id, and the old id keeps answering with what it showed while a reader may still hold it. | Field | Type | Description | | - | - | - | | entity\_id | [ string](#string) | The node's entity id, `lineagefold-` followed by a hash. | | fold\_id | [ string](#string) | The fold the node was made from. It may since have been changed, switched off or deleted: read it with `BatchGetFolds`. | | name | [ string](#string) | The fold's name when the node was made. | | matcher | [ FoldMatcher](#foldmatcher) | The fold's matcher when the node was made. | | member\_entity\_ids | [repeated string](#string) | The entities the node stands for, sorted. | | created\_at | [ Timestamp](#timestamp) | When the node was made. | ### IdPatternMatcher (synq.entities.lineage.folds.v1alpha.IdPatternMatcher) IdPatternMatcher matches the entity ids of the entities to fold. The pattern is an entity id with the part that changes replaced by wildcards: `*` matches any run of characters and `?` exactly one. A wildcard matches within one part of the id and never across the `::` between parts or the `/` inside a storage path, so `bq-proj::ds::events_*` folds `bq-proj::ds::events_20261008` but not anything inside another dataset, and `s3-bucket::p-runs/*/orders` folds one path segment. The first part of the id (the instance, project or bucket) is written out in full, and the pattern holds at least one wildcard. | Field | Type | Description | | - | - | - | | pattern | [ string](#string) | none | ### LineageFold (synq.entities.lineage.folds.v1alpha.LineageFold) LineageFold shows many similar entities as one node in lineage. Some tools write to a new table or a new storage path on every run: a date sharded table (`events_20261008`), a staging table per load (`tmp_load_`), an export per day (`exports/orders_20261008`). Each of them is its own entity, so lineage shows one node per day or per run. A fold matches those entities and lineage shows them as the single fold node instead, connected to everything any of them is connected to. Folding changes only how lineage is drawn. Every folded entity keeps its own page, checks, owners and documentation, and switching a fold off brings the original nodes back. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Id of the fold, a UUID chosen by the caller when the fold is created. | | name | [ string](#string) | Name shown on the fold's node, for example "orders exports". | | matcher | [ FoldMatcher](#foldmatcher) | Which entities the fold shows as its node. | | enabled | [ bool](#bool) | Whether lineage applies the fold. A fold that is switched off is kept, so it can be switched back on. | | etag | [ string](#string) | Entity tag for optimistic concurrency: pass it back on a change to guard against overwriting a concurrent one. Opaque, do not parse. Output only. | | created\_at | [ Timestamp](#timestamp) | When the fold was created. Output only. | | updated\_at | [ Timestamp](#timestamp) | When the fold was last changed, switching it on or off included. Output only. | | created\_by | [ Actor](#actor) | Who created the fold. Absent when it cannot be attributed to a person. Output only. | | updated\_by | [ Actor](#actor) | Who last changed the fold. Absent when it cannot be attributed to a person. Output only. | ### 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 | ### 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 | ### PlatformUser (synq.users.v1.PlatformUser) PlatformUser links a login on one connected platform, such as a warehouse user, to a workspace member, so what the login reads counts as that member's. A login belongs to at most one member, and a member may hold many logins. Linking a login that another member holds moves it to the new member. | Field | Type | Description | | - | - | - | | platform\_user\_id | [ string](#string) | The platform user id, as the platform users reads return it. | ### SlackUser (synq.users.v1.SlackUser) | Field | Type | Description | | - | - | - | | user\_id | [ string](#string) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_verified.verified | [optional bool](#bool) | True when the mapping was established by the user proving ownership of the Slack account through "Sign in with Slack" (OIDC), rather than being self-asserted. Server-set only — never trusted from client input. Empty (unset/false) means the mapping is self-asserted. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_team\_id.team\_id | [optional string](#string) | Slack workspace/team the user\_id belongs to. Set when the mapping was established via sign-in (a Slack user\_id is only unique within a team). Empty for self-asserted mappings. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_linked\_via.linked\_via | [optional string](#string) | How the mapping was established: "manual" (self-asserted selection) or "slack\_oauth" (verified sign-in). Empty is treated as "manual". | ### 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, and every linked platform user as its "platform\_user:" id). Can be passed to ListIssues(interacted\_by\_identities) to filter issues this user interacted with. | | roles | [repeated UserRole](#userrole) | Roles the user holds in the workspace. Empty when the user holds no role that can be managed through this API. | | status | [ UserStatus](#userstatus) | Whether the user has accepted their invitation to the workspace. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_last\_login\_at.last\_login\_at | [optional Timestamp](#timestamp) | Most recent interactive sign-in to the workspace, or to any workspace when no sign-in to this one has been recorded. Unset when the user has not signed in since sign-ins began being recorded. Token refreshes and API calls do not count as sign-ins. | | created\_at | [ Timestamp](#timestamp) | When the user account was created. | ### 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 | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) type.platform\_user | [ PlatformUser](#platformuser) | none | ### AddUserRoleRequest (synq.users.v1.AddUserRoleRequest) | Field | Type | Description | | - | - | - | | identity | [ string](#string) | One of the user's identities, as listed in User.identities or returned by GetUserIdentities: "synq:\", "email:\", "slack:\" or "msteams:\". | | role | [ UserRole](#userrole) | none | ### AddUserRoleResponse (synq.users.v1.AddUserRoleResponse) | Field | Type | Description | | - | - | - | | user | [ User](#user) | The user as stored after the call. | ### 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 | ### RemoveUserRoleRequest (synq.users.v1.RemoveUserRoleRequest) | Field | Type | Description | | - | - | - | | identity | [ string](#string) | One of the user's identities, as listed in User.identities or returned by GetUserIdentities: "synq:\", "email:\", "slack:\" or "msteams:\". | | role | [ UserRole](#userrole) | none | ### RemoveUserRoleResponse (synq.users.v1.RemoveUserRoleResponse) | Field | Type | Description | | - | - | - | | user | [ User](#user) | The user as stored after the call. Unset when the call removed the user from the workspace, or the user was not a member. | ### UpsertUserAliasesRequest (synq.users.v1.UpsertUserAliasesRequest) | Field | Type | Description | | - | - | - | | aliases | [repeated UserAlias](#useralias) | none | ### UpsertUserAliasesResponse (synq.users.v1.UpsertUserAliasesResponse) ### 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). | ### CatalogAccount (synq.auth.iam.v1.CatalogAccount) A Coalesce Catalog account linked to a Coalesce Quality workspace. | Field | Type | Description | | - | - | - | | id | [ string](#string) | Catalog's id of the account. | | name | [ string](#string) | Name of the account in Coalesce Catalog. | ### 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. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_catalog\_account.catalog\_account | [optional CatalogAccount](#catalogaccount) | Coalesce Catalog account the workspace is linked to. Unset when the workspace has no Catalog account, so nothing Catalog-backed (knowledge pages, Catalog-written descriptions) has anything to answer. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_time\_zone.time\_zone | [optional string](#string) | IANA time zone the workspace works in, such as "Europe/Madrid". Unset when the workspace has not set one. A client showing activity by local time uses `user_time_zone` when set, then this, then UTC. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_user\_time\_zone.user\_time\_zone | [optional string](#string) | IANA time zone the authenticated user chose, such as "Europe/Warsaw". Populated only when the token is tied to a Coalesce Quality user (i.e. `synq_user_id` is set) and that user has chosen a zone; unset otherwise. Takes precedence over `time_zone`. | ### BatchGetEntityKnowledgeRequest (synq.knowledge.v1alpha.BatchGetEntityKnowledgeRequest) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | Entities to read (1–100, unique), by the opaque entity id other APIs return. A caller holding structured coordinates converts them once with `synq.entities.resolve.v1.IdentifierResolveService.BatchResolveIdentifiers`. | ### BatchGetEntityKnowledgeResponse (synq.knowledge.v1alpha.BatchGetEntityKnowledgeResponse) | Field | Type | Description | | - | - | - | | knowledge | [map KnowledgeEntry](#knowledgeentry) | Knowledge keyed by entity id. Entities with no knowledge are absent. | ### BatchGetEntityKnowledgeResponse.KnowledgeEntry (synq.knowledge.v1alpha.BatchGetEntityKnowledgeResponse.KnowledgeEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ EntityKnowledge](#entityknowledge) | none | ### BatchGetKnowledgePagesRequest (synq.knowledge.v1alpha.BatchGetKnowledgePagesRequest) | Field | Type | Description | | - | - | - | | page\_ids | [repeated string](#string) | Knowledge pages to read (1–100, unique), by id. | | skip\_content | [ bool](#bool) | Leave each page's `markdown` out. Everything else is read as usual. | ### BatchGetKnowledgePagesResponse (synq.knowledge.v1alpha.BatchGetKnowledgePagesResponse) | Field | Type | Description | | - | - | - | | pages | [map PagesEntry](#pagesentry) | Pages keyed by id. Pages that do not exist or were deleted are absent. | ### BatchGetKnowledgePagesResponse.PagesEntry (synq.knowledge.v1alpha.BatchGetKnowledgePagesResponse.PagesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ KnowledgePage](#knowledgepage) | none | ### EntityKnowledge (synq.knowledge.v1alpha.EntityKnowledge) The knowledge held about an entity. | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_description.description | [optional KnowledgeDescription](#knowledgedescription) | The description people wrote for the entity. Unset when nobody wrote one. The description the asset's own source carries, such as a warehouse comment or a dbt description, is not repeated here: the entity itself reports it. | | pages | [repeated KnowledgePageRef](#knowledgepageref) | The knowledge pages pinned to the entity or pinning it, ordered by name. Read their content with `BatchGetKnowledgePages`. | ### KnowledgeDescription (synq.knowledge.v1alpha.KnowledgeDescription) A description people wrote for an entity. | Field | Type | Description | | - | - | - | | markdown | [ string](#string) | The description, as Markdown. | | generated | [ bool](#bool) | Whether it was generated rather than written by a person. | ### KnowledgeOwner (synq.knowledge.v1alpha.KnowledgeOwner) Someone who owns a knowledge page. | Field | Type | Description | | - | - | - | | name | [ string](#string) | The person's full name, or the team's name. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_email.email | [optional string](#string) | The person's or team's email, when known. | | team | [ bool](#bool) | Whether the owner is a team rather than a person. | ### KnowledgePage (synq.knowledge.v1alpha.KnowledgePage) A knowledge page: a document the team wrote, or imported from a tool such as Confluence or Notion. | Field | Type | Description | | - | - | - | | id | [ string](#string) | The page's id. | | name | [ string](#string) | none | | markdown | [ string](#string) | The page's content, as Markdown. Empty when the page has none, or when it was read with `skip_content`. | | generated | [ bool](#bool) | Whether the content was generated rather than written by a person. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_url.url | [optional string](#string) | Where the page was imported from. Unset for a page written here. | | updated\_at | [ Timestamp](#timestamp) | When the page last changed. | | ancestors | [repeated KnowledgePageRef](#knowledgepageref) | The pages above this one, from the top of the tree down to its parent. Empty for a page at the top. | | children | [repeated KnowledgePageRef](#knowledgepageref) | The pages directly under this one, ordered by name. | | certified | [ bool](#bool) | Whether someone certified the page as trustworthy. | | deprecated | [ bool](#bool) | none | | owners | [repeated KnowledgeOwner](#knowledgeowner) | The people and teams who own the page. | | tags | [repeated string](#string) | The page's tags, sorted. | ### KnowledgePageRef (synq.knowledge.v1alpha.KnowledgePageRef) Names a knowledge page. | Field | Type | Description | | - | - | - | | id | [ string](#string) | The page's id. | | name | [ string](#string) | none | ### ListKnowledgePageLinksRequest (synq.knowledge.v1alpha.ListKnowledgePageLinksRequest) | Field | Type | Description | | - | - | - | | page\_id | [ string](#string) | The knowledge page, by id. | ### ListKnowledgePageLinksResponse (synq.knowledge.v1alpha.ListKnowledgePageLinksResponse) | Field | Type | Description | | - | - | - | | entity\_ids | [repeated string](#string) | Entities pinned to the page or pinning it, sorted. | | page\_ids | [repeated string](#string) | Other knowledge pages pinned to the page or pinning it, ordered by name. | ### ListKnowledgePagesRequest (synq.knowledge.v1alpha.ListKnowledgePagesRequest) | Field | Type | Description | | - | - | - | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_name\_contains.name\_contains | [optional string](#string) | Keep pages whose name contains this, ignoring case. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_certified.certified | [optional bool](#bool) | Keep only certified pages (true) or only uncertified ones (false). | | include\_deprecated | [ bool](#bool) | Include deprecated pages, which are left out by default. | | page\_size | [ int32](#int32) | Pages per response, 1–100. Defaults to 50. | | page\_token | [ string](#string) | `next_page_token` of the previous response, to read the next one. | ### ListKnowledgePagesResponse (synq.knowledge.v1alpha.ListKnowledgePagesResponse) | Field | Type | Description | | - | - | - | | page\_ids | [repeated string](#string) | Knowledge page ids, ordered by the pages' names. | | next\_page\_token | [ string](#string) | Pass as `page_token` to read on. Empty on the last response. | | total\_count | [ int32](#int32) | How many pages match, across every response. | ### 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. | ### 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 | ### 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. | ### 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.services.v2.AlertsService` owner path — see `synq.alerts.v2.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. | ### 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.v2`) 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.services.v2.AlertsService` reports as the ownership reference (`synq.alerts.v2.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. | ### 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`. | ### GitContext (synq.ingest.git.v1.GitContext) | Field | Type | Description | | - | - | - | | clone\_url | [ string](#string) | none | | branch | [ string](#string) | none | | commit\_sha | [ 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) ### CloudwatchLogsLogEvent (synq.ingest.cloudwatch.v1.CloudwatchLogsLogEvent) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | timestamp | [ Timestamp](#timestamp) | none | | message | [ string](#string) | none | ### 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) ### 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. ### 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. | ### 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) | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_session\_id.session\_id | [optional string](#string) | The platform's id for the unit of work the query ran in: the session, or for a statement of a BigQuery script run outside a session the script job. Queries that share one ran one after another on one connection or in one script. Empty if the platform has none. | ### 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 | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_precision.precision | [optional int64](#int64) | Declared precision of an exact numeric column (NUMERIC, DECIMAL, NUMBER), in decimal digits. Set whichever category the column reads as, so a NUMBER(38,0) is NUMERIC\_CATEGORY\_INTEGER with precision 38 and scale 0. Unset for every other column, and for an exact numeric whose size the data warehouse does not report. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_scale.scale | [optional int64](#int64) | Declared scale of an exact numeric column, set together with precision. Unset is not a scale of 0: it means the scale is not known. | | numeric\_category | [ NumericCategory](#numericcategory) | What kind of number the column holds. Unspecified for a non-numeric column, and for one whose type is not recognised. When unspecified, it is read from native\_type and scale. | ### 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 | ### IngestDatahubAspectsRequest (synq.ingest.airflow\.v1.IngestDatahubAspectsRequest) | Field | Type | Description | | - | - | - | | aspects | [repeated Struct](#struct) | Request bodies of a DataHub REST emitter, each in the shape of `request`. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_action.action | [optional string](#string) | The emitter's `action` query parameter, for example `ingestProposal`. | | request | [ Struct](#struct) | The request body of a DataHub REST emitter, for example `{"proposal": {...}}`. | ### 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) ### 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) ### IngestRequest (synq.ingest.openlineage.v1.IngestRequest) | Field | Type | Description | | - | - | - | | payload | [ Struct](#struct) | none | ### IngestResponse (synq.ingest.openlineage.v1.IngestResponse) ### 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. | ### 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) | Field | Type | Description | | - | - | - | | errors | [repeated DeleteError](#deleteerror) | IDs that were not deleted, with the reason for each. Empty when everything in the request was deleted. Every other ID in the request is deleted regardless, so a caller reconciling a set can act on what failed without retrying what did not. | ### BatchDeleteSqlTestsResponse.DeleteError (synq.datachecks.sqltests.v1.BatchDeleteSqlTestsResponse.DeleteError) Details of a single ID that could not be deleted. | Field | Type | Description | | - | - | - | | id | [ string](#string) | The ID from the request that was not deleted, echoed back as it was sent. | | reason | [ string](#string) | Why it was not deleted. A test deployed by a SqlTestDeploymentRule cannot be deleted directly — delete or narrow the rule instead, or the rule's next sync would recreate the test. | ### 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. Each SqlTest is matched on the `id` it carries, and on its path when it has no id, so a caller that keeps its own ids can rename or re-target a test without replacing it. | | sql\_test\_ids\_to\_reset | [repeated string](#string) | List of SqlTest IDs to re-arm, given as the same `id` sent above. A test has no learned state to discard: this re-arms the scheduler of a test that carries a recurrence rule, so it runs immediately rather than at its next slot, and does nothing for a test scheduled externally. | ### 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 | ### BatchDeleteSqlTestDeploymentRulesRequest (synq.datachecks.sqltests.v1.BatchDeleteSqlTestDeploymentRulesRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | IDs of the SqlTestDeploymentRules to delete. | ### BatchDeleteSqlTestDeploymentRulesResponse (synq.datachecks.sqltests.v1.BatchDeleteSqlTestDeploymentRulesResponse) ### BatchDeploySqlTestDeploymentRulesRequest (synq.datachecks.sqltests.v1.BatchDeploySqlTestDeploymentRulesRequest) | Field | Type | Description | | - | - | - | | deployment\_rules | [repeated SqlTestDeploymentRule](#sqltestdeploymentrule) | List of SqlTestDeploymentRules to deploy. | ### BatchDeploySqlTestDeploymentRulesResponse (synq.datachecks.sqltests.v1.BatchDeploySqlTestDeploymentRulesResponse) | Field | Type | Description | | - | - | - | | deployed\_ids | [repeated string](#string) | IDs for which SqlTestDeploymentRules were deployed without error. | | errors | [repeated DeployError](#deployerror) | Errors raised while deploying. Empty if there were no errors. | ### BatchDeploySqlTestDeploymentRulesResponse.DeployError (synq.datachecks.sqltests.v1.BatchDeploySqlTestDeploymentRulesResponse.DeployError) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | reason | [ string](#string) | none | ### BatchGetSqlTestDeploymentRulesRequest (synq.datachecks.sqltests.v1.BatchGetSqlTestDeploymentRulesRequest) | Field | Type | Description | | - | - | - | | ids | [repeated string](#string) | none | ### BatchGetSqlTestDeploymentRulesResponse (synq.datachecks.sqltests.v1.BatchGetSqlTestDeploymentRulesResponse) | Field | Type | Description | | - | - | - | | deployment\_rules | [map DeploymentRulesEntry](#deploymentrulesentry) | none | ### BatchGetSqlTestDeploymentRulesResponse.DeploymentRulesEntry (synq.datachecks.sqltests.v1.BatchGetSqlTestDeploymentRulesResponse.DeploymentRulesEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ SqlTestDeploymentRuleView](#sqltestdeploymentruleview) | none | ### DeleteSqlTestDeploymentRuleRequest (synq.datachecks.sqltests.v1.DeleteSqlTestDeploymentRuleRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | ### DeleteSqlTestDeploymentRuleResponse (synq.datachecks.sqltests.v1.DeleteSqlTestDeploymentRuleResponse) ### DeploySqlTestDeploymentRuleRequest (synq.datachecks.sqltests.v1.DeploySqlTestDeploymentRuleRequest) | Field | Type | Description | | - | - | - | | deployment\_rule | [ SqlTestDeploymentRule](#sqltestdeploymentrule) | none | ### DeploySqlTestDeploymentRuleResponse (synq.datachecks.sqltests.v1.DeploySqlTestDeploymentRuleResponse) ### GetSqlTestDeployDeleteOverviewRequest (synq.datachecks.sqltests.v1.GetSqlTestDeployDeleteOverviewRequest) | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | ### GetSqlTestDeployDeleteOverviewResponse (synq.datachecks.sqltests.v1.GetSqlTestDeployDeleteOverviewResponse) | Field | Type | Description | | - | - | - | | overview | [ SqlTestsDeploymentOverview](#sqltestsdeploymentoverview) | none | ### GetSqlTestDeployOverviewRequest (synq.datachecks.sqltests.v1.GetSqlTestDeployOverviewRequest) | Field | Type | Description | | - | - | - | | deployment\_rule | [ SqlTestDeploymentRule](#sqltestdeploymentrule) | none | ### GetSqlTestDeployOverviewResponse (synq.datachecks.sqltests.v1.GetSqlTestDeployOverviewResponse) | Field | Type | Description | | - | - | - | | overview | [ SqlTestsDeploymentOverview](#sqltestsdeploymentoverview) | none | ### ListSqlTestDeploymentRulesRequest (synq.datachecks.sqltests.v1.ListSqlTestDeploymentRulesRequest) | Field | Type | Description | | - | - | - | | sources | [repeated Source](#source) | none | | configs\_filter | [ ConfigsFilter](#configsfilter) | Filter SqlTestDeploymentRules 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 SqlTestDeploymentRuleType](#sqltestdeploymentruletype) | Filter by rule type. When empty, rules of every type are returned. When set, only rules whose type is listed are returned. 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. Omitting this, or sending a zero page\_size, returns every matching rule in one response — there is no server-side default page size. Set page\_size to bound the response; pass page\_info.last\_id from the previous response as the cursor to fetch the next page. | ### ListSqlTestDeploymentRulesResponse (synq.datachecks.sqltests.v1.ListSqlTestDeploymentRulesResponse) | Field | Type | Description | | - | - | - | | deployment\_rules | [repeated SqlTestDeploymentRuleView](#sqltestdeploymentruleview) | 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. | ### 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. Placeholder: `{{ table }}` is substituted with the anchor table's fully qualified name, quoted for the warehouse — the matched table when the test is deployed by a deployment rule, which is how one query covers every table the rule matches instead of being copied onto each of them. It is the only supported placeholder; any other `{{ name }}` token is rejected. 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. Placeholder: `{{ table }}` is substituted with the anchor table's fully qualified name, quoted for the warehouse — the matched table when the test is deployed by a deployment rule. It is the only supported placeholder; any other `{{ name }}` token is rejected. It renders a table name, so it belongs where a table name goes — the FROM clause of a subquery of your own: "total > (SELECT max(total) FROM \{\{ table }})". It is not a column qualifier. The generated FROM clause carries no alias, and on BigQuery the fully qualified name is a single quoted identifier, so "\{\{ table }}.id" does not resolve. To name the anchor's columns, use BusinessQueryTest, where you write the FROM clause and can alias it. | \| 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 this test was authored from, when deployed via configuration as code. Unset for tests authored directly through this API. | On a write this field is only ever set, never unset: omitting it keeps the stored value, so a full-replace update cannot detach the test from the config that owns it. An empty string is a real config id — the one a deploy that declares no namespace uses — so sending it attaches the test to that config rather than clearing the field. No value detaches a test; recreating it is the only way to hand it back to the app. | \| 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. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_category.category | [optional string](#string) | Technical category this test declares for itself — what kind of check it is mechanically (e.g. "nullness", "uniqueness"). It is the test's own declaration, not an administrative override: it is authoritative over any categorisation rule the workspace would otherwise apply, and is itself overridden by an explicit per-check category an admin sets. The value is free-form and workspace-defined — whatever vocabulary your categorisation rules already use. It is displayed with underscores turned into spaces, so `snake_case` reads well. Send the whole test on every upsert: leaving this out is the same as sending it empty, and both mean the test declares no technical category. A test then falls back to its `quality.check_category` annotation, which remains accepted and keeps working — this field simply outranks it. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_governance\_category.governance\_category | [optional string](#string) | Governance category this test declares for itself — what the check is for, the data quality dimension governance reports on (e.g. "completeness"). Resolves independently of `category` — setting one never suppresses the other — and follows the same precedence, the same free-form vocabulary and the same full-state upsert rule described above. Its annotation fallback is `quality.governance_category`. | \| [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_deployment\_rule\_id.deployment\_rule\_id | [optional string](#string) | ID of the SqlTestDeploymentRule that deployed this test, when it was created by a deployment rule rather than authored directly. OUTPUT ONLY. A test with this set is rule-managed: direct edits through this API are rejected. | ### 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) | ### RuleTest (synq.datachecks.sqltests.v1.RuleTest) RuleTest is a SQL test template deployed by a SqlTestDeploymentRule onto every table or view the rule's selection matches. It carries the same test kinds as SqlTest.template, but — unlike Template — has no anchor entity: the anchor is whichever table or view the rule matched, filled in separately for each deployed test. | Field | Type | Description | | - | - | - | | name | [ string](#string) | Human friendly name for this test. Required (non-empty) for business\_rule\_test and business\_query\_test — for those two kinds, name is the test's identity key across rule redeployments, so a renamed test is treated as a different test. Optional for every other kind: leave it unset and a name is generated. | | description | [ string](#string) | Description of purpose and motivation, copied onto every test this rule deploys. | | severity | [ Severity](#severity) | Overrides the rule's config-level severity for this test only. Leave unset to use the config-level severity. | | [**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. | ### SqlTestDeploymentChange (synq.datachecks.sqltests.v1.SqlTestDeploymentChange) SqlTestDeploymentChange describes one test's planned or applied change for a single table or view within a SqlTestsDeploymentOverview. | Field | Type | Description | | - | - | - | | table\_path | [ string](#string) | Synq path of the table or view the test targets or would target. | | sql\_test\_path | [ string](#string) | Synq path of the SqlTest, when it already exists (create-side changes may leave this empty until the test is actually deployed). | | test\_name | [ string](#string) | Name of the test, resolved from its RuleTest.name (or the generated name for non-business test kinds). | | reason\_code | [ SqlTestSkipReason](#sqltestskipreason) | Why this change happens, when the reason is something other than the rule's selection. Today that is one case: SQL\_TEST\_SKIP\_REASON\_MISSING\_COLUMNS on a `tests_to_delete` entry whose table lost a column the test reads, so a caller can say "column dropped: amount" rather than reporting a bare delete. Unset (SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED) otherwise, including for a delete caused by the table no longer matching the rule's selection — treat unset as "no extra reason", never as a list this change cannot appear in. | | missing\_columns | [repeated string](#string) | Columns the table lacks, spelled as the test declares them, when `reason_code` is SQL\_TEST\_SKIP\_REASON\_MISSING\_COLUMNS. Empty otherwise. | ### SqlTestDeploymentRule (synq.datachecks.sqltests.v1.SqlTestDeploymentRule) SqlTestDeploymentRule dynamically deploys SQL test templates onto every table or view its selection matches, keeping them in sync as tables and columns change. Use it instead of authoring one SqlTest per table when the same set of checks should apply to many tables (e.g. "not\_null(email) on every table that has an email column"). | Field | Type | Description | | - | - | - | | id | [ string](#string) | Unique identifier for this rule. | | title | [ string](#string) | Human friendly name for this rule. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.query\_config | [ SqlTestsQueryConfig](#sqltestsqueryconfig) | Deploys tests onto every match of a query; the match set is resynced over time. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_query\_config | [ SqlTestsExclusiveQueryConfig](#sqltestsexclusivequeryconfig) | Deploys tests onto every match of a query; this rule exclusively owns the match set. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.static\_config | [ SqlTestsStaticConfig](#sqltestsstaticconfig) | Deploys tests onto a single fixed table or view. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_static\_config | [ SqlTestsExclusiveStaticConfig](#sqltestsexclusivestaticconfig) | Exclusively owns a single fixed table or view. | | source | [ Source](#source) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | Config ID this rule was authored from, when deployed via configuration as code. Unset for rules authored directly through this API. | On a write this field is only ever set, never unset: omitting it keeps the stored value, so a full-replace update cannot detach the rule from the config that owns it. An empty string is a real config id — the one a deploy that declares no namespace uses — so sending it attaches the rule to that config rather than clearing the field. No value detaches a rule; recreating it is the only way to hand it back to the app. | ### SqlTestDeploymentRuleView (synq.datachecks.sqltests.v1.SqlTestDeploymentRuleView) SqlTestDeploymentRuleView is a SqlTestDeploymentRule together with a summary of how many tests it currently has deployed. | Field | Type | Description | | - | - | - | | id | [ string](#string) | none | | title | [ string](#string) | none | | test\_count | [ int32](#int32) | Number of tests currently deployed by this rule, across every matched table or view. | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.query\_config | [ SqlTestsQueryConfig](#sqltestsqueryconfig) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_query\_config | [ SqlTestsExclusiveQueryConfig](#sqltestsexclusivequeryconfig) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.static\_config | [ SqlTestsStaticConfig](#sqltestsstaticconfig) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) config.exclusive\_static\_config | [ SqlTestsExclusiveStaticConfig](#sqltestsexclusivestaticconfig) | none | | source | [ Source](#source) | none | | [**oneof**](https://developers.google.com/protocol-buffers/docs/proto3#oneof) \_config\_id.config\_id | [optional string](#string) | none | ### SqlTestsDeploymentOverview (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverview) SqlTestsDeploymentOverview previews or reports the effect of deploying a SqlTestDeploymentRule, per test rather than per table — a table with three tests deployed appears as three entries, one for each test. | Field | Type | Description | | - | - | - | | tests\_to\_create | [repeated SqlTestDeploymentChange](#sqltestdeploymentchange) | Tests that would be newly created by this deploy. | | tests\_to\_update | [repeated SqlTestDeploymentChange](#sqltestdeploymentchange) | Tests that already exist and would be updated (e.g. a changed severity or template) by this deploy. | | tests\_to\_delete | [repeated SqlTestDeploymentChange](#sqltestdeploymentchange) | Tests that would be deleted by this deploy, because their table or view no longer matches the rule's selection. | | tests\_to\_keep | [repeated SqlTestDeploymentChange](#sqltestdeploymentchange) | Tests that already exist, still match, and would be left unchanged. | | skipped\_tables | [repeated SkippedTable](#skippedtable) | Tables or views this rule matched but could not deploy tests onto. | | skipped\_tests | [repeated SkippedTest](#skippedtest) | Tests this rule declares that this deploy did not deploy — because another rule already owns them on the table, or because the table's columns do not support them. | | summary | [ SqlTestsDeploymentOverviewSummary](#sqltestsdeploymentoverviewsummary) | Counts over the lists above, so a rule matching thousands of tables can be reported without reading every row. Always populated. | ### SqlTestsDeploymentOverview\.SkippedTable (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverview\.SkippedTable) SkippedTable names a table or view the rule's selection matched, but that this deploy could not deploy tests onto. | Field | Type | Description | | - | - | - | | table\_path | [ string](#string) | Synq path of the skipped table or view. | | reason | [ string](#string) | Why the table or view was skipped, as a stable SCREAMING\_SNAKE token: | SKIPPED\_HIGHER\_PRIORITY\_RULE an exclusive rule has carved the table out SKIPPED\_NO\_INTEGRATION the table has no integration to run a test against SKIPPED\_TEST\_PREPARATION\_FAILED the integration's configuration is unavailable, or the table's dialect cannot render the test Clients branch on these, so treat the spellings as part of this API: adding a value is safe, renaming one is a breaking change. A value not listed here may appear — fall through to "skipped, reason unrecognised" rather than assume the set is closed. `reason_code` is the checkable form. | \| reason\_code | [ SqlTestSkipReason](#sqltestskipreason) | Machine-checkable form of `reason`, so a client can branch on a value the compiler knows instead of string-matching a wire constant. `reason` remains authoritative and keeps being written unchanged; `reason_code` is SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED for a `reason` this enum does not yet cover. | ### SqlTestsDeploymentOverview\.SkippedTest (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverview\.SkippedTest) SkippedTest names one test the rule declares that this deploy left in place rather than deploying, because another rule already deployed it on that table. Rules covering the same table merge additively: each deploys the tests that are not there yet, and never touches a test another rule owns. | Field | Type | Description | | - | - | - | | table\_path | [ string](#string) | Synq path of the table or view carrying the test. | | sql\_test\_path | [ string](#string) | Synq path of the SqlTest, when it already exists (empty while the owning rule has not deployed it yet). | | test\_name | [ string](#string) | Name of the test, resolved the same way as in SqlTestDeploymentChange. | | reason | [ string](#string) | Why the test was skipped, as a stable SCREAMING\_SNAKE token: | SKIPPED\_TEST\_OWNED\_BY\_OTHER\_RULE another rule already deploys that test SKIPPED\_MISSING\_COLUMNS the table lacks a column the test reads SKIPPED\_SCHEMA\_UNAVAILABLE no schema is known for the table yet Clients branch on these, so treat the spellings as part of this API: adding a value is safe, renaming one is a breaking change. A value not listed here may appear — fall through to "skipped, reason unrecognised" rather than assume the set is closed. `reason_code` is the checkable form. | \| owner\_rule\_id | [ string](#string) | Id of the deployment rule that owns the test. Set only for SKIPPED\_TEST\_OWNED\_BY\_OTHER\_RULE. | \| owner\_rule\_title | [ string](#string) | Title the owning rule carried when this plan was made. A title can be renamed — use owner\_rule\_id to look the rule up. | \| reason\_code | [ SqlTestSkipReason](#sqltestskipreason) | Machine-checkable form of `reason`. Same contract as SkippedTable.reason\_code: `reason` stays authoritative, and this is SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED for a reason this enum does not yet cover. | \| missing\_columns | [repeated string](#string) | Columns the test reads that the table does not have, spelled as the test declares them. Set for SKIPPED\_MISSING\_COLUMNS; empty for every other reason. A test is skipped whole — `not_null[a, b]` with only `b` missing lists just `b` but deploys neither column — so this names the gap, not the test's column list. | \| referenced\_table\_path | [ string](#string) | Synq path of the *referenced* table, for a `relationships` test skipped because that table (rather than the table under test) lacks the column. Empty otherwise. | ### SqlTestsDeploymentOverviewSummary (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverviewSummary) SqlTestsDeploymentOverviewSummary counts a SqlTestsDeploymentOverview, so a caller can render "40 tables, 78 tests, 2 skipped for a missing column" without walking lists that run to thousands of entries for a warehouse-wide rule. Every count is derived from the lists in the same message — it adds no information a reader of those lists could not compute, only the ability to skip reading them. | Field | Type | Description | | - | - | - | | tables\_matched | [ int32](#int32) | Distinct tables and views this plan touches: every table\_path appearing in tests\_to\_create, tests\_to\_update, tests\_to\_delete, tests\_to\_keep, skipped\_tests or skipped\_tables, counted once. | | tests\_to\_create | [ int32](#int32) | len(tests\_to\_create). | | tests\_to\_update | [ int32](#int32) | len(tests\_to\_update). | | tests\_to\_delete | [ int32](#int32) | len(tests\_to\_delete). | | tests\_to\_keep | [ int32](#int32) | len(tests\_to\_keep). | | tests\_skipped | [ int32](#int32) | len(skipped\_tests). Skipped *tables* are not counted here — see skipped\_by\_reason, which covers both lists. A test dropped because its column went away is a delete, not a skip, and counts in tests\_to\_delete. | | skipped\_by\_reason | [map SkippedByReasonEntry](#skippedbyreasonentry) | One entry per skip across BOTH skipped\_tables and skipped\_tests, keyed by the SqlTestSkipReason value name (e.g. "SQL\_TEST\_SKIP\_REASON\_MISSING\_COLUMNS"), and "SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED" for a reason string this enum does not cover. The two lists count in different units — a skipped table is one table, a skipped test is one test — so the values sum to more than `tests_skipped` whenever a table was skipped. | | missing\_columns\_histogram | [map MissingColumnsHistogramEntry](#missingcolumnshistogramentry) | Lowercased column name to the number of tests citing it as missing, counted over every entry carrying `missing_columns` — the skipped\_tests the rule could not deploy AND the tests\_to\_delete it is removing because the column went away. Both answer the same question, "which columns does this rule not find", and a dropped column shows up as deletes rather than skips, so counting only one of the two reports an empty histogram for the case it exists for. A test missing two columns adds one to each. Lowercased so a column two tests spell differently is one entry. Empty when nothing cited a missing column. | ### SqlTestsDeploymentOverviewSummary.MissingColumnsHistogramEntry (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverviewSummary.MissingColumnsHistogramEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ int32](#int32) | none | ### SqlTestsDeploymentOverviewSummary.SkippedByReasonEntry (synq.datachecks.sqltests.v1.SqlTestsDeploymentOverviewSummary.SkippedByReasonEntry) | Field | Type | Description | | - | - | - | | key | [ string](#string) | none | | value | [ int32](#int32) | none | ### SqlTestsExclusiveQueryConfig (synq.datachecks.sqltests.v1.SqlTestsExclusiveQueryConfig) SqlTestsExclusiveQueryConfig selects tables and views by query and takes exclusive ownership of the match set: any table or view previously managed by this rule that no longer matches has its deployed tests removed on the next sync, with no `keep_removed_tests` opt-out (a rule managing an exclusive set never "keeps" a table that stopped matching). | Field | Type | Description | | - | - | - | | query | [ EntitySelectionQuery](#entityselectionquery) | Structured selection of tables and views this rule exclusively owns. | | resolver\_ql | [ string](#string) | ResolverQL selection string for the exclusion set. Same semantics as SqlTestsQueryConfig.resolver\_ql: when set on write it takes precedence over `query` and is stored compiled; on read it carries the canonical rendering of the stored selection, equal to `rendered_resolver_ql`. `query` is always populated. | | rendered\_resolver\_ql | [ string](#string) | Canonical ResolverQL rendering of the exclusion selection. OUTPUT ONLY, populated for every rule, ignored on write. | ### SqlTestsExclusiveStaticConfig (synq.datachecks.sqltests.v1.SqlTestsExclusiveStaticConfig) SqlTestsExclusiveStaticConfig marks a single fixed path as exclusively owned by this rule — used to carve out a per-table override from a broader query rule (see SqlTestDeploymentRule precedence). | Field | Type | Description | | - | - | - | | path | [ string](#string) | Synq path of the table or view this rule exclusively owns. | ### SqlTestsQueryConfig (synq.datachecks.sqltests.v1.SqlTestsQueryConfig) SqlTestsQueryConfig selects tables and views by query, deploying every test in `tests` onto each match. As the matched set changes over time (new tables, dropped columns, …), a periodic sync keeps deployed tests in step. | Field | Type | Description | | - | - | - | | query | [ EntitySelectionQuery](#entityselectionquery) | Structured selection of tables and views to deploy tests onto. | | 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. The selection is compiled when it is written and stored in that form, so the text itself is not kept: two spellings of the same selection store the same rule, and a type alias such as "table" is expanded to the types it names at the time of the write. On read this field carries the canonical rendering of the stored selection, equal to `rendered_resolver_ql`, whichever way the rule was written, and is empty when the selection has no ResolverQL representation. Writing a read response back unchanged stores the same selection. `query` is always populated. | | rendered\_resolver\_ql | [ string](#string) | Canonical ResolverQL rendering of this rule's selection, populated for every rule regardless of how it was authored. OUTPUT ONLY — it is ignored on write; set `resolver_ql` to author a selection in ResolverQL. Compare selections by this field rather than by the text a rule was written with, which may be spelled differently. | | tests | [repeated RuleTest](#ruletest) | Tests deployed onto every table or view this rule's selection matches. | | recurrence\_rule | [ string](#string) | [Recurrence rule](https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html) for the execution schedule applied to every test this rule deploys. Empty means on-demand — deployed tests are never scheduled to run automatically. When set, it must carry an inline `DTSTART:` naming the first occurrence, e.g. "DTSTART:20260101T000000Z\nRRULE:FREQ=DAILY". | | timezone | [ string](#string) | IANA timezone name (e.g., "Europe/Prague", "America/New\_York") used to interpret recurrence\_rule. Empty defaults to UTC. | | severity | [ Severity](#severity) | Severity applied to every test this rule deploys, unless a RuleTest overrides it. Required — must be set to a value other than unspecified. | | save\_failures | [ bool](#bool) | Applied to every test this rule deploys. Toggles saving of failure runs. | | keep\_removed\_tests | [ bool](#bool) | When a previously matched table or view stops matching this rule's selection, its deployed tests are deleted by default. Set true to keep them as-is instead — they remain rule-managed but are no longer resynced. | ### SqlTestsStaticConfig (synq.datachecks.sqltests.v1.SqlTestsStaticConfig) SqlTestsStaticConfig deploys tests onto a single, fixed table or view. Unlike the query-based configs, a static rule never resyncs against a changing match set — it pins one path. | Field | Type | Description | | - | - | - | | path | [ string](#string) | Synq path of the table or view this rule deploys tests onto. | | tests | [repeated RuleTest](#ruletest) | Tests deployed onto the table or view at `path`. | | recurrence\_rule | [ string](#string) | [Recurrence rule](https://icalendar.org/iCalendar-RFC-5545/3-8-5-3-recurrence-rule.html) for the execution schedule applied to every test this rule deploys. Empty means on-demand. When set, it must carry an inline `DTSTART:` naming the first occurrence, e.g. "DTSTART:20260101T000000Z\nRRULE:FREQ=DAILY". | | timezone | [ string](#string) | IANA timezone name used to interpret recurrence\_rule. Empty defaults to UTC. | | severity | [ Severity](#severity) | Severity applied to every test this rule deploys, unless a RuleTest overrides it. Required — must be set to a value other than unspecified. | | save\_failures | [ bool](#bool) | Applied to every test this rule deploys. Toggles saving of failure runs. | ### 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) | # Enums ### 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 | ### 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 | ### 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 | ### AppDestination (synq.recommendations.v1.AppDestination) AppDestination is a place in the Coalesce Quality app a recommendation can send you to. A client that does not know a value offers no button for it. | Name | Number | Description | | - | - | - | | APP\_DESTINATION\_UNSPECIFIED | 0 | none | | APP\_DESTINATION\_PROMPT\_SUGGESTIONS | 1 | The review of the AI agent's prompt suggestions. | | APP\_DESTINATION\_SERVICE\_ACCOUNTS | 2 | The service accounts of the workspace, with the proposals waiting for review. | ### RecommendationDecisionKind (synq.recommendations.v1.RecommendationDecisionKind) RecommendationDecisionKind is what was decided about a recommendation. | Name | Number | Description | | - | - | - | | RECOMMENDATION\_DECISION\_KIND\_UNSPECIFIED | 0 | none | | RECOMMENDATION\_DECISION\_KIND\_DISMISSED | 1 | Hidden until something new is found. | | RECOMMENDATION\_DECISION\_KIND\_IGNORED | 2 | Hidden for good. | ### RecommendationState (synq.recommendations.v1.RecommendationState) RecommendationState is whether a recommendation is in front of you. | Name | Number | Description | | - | - | - | | RECOMMENDATION\_STATE\_UNSPECIFIED | 0 | none | | RECOMMENDATION\_STATE\_OPEN | 1 | Nobody dismissed or ignored it, or something new was found since it was dismissed. | | RECOMMENDATION\_STATE\_DISMISSED | 2 | Dismissed, and nothing new was found since: no object it did not already list, and the same remediation. An object disappearing, the message being reworded or the actions changing keep it dismissed. | | RECOMMENDATION\_STATE\_IGNORED | 3 | Ignored. Stays hidden whatever is found later. | ### RecommendationTargetKind (synq.recommendations.v1.RecommendationTargetKind) RecommendationTargetKind names a kind of target, for filtering. | Name | Number | Description | | - | - | - | | RECOMMENDATION\_TARGET\_KIND\_UNSPECIFIED | 0 | none | | RECOMMENDATION\_TARGET\_KIND\_WORKSPACE | 1 | `RecommendationTarget.workspace`. | | RECOMMENDATION\_TARGET\_KIND\_INTEGRATION | 2 | `RecommendationTarget.integration`. | ### 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 | ### DelayModel (synq.monitors.v1.DelayModel) How the expected arrival time of new data is modelled, for the delay and volume change delay metrics. Only table stats monitors produce those metrics, so the choice has no effect on any other monitor type. | Name | Number | Description | | - | - | - | | DELAY\_MODEL\_UNSPECIFIED | 0 | Not set — the workspace default applies. | | DELAY\_MODEL\_STANDARD | 1 | Expects data to keep arriving at the cadence it has been arriving at, regardless of which day it is. The default, and the right choice for a pipeline that runs daily. | | DELAY\_MODEL\_WEEKLY\_PATTERN | 2 | Learns a separate cadence for each day of the week, so a pipeline that deliberately skips weekends is not reported as delayed on Saturday and Sunday. Needs roughly two weeks of history before it has a pattern to compare against. | ### 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) Metric a monitor predicts. ROW\_COUNT, DELAY and VOLUME\_CHANGE\_DELAY apply to table stats monitors and deployment rules; the remaining values are field statistics and apply to field stats columns only. | 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 | | METRIC\_ID\_NUM\_ROWS | 4 | Field statistic: number of rows. | | METRIC\_ID\_NUM\_NULL | 5 | Field statistic: number of null values. | | METRIC\_ID\_PCT\_NULL | 6 | Field statistic: share of null values. | | METRIC\_ID\_NUM\_UNIQUE | 7 | Field statistic: number of distinct values. | | METRIC\_ID\_PCT\_UNIQUE | 8 | Field statistic: share of distinct values. | | METRIC\_ID\_NUM\_EMPTY | 9 | Field statistic: number of empty values. | | METRIC\_ID\_PCT\_EMPTY | 10 | Field statistic: share of empty values. | | METRIC\_ID\_MEAN | 11 | Field statistic: mean value. | | METRIC\_ID\_MIN | 12 | Field statistic: minimum value. | | METRIC\_ID\_MAX | 13 | Field statistic: maximum value. | | METRIC\_ID\_MEDIAN | 14 | Field statistic: median value. | | METRIC\_ID\_STDDEV | 15 | Field statistic: standard deviation. | ### 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 | ### SkipReason (synq.monitors.automated\_monitors.v1.SkipReason) SkipReason is the checkable form of SkippedAsset.reason. Values mirror the SCREAMING\_SNAKE tokens documented on that field one-for-one. The set is open by design — a producer may report a reason before this enum has a matching value for it — so a client must treat SKIP\_REASON\_UNSPECIFIED (and any value this client predates) as "skipped, reason unrecognised" rather than as proof nothing applies. | Name | Number | Description | | - | - | - | | SKIP\_REASON\_UNSPECIFIED | 0 | none | | SKIP\_REASON\_HIGHER\_PRIORITY\_RULE | 1 | none | | SKIP\_REASON\_NO\_FRESHNESS\_COLUMN\_MATCH | 2 | none | | SKIP\_REASON\_NO\_FRESHNESS\_FIELD\_PATTERN | 3 | none | | SKIP\_REASON\_NO\_INTEGRATION | 4 | none | | SKIP\_REASON\_TEST\_PREPARATION\_FAILED | 5 | none | | SKIP\_REASON\_TEST\_OWNED\_BY\_OTHER\_RULE | 6 | none | ### 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. | ### Status (synq.extensions.atlan.workflows.v1.Status) | Name | Number | Description | | - | - | - | | STATUS\_UNSPECIFIED | 0 | none | | STATUS\_OK | 1 | none | | STATUS\_FAILED | 2 | none | ### TestAlertKind (synq.alerts.services.v2.TestAlertKind) The alert kind a test message stands in for. It only selects the wording of the message; the targets receive the same static test regardless. | Name | Number | Description | | - | - | - | | TEST\_ALERT\_KIND\_UNSPECIFIED | 0 | Generic wording ("your alerts will be sent here"). | | TEST\_ALERT\_KIND\_ISSUE\_LIFECYCLE | 1 | Wording for an alert on issues. | | TEST\_ALERT\_KIND\_SCHEMA\_CHANGE | 2 | Wording for an alert on schema changes. | | TEST\_ALERT\_KIND\_INCIDENT\_LIFECYCLE | 3 | Wording for an alert on incidents. | ### 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 | ### Domain.Source (synq.domains.v1.Domain.Source) | Name | Number | Description | | - | - | - | | SOURCE\_SYNQ | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX | | SOURCE\_ATLAN | 1 | 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). | ### 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 | ### 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 | ### CoverageFilter (synq.overlays.v1.CoverageFilter) CoverageFilter narrows the candidates to those in a particular coverage state. It never widens them: everything it can return was in the selection. | Name | Number | Description | | - | - | - | | COVERAGE\_FILTER\_UNSPECIFIED | 0 | Every candidate, covered or not. The full coverage table. | | COVERAGE\_FILTER\_WITHOUT\_DATAPRODUCT | 1 | Candidates in no data product. | | COVERAGE\_FILTER\_WITHOUT\_OWNER | 2 | Candidates with no owner. | | COVERAGE\_FILTER\_WITHOUT\_ANY | 3 | Candidates in no data product *and* with no owner — nothing claims them at all. Narrower than either of the two above, not the union of them. | | COVERAGE\_FILTER\_WITH\_DATAPRODUCT | 4 | Candidates in at least one data product. | | COVERAGE\_FILTER\_WITH\_OWNER | 5 | Candidates with at least one owner. | ### Freshness (synq.overlays.v1.Freshness) Freshness chooses what a coverage answer is computed from. | Name | Number | Description | | - | - | - | | FRESHNESS\_UNSPECIFIED | 0 | Same as `FRESHNESS_CACHED`. | | FRESHNESS\_CACHED | 1 | The periodically recomputed membership, as everything else in this service reads it. Which overlays exist and what they are attached to is current; what each one *contains* is behind by at most one recomputation, and the response says how far in `members_computed_at`. This is what you want for anything that refreshes. | | FRESHNESS\_LIVE | 2 | Re-resolve every overlay definition now. Correct as of the call, and far slower and far more expensive than `FRESHNESS_CACHED` — the cost is the whole catalog, not the candidate set. Use it for a one-off audit, or right after a bulk change whose effect you need to see immediately. Responses carry no `members_computed_at`, because nothing was read from an index. | One limit worth knowing before you rely on it. This settles *whether* an asset is covered as of now; naming *which* overlays claim it still needs the recomputed membership, and that half can lag. So a row is never inconsistent with the filter that selected it — an asset this call finds uncovered comes back with empty lists whatever the index still says — but an asset that has only just started matching a rule can come back covered with nothing named yet. Counts and filters are exact either way; it is the id lists that catch up on the next recomputation. | ### ClickhouseClusterMode (synq.integrations.v1.ClickhouseClusterMode) | Name | Number | Description | | - | - | - | | CLICKHOUSE\_CLUSTER\_MODE\_UNSPECIFIED | 0 | Treated as CLICKHOUSE\_CLUSTER\_MODE\_ALL\_REPLICAS. Reading across a cluster is the behaviour of an integration that has never set this, so single-node reads have to be asked for rather than inherited from an unset field. | | CLICKHOUSE\_CLUSTER\_MODE\_ALL\_REPLICAS | 1 | Read system tables across the named cluster, so metadata covers every replica. Requires `GRANT REMOTE ON *.*`. | | CLICKHOUSE\_CLUSTER\_MODE\_SINGLE\_NODE | 2 | Read system tables on the connected node only. The one option that works on a ClickHouse whose remote\_servers defines no cluster, and it needs no REMOTE grant — but on a service that does have replicas it reports the metadata of a single node. | ### 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). | ### 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 | | SCOPE\_DELIVERY\_READ | 242 | none | | SCOPE\_DELIVERY\_EDIT | 243 | none | | SCOPE\_RECOMMENDATIONS\_READ | 244 | none | | SCOPE\_RECOMMENDATIONS\_EDIT | 245 | none | | SCOPE\_PLATFORM\_USERS\_READ | 246 | none | | SCOPE\_PLATFORM\_USER\_LINK | 247 | none | | SCOPE\_SERVICE\_ACCOUNTS\_READ | 248 | none | | SCOPE\_SERVICE\_ACCOUNTS\_EDIT | 249 | 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 | ### Source (synq.v1.Source) | Name | Number | Description | | - | - | - | | SOURCE\_APP | 0 | buf:lint:ignore ENUM\_ZERO\_VALUE\_SUFFIX | | SOURCE\_API | 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\_FIVETRAN | 250 | none | | DATA\_PLATFORM\_TYPE\_DAGSTER | 260 | none | | DATA\_PLATFORM\_TYPE\_AIRBYTE | 270 | none | | DATA\_PLATFORM\_TYPE\_STITCH | 280 | none | | DATA\_PLATFORM\_TYPE\_SNOWPLOW | 290 | 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\_DB2 | 380 | none | | DATA\_PLATFORM\_TYPE\_LOOKER\_STUDIO | 390 | none | | DATA\_PLATFORM\_TYPE\_HEX | 400 | none | | DATA\_PLATFORM\_TYPE\_OMNI | 410 | none | | DATA\_PLATFORM\_TYPE\_METABASE | 420 | none | | DATA\_PLATFORM\_TYPE\_GOOGLE\_SHEETS | 430 | none | | DATA\_PLATFORM\_TYPE\_GRAFANA | 440 | none | | DATA\_PLATFORM\_TYPE\_STREAMLIT | 450 | none | | DATA\_PLATFORM\_TYPE\_ASTRATO | 460 | none | | DATA\_PLATFORM\_TYPE\_SNOWFLAKE\_CORTEX | 470 | none | | DATA\_PLATFORM\_TYPE\_SNOWFLAKE\_INTELLIGENCE | 480 | none | | DATA\_PLATFORM\_TYPE\_CUBE | 490 | none | | DATA\_PLATFORM\_TYPE\_CENSUS | 500 | none | | DATA\_PLATFORM\_TYPE\_HIGHTOUCH | 510 | none | | DATA\_PLATFORM\_TYPE\_WORKATO | 520 | none | | DATA\_PLATFORM\_TYPE\_ESTUARY | 530 | none | | DATA\_PLATFORM\_TYPE\_DLT | 540 | none | | DATA\_PLATFORM\_TYPE\_TERRAFORM | 550 | none | | DATA\_PLATFORM\_TYPE\_HEVO | 560 | none | | DATA\_PLATFORM\_TYPE\_DATASTREAM | 570 | 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 | ### SkipReason (synq.deliveries.v1.SkipReason) SkipReason says why a delivery sent nothing. Every code path that declines to send names one, so an integration that appears silent can be explained rather than guessed at. It is an enum rather than a message we wrote once, so a caller can act on the reason: a not-subscribed event is fixed in the integration's settings, a disabled integration is fixed by enabling it, and an unsupported event type is not fixable at all. | Name | Number | Description | | - | - | - | | SKIP\_REASON\_UNSPECIFIED | 0 | none | | SKIP\_REASON\_EVENT\_TYPE\_NOT\_SUBSCRIBED | 1 | The event type is not among the ones the integration subscribes to. | | SKIP\_REASON\_EVENT\_TYPE\_UNSUPPORTED\_BY\_INTEGRATION | 2 | The destination has no representation for this kind of event. | | SKIP\_REASON\_NO\_ACTION\_FOR\_LIFECYCLE\_STATE | 3 | The change of state maps to no action on the destination. | | SKIP\_REASON\_INTEGRATION\_NOT\_FOUND | 4 | The integration the event was addressed to no longer exists. | | SKIP\_REASON\_INTEGRATION\_DISABLED | 5 | The integration exists but is disabled. | | SKIP\_REASON\_EMPTY\_EVENT\_SUBJECT | 6 | The event carried no issue or incident to describe. | ### StatusClass (synq.deliveries.v1.StatusClass) StatusClass groups HTTP statuses the way a delivery report reads them. | Name | Number | Description | | - | - | - | | STATUS\_CLASS\_UNSPECIFIED | 0 | none | | STATUS\_CLASS\_SUCCESS | 2 | 2xx — accepted. The only class that counts as delivered. | | STATUS\_CLASS\_REDIRECT | 3 | 3xx. Redirects are not followed: a delivery carries credentials scoped to one host, so a destination answering with one is treated as not having accepted the payload. | | STATUS\_CLASS\_CLIENT\_ERROR | 4 | 4xx — the destination rejected the request. | | STATUS\_CLASS\_SERVER\_ERROR | 5 | 5xx — the destination failed to handle it. | | STATUS\_CLASS\_NO\_RESPONSE | 6 | No response arrived at all: a connection failure, a TLS error, a timeout. | ### Outcome (synq.deliveries.v1.Outcome) Outcome is what became of a delivery. It is a state the service maintains, not something to recompute from status codes: a 500 that will be retried and a 500 that exhausted the retries are the same status and different outcomes. | Name | Number | Description | | - | - | - | | OUTCOME\_UNSPECIFIED | 0 | none | | OUTCOME\_PENDING | 1 | Accepted and queued, with at least one attempt still to come. | | OUTCOME\_DELIVERED | 2 | Every request the delivery produced was accepted by the destination. | | OUTCOME\_FAILED | 3 | The destination rejected it, or it was still failing when the retries ran out. No further attempt will be made — use `Redeliver` to try again. | | OUTCOME\_SKIPPED | 4 | The integration was reached and declined to send anything; `skip_reason` says why. Nothing was attempted and nothing will be. | | OUTCOME\_NOT\_ROUTED | 5 | No integration could be resolved for the event at all; `skip_reason` says why. Distinct from `OUTCOME_SKIPPED`, where the integration was found and it was its own configuration that declined. | ### SubjectType (synq.deliveries.v1.SubjectType) | Name | Number | Description | | - | - | - | | SUBJECT\_TYPE\_UNSPECIFIED | 0 | none | | SUBJECT\_TYPE\_ISSUE | 1 | none | | SUBJECT\_TYPE\_INCIDENT | 2 | none | | SUBJECT\_TYPE\_DELIVERY\_TEST | 3 | A delivery sent by `SendTestDelivery`, which is about no issue or incident. | ### 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 | | TRIAGE\_FAILURE\_CATEGORY\_NOT\_CONFIGURED | 8 | Scout is not enabled for this workspace, so no triage can run until an administrator configures it | ### 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 | ### 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. | ### 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 | ### 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 | ### ClickhouseClusterMode (synq.agent.dwh.v1.ClickhouseClusterMode) | Name | Number | Description | | - | - | - | | CLICKHOUSE\_CLUSTER\_MODE\_UNSPECIFIED | 0 | Treated as CLICKHOUSE\_CLUSTER\_MODE\_ALL\_REPLICAS. Reading across a cluster is the behaviour of a connection that has never set this, so single-node reads have to be asked for rather than inherited from an unset field. | | CLICKHOUSE\_CLUSTER\_MODE\_ALL\_REPLICAS | 1 | Read system tables across the named cluster, so metadata covers every replica. Requires `GRANT REMOTE ON *.*`. | | CLICKHOUSE\_CLUSTER\_MODE\_SINGLE\_NODE | 2 | Read system tables on the connected node only. The one option that works on a ClickHouse whose remote\_servers defines no cluster, and it needs no REMOTE grant — but on a service that does have replicas it reports the metadata of a single node. | ### 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 | ### 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 | ### 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. | ### 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. | ### IngestMessageSeverity (synq.agent.recon.v1.IngestMessageSeverity) IngestMessageSeverity is how prominently to show an IngestMessage. | Name | Number | Description | | - | - | - | | INGEST\_MESSAGE\_SEVERITY\_UNSPECIFIED | 0 | none | | INGEST\_MESSAGE\_SEVERITY\_INFO | 1 | Information, for example where to view the run. | | INGEST\_MESSAGE\_SEVERITY\_WARNING | 2 | Something the user should know about the stored run, for example that part of what was reported was not stored. | ### 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). | ### SuiteValidationSeverity (synq.agent.recon.v1.SuiteValidationSeverity) The severity of a SuiteValidationIssue. | Name | Number | Description | | - | - | - | | SUITE\_VALIDATION\_SEVERITY\_UNSPECIFIED | 0 | none | | SUITE\_VALIDATION\_SEVERITY\_ERROR | 1 | The suite has a problem that you must correct before you save or run it. | | SUITE\_VALIDATION\_SEVERITY\_WARNING | 2 | The suite can run, but the result is possibly not what you want. Examples are a query that reads the current time, a window that filters no rows, and a duration that is too long to be correct. You can save a suite that has warnings. | ### 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. | | DEPLOYMENT\_ACTION\_CATEGORIES\_CHANGED | 10 | The categories declared for the deployment's reconciliation checks changed. | ### 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. | | UNRESOLVED\_CONNECTION\_REASON\_PLATFORM\_MISMATCH | 5 | The connection is named after a workspace integration, and the mapping binds it to an integration on a different platform (a Snowflake connection mapped to a Postgres integration). The suite's SQL for that side is written for the platform it names. | | UNRESOLVED\_CONNECTION\_REASON\_DISABLED\_FOR\_WORKSPACE | 6 | Reconciliation (ad-hoc or deployed, whichever was asked for) is turned off for the whole workspace, for every integration and every credential. No mapping resolves it. | ### 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. | ### 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 | ### TimestampPrecision (synq.agent.recon.v1.TimestampPrecision) TimestampPrecision is how much of a second a timestamp column is compared to. Both sides are cut to it, never rounded, so a value that differs only beyond it matches. | Name | Number | Description | | - | - | - | | TIMESTAMP\_PRECISION\_UNSPECIFIED | 0 | none | | TIMESTAMP\_PRECISION\_SECOND | 1 | Whole seconds. | | TIMESTAMP\_PRECISION\_MILLISECOND | 2 | Milliseconds, three fractional digits. | | TIMESTAMP\_PRECISION\_MICROSECOND | 3 | Microseconds, six fractional digits. | | TIMESTAMP\_PRECISION\_EXACT | 4 | Every fractional digit both sides hold, without cutting either: on one kind of database the column is compared as it is held, and between two the sides must hold the same precision, at most microseconds, otherwise the reconciliation fails rather than cutting the finer side. | ### 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. | ### RelationshipWriteOutcome (synq.entities.custom.v1.RelationshipWriteOutcome) RelationshipWriteOutcome is the effect one requested write had. | Name | Number | Description | | - | - | - | | RELATIONSHIP\_WRITE\_OUTCOME\_UNSPECIFIED | 0 | none | | RELATIONSHIP\_WRITE\_OUTCOME\_CREATED | 1 | Nothing joined these two entities; the relationship was created. | | RELATIONSHIP\_WRITE\_OUTCOME\_UPDATED | 2 | The two entities were already joined; the relationship was replaced. | | RELATIONSHIP\_WRITE\_OUTCOME\_DELETED | 3 | The relationship existed and has been removed. | | RELATIONSHIP\_WRITE\_OUTCOME\_NOT\_FOUND | 4 | Nothing joined these two entities, so the delete removed nothing. | ### 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 | ### 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. | ### 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 | ### NumericCategory (synq.entities.v1.NumericCategory) NumericCategory is the kind of number a column holds, which decides how many significant digits its values carry. It is read from the column's type as the data warehouse declares it, with the same name meaning a different size on different warehouses taken into account: a bare FLOAT is single precision on MySQL and a double on Snowflake. | Name | Number | Description | | - | - | - | | NUMERIC\_CATEGORY\_UNSPECIFIED | 0 | The column does not hold a number, or its type is not recognised. | | NUMERIC\_CATEGORY\_INTEGER | 1 | A whole number: an integer type, or an exact decimal declared with scale 0 (a Snowflake NUMBER(38,0)). | | NUMERIC\_CATEGORY\_DECIMAL | 2 | An exact decimal (NUMERIC, DECIMAL, NUMBER) that may hold fractions, sized by its precision and scale when they are known. | | NUMERIC\_CATEGORY\_FLOAT | 3 | A double-precision binary float, about 15 significant digits. | | NUMERIC\_CATEGORY\_SINGLE\_PRECISION\_FLOAT | 4 | A single-precision binary float (REAL, FLOAT4, Float32, BINARY\_FLOAT), about 7 significant digits. | ### CodeType (synq.entities.v1.CodeType) CodeType describes how to read the body of a Code — which language or format its `content` is written in, so a client can highlight, parse or hand it to the right tool. A producer that cannot tell leaves CODE\_TYPE\_UNSPECIFIED rather than guessing; treat that as plain text. | 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 | | CODE\_TYPE\_JAVASCRIPT | 8 | JavaScript, as used for the body of a Snowflake stored procedure or user-defined function declared LANGUAGE JAVASCRIPT. | | CODE\_TYPE\_BASH | 9 | Shell script, as used by an orchestrator task that shells out instead of running SQL or Python. | | CODE\_TYPE\_DAX | 10 | DAX, the expression language behind Power BI measures and calculated columns. | | CODE\_TYPE\_JAVA | 11 | Java source, as used for the body of a Snowflake routine declared LANGUAGE JAVA. | | CODE\_TYPE\_SCALA | 12 | Scala source, as used for the body of a Snowflake routine declared LANGUAGE SCALA. | | CODE\_TYPE\_TEXT | 13 | Plain text with no known syntax. Distinct from CODE\_TYPE\_UNSPECIFIED: this is a producer stating the body has no language, rather than a producer that could not tell. | | CODE\_TYPE\_MARKDOWN | 14 | Markdown, as used by a notebook cell or a documentation block that ships beside a model. | ### CodeSource (synq.entities.v1.CodeSource) CodeSource names one of the places an entity's code is read from. An entity usually has code in more than one of them — a dbt model has its own source and the warehouse table's DDL — and each is read independently, so one being unavailable does not hide the others. | Name | Number | Description | | - | - | - | | CODE\_SOURCE\_UNSPECIFIED | 0 | none | | CODE\_SOURCE\_SQL\_DEFINITION | 1 | The compiled SQL definition of a table or view. | | CODE\_SOURCE\_ENTITY\_DEFINITION | 2 | Code carried by the entity itself: a transformation model's source, a stored routine's body, an orchestration task's script. | | CODE\_SOURCE\_REPOSITORY\_FILE | 3 | A file read from a connected repository. | | CODE\_SOURCE\_CUSTOM\_ENTITY | 4 | Code attached to a custom entity. | | CODE\_SOURCE\_SQL\_TEST | 5 | The expression of a SQL test. | | CODE\_SOURCE\_RECONCILIATION | 6 | The configuration of a deployed reconciliation suite or case. | | CODE\_SOURCE\_MONITOR | 7 | The query a monitor runs against the warehouse. | ### 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 | | SQL\_DIALECT\_DB2 | 14 | none | ### 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\_LOOKER\_INSTANCE | 210 | 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\_SNOWFLAKE\_STAGE | 517 | none | | ENTITY\_TYPE\_SNOWFLAKE\_STREAMLIT | 518 | none | | ENTITY\_TYPE\_SNOWFLAKE\_NOTEBOOK | 519 | none | | ENTITY\_TYPE\_SNOWFLAKE\_WAREHOUSE | 520 | none | | ENTITY\_TYPE\_SNOWFLAKE\_PIPE | 521 | none | | ENTITY\_TYPE\_SNOWFLAKE\_CORTEX\_SEARCH\_SERVICE | 522 | 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\_TABLEAU\_WORKBOOK | 1107 | none | | ENTITY\_TYPE\_TABLEAU\_SITE | 1108 | 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\_LINEAGE\_FOLD | 1504 | 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\_DATABRICKS\_METRIC\_VIEW | 1812 | 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\_SIGMA\_ORGANIZATION | 3203 | 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\_DB2\_TABLE | 3803 | none | | ENTITY\_TYPE\_DB2\_VIEW | 3805 | none | | ENTITY\_TYPE\_LOOKER\_STUDIO\_CUSTOMER | 3901 | none | | ENTITY\_TYPE\_LOOKER\_STUDIO\_REPORT | 3902 | none | | ENTITY\_TYPE\_LOOKER\_STUDIO\_DATA\_SOURCE | 3903 | 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 | ### 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 | ### 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 | ### 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 | ### 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. | | SQL\_CONSTRUCT\_HAS\_JOIN\_PREDICATES | 101 | Set when the parser read at least one column comparison from the SQL: a join key, or a comparison relating two columns without joining them. | | SQL\_CONSTRUCT\_HAS\_JOIN\_PAIRS | 102 | Set when at least one join key compares two columns that both belong to known entities and are declared in their schemas. | ### ActivityDirection (synq.entities.activity.v1alpha.ActivityDirection) ActivityDirection is how a query touched an entity. | Name | Number | Description | | - | - | - | | ACTIVITY\_DIRECTION\_UNSPECIFIED | 0 | none | | ACTIVITY\_DIRECTION\_READ | 1 | A statement that writes nothing read the entity. | | ACTIVITY\_DIRECTION\_INPUT | 2 | A statement that writes another table read the entity, such as a model build. | | ACTIVITY\_DIRECTION\_WRITE | 3 | Rows landed in the entity. For RUNS, one run of what builds the entity. | ### ActivityLens (synq.entities.activity.v1alpha.ActivityLens) ActivityLens picks which directions and which logins count. Coalesce Quality's own queries, a read of an intermediate table and a login's reads of a table it wrote the same day are left out under every lens, and writes never depend on it. | Name | Number | Description | | - | - | - | | ACTIVITY\_LENS\_UNSPECIFIED | 0 | Read as CONSUMPTION. | | ACTIVITY\_LENS\_CONSUMPTION | 1 | Reads by the logins whose reads count toward popularity: people, BI tools, reverse ETL and applications. What BatchGetPopularity counts. | | ACTIVITY\_LENS\_DEVELOPMENT | 2 | Every INPUT, and the reads of people: what is read to build, and what developers look at. | | ACTIVITY\_LENS\_MONITORING | 3 | Reads by a service account whose purpose is observability. | ### ActivityMeasure (synq.entities.activity.v1alpha.ActivityMeasure) ActivityMeasure is what a count counts. Counts are compared only within one measure. | Name | Number | Description | | - | - | - | | ACTIVITY\_MEASURE\_UNSPECIFIED | 0 | none | | ACTIVITY\_MEASURE\_QUERIES | 1 | Warehouse queries. | | ACTIVITY\_MEASURE\_VIEWS | 2 | Opens of a BI asset. | | ACTIVITY\_MEASURE\_RUNS | 3 | Orchestrated runs of what builds an entity. Always WRITE, with no login. | ### ActivityShape (synq.entities.activity.v1alpha.ActivityShape) ActivityShape is how a platform reports a figure. | Name | Number | Description | | - | - | - | | ACTIVITY\_SHAPE\_UNSPECIFIED | 0 | none | | ACTIVITY\_SHAPE\_INTERVAL | 1 | Occurrences counted per event, hour or day. | | ACTIVITY\_SHAPE\_CUMULATIVE | 2 | The day's difference between two daily readings of an all-time counter. | | ACTIVITY\_SHAPE\_TRAILING\_WINDOW | 3 | The platform's own "N in the last M days". | | ACTIVITY\_SHAPE\_LATEST\_VALUE | 4 | A figure with no stated window. | ### ComputeUnit (synq.entities.activity.v1alpha.ComputeUnit) ComputeUnit is what compute\_ms counts on one platform. Each platform reports its own unit, so compute is never summed across platforms. | Name | Number | Description | | - | - | - | | COMPUTE\_UNIT\_UNSPECIFIED | 0 | The platform reports no compute figure. | | COMPUTE\_UNIT\_SNOWFLAKE\_XSMALL\_WAREHOUSE\_MS | 1 | Milliseconds of an X-Small warehouse: a query's execution time scaled by its warehouse size and its share of the warehouse. | | COMPUTE\_UNIT\_BIGQUERY\_SLOT\_MS | 2 | BigQuery slot milliseconds. | | COMPUTE\_UNIT\_DATABRICKS\_TASK\_MS | 3 | Databricks task milliseconds. | ### PopularityPool (synq.entities.activity.v1alpha.PopularityPool) PopularityPool is what a rank compares an entity with. | Name | Number | Description | | - | - | - | | POPULARITY\_POOL\_UNSPECIFIED | 0 | Read as SYSTEM. | | POPULARITY\_POOL\_SYSTEM | 1 | One measure on one platform instance, such as one Snowflake account. | | POPULARITY\_POOL\_PLATFORM | 2 | One measure on every instance of one platform. | | POPULARITY\_POOL\_WORKSPACE | 3 | One measure across the workspace. | ### Purpose (synq.entities.activity.v1alpha.Purpose) Purpose is what a service account acts for. It decides whether its reads count toward popularity when its popularity policy does not say. | Name | Number | Description | | - | - | - | | PURPOSE\_UNSPECIFIED | 0 | none | | PURPOSE\_LOADER | 1 | Ingestion and replication, such as Fivetran, Airbyte, Stitch or Estuary. | | PURPOSE\_ORCHESTRATOR | 2 | Airflow, Dagster. | | PURPOSE\_TRANSFORMER | 3 | dbt, Coalesce Transform, SQLMesh. | | PURPOSE\_BI | 4 | Looker, Tableau, Sigma, Power BI. | | PURPOSE\_REVERSE\_ETL | 5 | Hightouch, Census. | | PURPOSE\_APPLICATION | 6 | A product or service that reads its own data, such as a Streamlit app. | | PURPOSE\_OBSERVABILITY | 7 | Data quality and observability tools, Coalesce Quality included. | | PURPOSE\_CATALOG | 8 | Metadata crawlers, Coalesce Catalog included. | | PURPOSE\_CI | 9 | CI and infrastructure as code. | | PURPOSE\_OTHER | 10 | none | ### SeriesSplit (synq.entities.activity.v1alpha.SeriesSplit) SeriesSplit is how each point of a series is broken down. | Name | Number | Description | | - | - | - | | SERIES\_SPLIT\_UNSPECIFIED | 0 | No breakdown. | | SERIES\_SPLIT\_ISSUER | 1 | Per issuing tool, from the tag its queries carry. | ### WriteCadence (synq.entities.activity.v1alpha.WriteCadence) WriteCadence is how often something wrote an entity in the window, from the median gap between the hours with writes. It is not freshness. | Name | Number | Description | | - | - | - | | WRITE\_CADENCE\_UNSPECIFIED | 0 | none | | WRITE\_CADENCE\_NONE | 1 | Nothing written in the window. | | WRITE\_CADENCE\_ONCE | 2 | One hour with writes. | | WRITE\_CADENCE\_HOURLY | 3 | none | | WRITE\_CADENCE\_SUB\_DAILY | 4 | Several times a day. | | WRITE\_CADENCE\_DAILY | 5 | none | | WRITE\_CADENCE\_WEEKLY | 6 | none | | WRITE\_CADENCE\_RARE | 7 | Less often than weekly. | ### AccessSignal (synq.entities.activity.v1alpha.AccessSignal) AccessSignal is a place where how an entity is used and what is expected of it disagree. Coalesce Quality's own access, such as a monitor reading a table, never counts as using it. | Name | Number | Description | | - | - | - | | ACCESS\_SIGNAL\_UNSPECIFIED | 0 | none | | ACCESS\_SIGNAL\_BUILT\_NEVER\_READ | 1 | A pipeline, an orchestrator's runs or what transforms, wrote the entity in the window, and nobody read it or built anything from it. Each entity carries its share of what building it cost. | | ACCESS\_SIGNAL\_UNTOUCHED | 2 | A live warehouse table or view nobody read, built from or wrote in the window, with the schema it lives in. A table on a platform with no query history in the window is never untouched, as nothing could have seen it used. | | ACCESS\_SIGNAL\_READ\_WITHOUT\_VIEWER | 3 | Reads that count toward popularity came through a login that reads for whoever looks at a BI tool or an application, so the viewer behind them is not known. The response sums them per tool. | | ACCESS\_SIGNAL\_WRITTEN\_OUTSIDE\_PIPELINE | 4 | A pipeline maintains the entity while a person, or a login nobody names, writes it too. | ### ActorGroupKind (synq.entities.activity.v1alpha.ActorGroupKind) ActorGroupKind is the group a login's queries land in on the overview. Each lands in exactly one, so the groups add up to the workspace. | Name | Number | Description | | - | - | - | | ACTOR\_GROUP\_KIND\_UNSPECIFIED | 0 | none | | ACTOR\_GROUP\_KIND\_COALESCE | 1 | Coalesce Quality's own queries on any login, and every query of a login Coalesce Quality or Coalesce Catalog connects as. | | ACTOR\_GROUP\_KIND\_SERVICE\_ACCOUNT | 2 | The logins whose first service account is this one, a built-in one included. | | ACTOR\_GROUP\_KIND\_TOOL | 3 | A tool's tag on queries of logins no service account holds. | | ACTOR\_GROUP\_KIND\_PEOPLE | 4 | The logins known to be a person's: those a person rule or the platform's email names a person. | | ACTOR\_GROUP\_KIND\_UNATTRIBUTED | 5 | Queries that name no login. | | ACTOR\_GROUP\_KIND\_LOGINS | 6 | The logins nothing classifies. Nothing says whether a person or a program is behind one, so it is a login, never a person. | ### ActorKind (synq.entities.activity.v1alpha.ActorKind) ActorKind is what an actor of ListActors is. | Name | Number | Description | | - | - | - | | ACTOR\_KIND\_UNSPECIFIED | 0 | none | | ACTOR\_KIND\_COALESCE | 1 | Coalesce Quality's own queries on any login, and every query of a login Coalesce Quality or Coalesce Catalog connects as. | | ACTOR\_KIND\_SERVICE\_ACCOUNT | 2 | The logins a service account holds, a built-in one included. | | ACTOR\_KIND\_TOOL | 3 | A tool, from the tag its queries carry, on any login. | | ACTOR\_KIND\_PERSON | 4 | The logins of one person. | | ACTOR\_KIND\_LOGIN | 5 | A login nothing classifies, with all of its queries. | ### ActorSort (synq.entities.activity.v1alpha.ActorSort) ActorSort is the order of ListActors, highest first, then by kind and actor. | Name | Number | Description | | - | - | - | | ACTOR\_SORT\_UNSPECIFIED | 0 | Read as ACCESS. | | ACTOR\_SORT\_ACCESS | 1 | Reads, inputs and writes together. | | ACTOR\_SORT\_QUERIES | 2 | Queries. Refused under a selection, which counts access, not queries. | | ACTOR\_SORT\_READS | 3 | none | | ACTOR\_SORT\_WRITES | 4 | none | | ACTOR\_SORT\_COMPUTE | 5 | Compute on the asked platform, as each platform reports compute in its own unit. Under a selection, the compute share of the selected entities. | ### FileOperation (synq.entities.activity.v1alpha.FileOperation) FileOperation is a query that moves files rather than rows. | Name | Number | Description | | - | - | - | | FILE\_OPERATION\_UNSPECIFIED | 0 | none | | FILE\_OPERATION\_LOAD | 1 | A COPY that lands files in a table. | | FILE\_OPERATION\_UNLOAD | 2 | A COPY that writes a table's rows out to files. | | FILE\_OPERATION\_PUT | 3 | A file uploaded to a stage, such as a Snowflake PUT. | | FILE\_OPERATION\_GET | 4 | A file downloaded from a stage, such as a Snowflake GET. | | FILE\_OPERATION\_REMOVE | 5 | Files removed from a stage, such as a Snowflake REMOVE. | ### LoginBasis (synq.entities.activity.v1alpha.LoginBasis) LoginBasis is how a login touching an entity is known. | Name | Number | Description | | - | - | - | | LOGIN\_BASIS\_UNSPECIFIED | 0 | none | | LOGIN\_BASIS\_SERVICE\_ACCOUNT | 1 | A login in a service account. Never a person. | | LOGIN\_BASIS\_SHARED\_LOGIN | 2 | A login that stands for whoever was looking: one in a BI or application service account, or a login reading for a BI or application tool. | | LOGIN\_BASIS\_OWN\_LOGIN | 3 | A login linked to a person, by a person link or the platform's email. A platform user alias in synq.users.v1 that names the login wins over that person: the caller applies it. | | LOGIN\_BASIS\_UNRESOLVED\_LOGIN | 4 | A login nothing classifies, presumed a person. | | LOGIN\_BASIS\_VIEWER\_EMAIL | 5 | A viewer a BI tool's query tag named by email, on the BI asset it looked at. | | LOGIN\_BASIS\_VIEWER\_TOOL\_USER | 6 | A viewer a BI tool's query tag named by the tool's own user id, on the BI asset it looked at. | ### UsageEvidence (synq.entities.activity.v1alpha.UsageEvidence) UsageEvidence is what a role was learned from, and what its count counts. | Name | Number | Description | | - | - | - | | USAGE\_EVIDENCE\_UNSPECIFIED | 0 | none | | USAGE\_EVIDENCE\_IDENTITY | 1 | An entity that is the same as the asked one, such as the dbt model that builds a table, with no activity in the window. count is 0. | | USAGE\_EVIDENCE\_RUNS | 2 | Orchestrated runs. | | USAGE\_EVIDENCE\_QUERIES | 3 | Warehouse queries. | | USAGE\_EVIDENCE\_VIEWS | 4 | Opens of a BI asset. | ### UsageLevel (synq.entities.activity.v1alpha.UsageLevel) UsageLevel is how precisely a role names its actor, most precise first. A role with an ENTITY or a SERVICE\_ACCOUNT row has no TOOL row for the same tool. | Name | Number | Description | | - | - | - | | USAGE\_LEVEL\_UNSPECIFIED | 0 | none | | USAGE\_LEVEL\_ENTITY | 1 | A job, task, step, model or app, in issuer\_entity\_id. One that no longer exists falls back to its tool. | | USAGE\_LEVEL\_SERVICE\_ACCOUNT | 2 | A service account, a built-in one included, in service\_account\_id. | | USAGE\_LEVEL\_TOOL | 3 | Only the tool, in issuer, from the tag on its queries. | | USAGE\_LEVEL\_PEOPLE | 4 | The logins known to be a person's, by a person rule or the platform's email. actors counts the people. | | USAGE\_LEVEL\_UNKNOWN | 5 | Access with no login and no tool. | | USAGE\_LEVEL\_LOGINS | 6 | The logins nothing classifies, none of them known to be a person. actors counts the logins. | ### UsageRoleKind (synq.entities.activity.v1alpha.UsageRoleKind) UsageRoleKind is what an actor does to an entity, in the order to draw them in, left to right. | Name | Number | Description | | - | - | - | | USAGE\_ROLE\_KIND\_UNSPECIFIED | 0 | none | | USAGE\_ROLE\_KIND\_LOADED | 1 | A loader writes it, such as Fivetran, Airbyte, Stitch or a loader service account. | | USAGE\_ROLE\_KIND\_ORCHESTRATED | 2 | An orchestrator runs what builds it, such as an Airflow task, a dbt Cloud job step or a Coalesce job, or an orchestrator writes it. Two orchestrators of one run are two roles, each with its own count. | | USAGE\_ROLE\_KIND\_TRANSFORMED | 3 | A transformer builds it: a dbt model, a Coalesce node or a SQLMesh model that is the same entity, even with no query history, and a transformer's writes, which add to that model. | | USAGE\_ROLE\_KIND\_WRITTEN | 4 | Any other write, such as a person's. | | USAGE\_ROLE\_KIND\_READ | 5 | A tool, an app or people read it. | | USAGE\_ROLE\_KIND\_REVERSE\_ETL | 6 | A reverse ETL tool, such as Census or Hightouch, reads it to copy the rows into another system, so a broken entity breaks a sync there. | ### CategorySource (synq.entities.checks.v2.CategorySource) Where a check's effective category came from. The three sources are a strict precedence: an admin override beats a producer-explicit category, which beats a computed one. | Name | Number | Description | | - | - | - | | CATEGORY\_SOURCE\_UNSPECIFIED | 0 | The check has no category on this dimension — it is uncategorised. | | CATEGORY\_SOURCE\_OVERRIDE | 1 | Admin override — pinned on the check itself through UpsertCheckCategories. Overrides always win. | | CATEGORY\_SOURCE\_PRODUCER | 2 | Producer-explicit — declared by the tool that produced the check, either directly or as a `quality.check_category` / `quality.governance_category` annotation carried on the source asset. | | CATEGORY\_SOURCE\_RULE | 3 | Computed — derived from the workspace's categorisation rules. | ### RecategorisationStatus.State (synq.entities.checks.v2.RecategorisationStatus.State) | Name | Number | Description | | - | - | - | | STATE\_UNSPECIFIED | 0 | none | | STATE\_IDLE | 1 | No sweep is scheduled or running — the workspace's checks are up to date with its rules. | | STATE\_SCHEDULED | 2 | A sweep is queued but has not started. | | STATE\_IN\_PROGRESS | 3 | A sweep is running. | ### CategoryDimension (synq.entities.checks.v2.CategoryDimension) The dimension a category classifies a check along. A check carries at most one category per dimension, and the two resolve independently of each other. | Name | Number | Description | | - | - | - | | CATEGORY\_DIMENSION\_UNSPECIFIED | 0 | none | | CATEGORY\_DIMENSION\_TECHNICAL | 1 | Technical — what kind of check this is, mechanically. Values such as "nullness", "uniqueness", "referential integrity", "freshness". | | CATEGORY\_DIMENSION\_GOVERNANCE | 2 | Governance — what the check is for, in data-quality terms. Values such as "Completeness", "Accuracy", "Validity", "Timeliness", "Uniqueness". | ### CategorisationFilter (synq.entities.checks.v2.CategorisationFilter) Narrows a listing to checks that do — or do not — have an effective category on a dimension. | Name | Number | Description | | - | - | - | | CATEGORISATION\_FILTER\_UNSPECIFIED | 0 | No filter. | | CATEGORISATION\_FILTER\_CATEGORISED | 1 | Only checks that have an effective category on the dimension. | | CATEGORISATION\_FILTER\_UNCATEGORISED | 2 | Only checks with no effective category on the dimension. | ### OverrideFilter (synq.entities.checks.v2.OverrideFilter) Narrows a listing to checks that do — or do not — carry a category set explicitly on them on a dimension. | Name | Number | Description | | - | - | - | | OVERRIDE\_FILTER\_UNSPECIFIED | 0 | No filter. | | OVERRIDE\_FILTER\_OVERRIDDEN | 1 | Only checks whose category on the dimension was set explicitly. | | OVERRIDE\_FILTER\_NOT\_OVERRIDDEN | 2 | Only checks whose category on the dimension was not set explicitly. | ### RuleScope (synq.entities.checks.v2.RuleScope) Whether a categorisation rule belongs to the workspace or is one of the platform-provided defaults. | Name | Number | Description | | - | - | - | | RULE\_SCOPE\_UNSPECIFIED | 0 | none | | RULE\_SCOPE\_GLOBAL | 1 | Platform-provided rule, shared by every workspace and read-only for workspace users. | | RULE\_SCOPE\_WORKSPACE | 2 | Rule defined in the caller's workspace. A workspace rule always wins over a matching global rule. | ### 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 | ### LinkEvidence (synq.entities.platformusers.v1alpha.LinkEvidence) LinkEvidence is why a login is suggested for a member, strongest first. | Name | Number | Description | | - | - | - | | LINK\_EVIDENCE\_UNSPECIFIED | 0 | none | | LINK\_EVIDENCE\_LOGIN\_IS\_EMAIL | 1 | The login is an email address equal to the member's email. | | LINK\_EVIDENCE\_EMAIL\_LOCAL\_PART | 2 | The login equals the local part of the member's email. | | LINK\_EVIDENCE\_NAME | 3 | The login spells the member's first and last name. | ### PlatformUserView (synq.entities.platformusers.v1alpha.PlatformUserView) PlatformUserView is how much of a login a read returns. | Name | Number | Description | | - | - | - | | PLATFORM\_USER\_VIEW\_UNSPECIFIED | 0 | Read as BASIC. | | PLATFORM\_USER\_VIEW\_BASIC | 1 | Everything but the signals of each slice. | | PLATFORM\_USER\_VIEW\_FULL | 2 | With the signals of each slice. | ### SuggestionConfidence (synq.entities.platformusers.v1alpha.SuggestionConfidence) SuggestionConfidence is how sure a suggestion is, from its evidence. | Name | Number | Description | | - | - | - | | SUGGESTION\_CONFIDENCE\_UNSPECIFIED | 0 | none | | SUGGESTION\_CONFIDENCE\_LOW | 1 | A name token or behaviour alone. | | SUGGESTION\_CONFIDENCE\_MEDIUM | 2 | A tool's tag, a name a tool's setup guide prescribes, a loader's columns on part of the writes, or behaviour with a name token. | | SUGGESTION\_CONFIDENCE\_HIGH | 3 | Coalesce Quality's own tag, a kind of login the platform states, or a loader's columns on nearly every write. | ### SuggestionSource (synq.entities.platformusers.v1alpha.SuggestionSource) SuggestionSource is the evidence a suggestion rests on, most confident first. | Name | Number | Description | | - | - | - | | SUGGESTION\_SOURCE\_UNSPECIFIED | 0 | none | | SUGGESTION\_SOURCE\_COALESCE\_QUALITY\_MARKER | 1 | Coalesce Quality's tag on the queries of a login Coalesce Quality does not know as its own. | | SUGGESTION\_SOURCE\_TOOL\_MARKER | 2 | Another tool's tag on the login's queries. | | SUGGESTION\_SOURCE\_PLATFORM\_KIND | 3 | A kind of login the platform states is not a person, such as Snowflake's `SERVICE`. | | SUGGESTION\_SOURCE\_NAME\_PATTERN | 4 | A login name a tool's setup guide tells you to create, such as `FIVETRAN_USER`. | | SUGGESTION\_SOURCE\_LOADER\_FOOTPRINT | 5 | The tables the login writes carry a loader's columns, such as Fivetran's `_fivetran_synced`. | | SUGGESTION\_SOURCE\_BEHAVIOUR | 6 | The login writes on a fixed cadence, reads through every hour of the day, loads files, or touches far more entities than people do. | | SUGGESTION\_SOURCE\_NAME\_TOKEN | 7 | A tool's name or a service affix, such as `_SVC`, inside the login name. | ### Classification (synq.entities.platformusers.v1alpha.Classification) Classification is how a login reads, in one word. | Name | Number | Description | | - | - | - | | CLASSIFICATION\_UNSPECIFIED | 0 | none | | CLASSIFICATION\_PERSON | 1 | Linked to a person, by a person link or the email the platform states. | | CLASSIFICATION\_SERVICE\_ACCOUNT | 2 | In one of the workspace's service accounts. | | CLASSIFICATION\_BUILT\_IN | 3 | In a built-in account only. | | CLASSIFICATION\_COALESCE | 4 | A login Coalesce Quality or Coalesce Catalog connects as. | | CLASSIFICATION\_UNCLASSIFIED | 5 | Nothing classifies it. It is presumed a person, and its reads count. | ### EvidenceKind (synq.entities.platformusers.v1alpha.EvidenceKind) EvidenceKind is a kind of hint about what a login is. | Name | Number | Description | | - | - | - | | EVIDENCE\_KIND\_UNSPECIFIED | 0 | none | | EVIDENCE\_KIND\_TOOL\_MARKER | 1 | A tool's tag on its queries. | | EVIDENCE\_KIND\_NAME\_PATTERN | 2 | A login name a tool's setup guide tells you to create. | | EVIDENCE\_KIND\_PLATFORM\_KIND | 3 | A kind of login the platform states is not a person. | | EVIDENCE\_KIND\_FOOTPRINT | 4 | The tables it writes carry a loader's columns. | | EVIDENCE\_KIND\_WRITE\_CADENCE | 5 | It writes on a fixed cadence. | | EVIDENCE\_KIND\_EMAIL | 6 | The platform states an email for it. | | EVIDENCE\_KIND\_READ\_CADENCE | 7 | It reads through every hour of the day. | | EVIDENCE\_KIND\_LOAD\_OPERATIONS | 8 | Most of its queries load files or move them on a stage. | | EVIDENCE\_KIND\_NAME\_TOKEN | 9 | Its name holds a tool's name or a service affix, such as `_SVC`. | | EVIDENCE\_KIND\_PERSON\_NAME | 10 | Its name reads as a person's, such as `JANE.DOE`, `JANE_DOE` or an email address, and nothing about it says it is a service. A hint about the login, not who it is: the login stays unclassified until a person rule, a stated email or a link names its person. | ### MatchKind (synq.entities.platformusers.v1alpha.MatchKind) MatchKind is why a slice is in a service account. | Name | Number | Description | | - | - | - | | MATCH\_KIND\_UNSPECIFIED | 0 | none | | MATCH\_KIND\_EXACT | 1 | An exact matcher names the login. | | MATCH\_KIND\_MATCHER | 2 | A matcher's patterns or conditions match it. | | MATCH\_KIND\_BUILT\_IN | 3 | A built-in account's rules match it. | ### JoinEvidenceKind (synq.entities.sql\_insights.v1.JoinEvidenceKind) JoinEvidenceKind says where a join pattern was seen. | Name | Number | Description | | - | - | - | | JOIN\_EVIDENCE\_KIND\_UNSPECIFIED | 0 | none | | JOIN\_EVIDENCE\_KIND\_SQL\_DEFINITION | 1 | The SQL that builds a table, view or model joins on the key. | | JOIN\_EVIDENCE\_KIND\_QUERY\_LOG | 2 | Queries in the warehouse's query history made the join. | ### JoinIssuerKind (synq.entities.sql\_insights.v1.JoinIssuerKind) JoinIssuerKind says who ran the queries of a JoinIssuer. | Name | Number | Description | | - | - | - | | JOIN\_ISSUER\_KIND\_UNSPECIFIED | 0 | none | | JOIN\_ISSUER\_KIND\_TOOL | 1 | A tool that the query's tag names. | | JOIN\_ISSUER\_KIND\_PEOPLE | 2 | People: warehouse users linked to a person, with an email, or not classified otherwise. | | JOIN\_ISSUER\_KIND\_SERVICE\_ACCOUNT | 3 | Warehouse users in a service account. | | JOIN\_ISSUER\_KIND\_COALESCE | 4 | The warehouse users Coalesce connects as, for Coalesce Quality or Coalesce Catalog. | | JOIN\_ISSUER\_KIND\_UNKNOWN | 5 | Queries that name no warehouse user, or users of a recognized tool that no service account holds. | ### JoinKeeps (synq.entities.sql\_insights.v1.JoinKeeps) JoinKeeps says which side of a join keeps all of its rows, also those that find no match, seen from the requested entity's side. A row with no match comes back with the other side's columns null. | Name | Number | Description | | - | - | - | | JOIN\_KEEPS\_UNSPECIFIED | 0 | A semi or anti join, UPDATE FROM, DELETE USING or MERGE, which return or change the rows of one side only. | | JOIN\_KEEPS\_MATCHED | 1 | Only the rows that match: an inner join, a comma join, or a cross join with a predicate. | | JOIN\_KEEPS\_REQUESTED | 2 | All rows of the requested entity: a left outer join from its side, or an ASOF join in which it is the side looking for a match. | | JOIN\_KEEPS\_OTHER | 3 | All rows of the other entity: a right outer join from the requested entity's side, or an ASOF join in which the other side looks for a match. | | JOIN\_KEEPS\_BOTH | 4 | All rows of both: a full outer join. | ### JoinType (synq.entities.sql\_insights.v1.JoinType) JoinType is a join type as a semantic layer names it. | Name | Number | Description | | - | - | - | | JOIN\_TYPE\_UNSPECIFIED | 0 | none | | JOIN\_TYPE\_LEFT\_OUTER | 1 | none | | JOIN\_TYPE\_INNER | 2 | none | | JOIN\_TYPE\_FULL\_OUTER | 3 | none | | JOIN\_TYPE\_CROSS | 4 | none | | JOIN\_TYPE\_OTHER | 5 | `native_join_type` says which. | ### JoinKind (synq.entities.sql\_insights.v1.JoinKind) JoinKind is the kind of join a join pair belongs to. | Name | Number | Description | | - | - | - | | JOIN\_KIND\_UNSPECIFIED | 0 | none | | JOIN\_KIND\_INNER | 1 | INNER JOIN, an unqualified `JOIN`, or MySQL `STRAIGHT_JOIN`. | | JOIN\_KIND\_LEFT\_OUTER | 2 | LEFT \[OUTER] JOIN. The left side is the one SQL wrote first. | | JOIN\_KIND\_RIGHT\_OUTER | 3 | RIGHT \[OUTER] JOIN. | | JOIN\_KIND\_FULL\_OUTER | 4 | FULL \[OUTER] JOIN. | | JOIN\_KIND\_CROSS | 5 | CROSS JOIN written with a predicate, which some dialects accept. | | JOIN\_KIND\_LEFT\_SEMI | 6 | LEFT SEMI JOIN. | | JOIN\_KIND\_RIGHT\_SEMI | 7 | RIGHT SEMI JOIN. | | JOIN\_KIND\_LEFT\_ANTI | 8 | LEFT ANTI JOIN. | | JOIN\_KIND\_RIGHT\_ANTI | 9 | RIGHT ANTI JOIN. | | JOIN\_KIND\_ASOF | 10 | Snowflake / Databricks ASOF JOIN, from its MATCH\_CONDITION or its ON. | | JOIN\_KIND\_IMPLICIT | 11 | A comma join: `FROM a, b WHERE a.x = b.y`. The predicate comes from the WHERE clause and compares columns of two different FROM items. | | JOIN\_KIND\_UPDATE\_FROM | 12 | `UPDATE t … FROM s WHERE t.x = s.y`: a WHERE comparison between the updated table and a FROM item. | | JOIN\_KIND\_DELETE\_USING | 13 | `DELETE FROM t USING s WHERE t.x = s.y`: a WHERE comparison between a table rows are deleted from and a USING item. | | JOIN\_KIND\_MERGE | 14 | `MERGE INTO t USING s ON t.x = s.y`: a conjunct of the MERGE's ON. The statement then acts on matched and unmatched rows alike, so no outer-join kind describes it. | ### JoinOperator (synq.entities.sql\_insights.v1.JoinOperator) JoinOperator is the comparison a join pair makes between its two sides. | Name | Number | Description | | - | - | - | | JOIN\_OPERATOR\_UNSPECIFIED | 0 | none | | JOIN\_OPERATOR\_EQ | 1 | `=`. | | JOIN\_OPERATOR\_NULL\_SAFE\_EQ | 2 | A null-safe equality: `<=>` or `IS NOT DISTINCT FROM`. | | JOIN\_OPERATOR\_NOT\_EQ | 3 | `<>` or `!=`. | | JOIN\_OPERATOR\_LT | 4 | `<`. | | JOIN\_OPERATOR\_LTE | 5 | `<=`, and the upper bound of a BETWEEN. | | JOIN\_OPERATOR\_GT | 6 | `>`. | | JOIN\_OPERATOR\_GTE | 7 | `>=`, and the lower bound of a BETWEEN. | | JOIN\_OPERATOR\_OTHER | 8 | Anything else that relates two tables: an OR, a NOT BETWEEN, LIKE, a function of columns of both. The sides then hold the columns each table contributes, and `expression` holds the whole predicate. | ### JoinSideDerivation (synq.entities.sql\_insights.v1.JoinSideDerivation) JoinSideDerivation is how a join pair side's column reaches the comparison. | Name | Number | Description | | - | - | - | | JOIN\_SIDE\_DERIVATION\_UNSPECIFIED | 0 | none | | JOIN\_SIDE\_DERIVATION\_PASSTHROUGH | 1 | The base column arrives unchanged: `a.id`, or a CTE column that selects it as is. | | JOIN\_SIDE\_DERIVATION\_RENAMED | 2 | Only an alias changed on the way, in a CTE or a subquery: `id AS order_id`. | | JOIN\_SIDE\_DERIVATION\_TRANSFORMED | 3 | An expression stands between the base column and the comparison: `lower(a.email)`, `left(a.id, 15)`, a CASE, a cast. Evidence of a relationship, never a plain column pair. | ### 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.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 | ### 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. | ### 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 | ### UserRole (synq.users.v1.UserRole) UserRole is a role a member holds in the workspace. Names match the roles shown in Settings → Team. | Name | Number | Description | | - | - | - | | USER\_ROLE\_UNSPECIFIED | 0 | none | | USER\_ROLE\_ADMIN | 1 | Admin: full control of the workspace, including its members. | | USER\_ROLE\_DEVELOPER | 2 | Developer. | | USER\_ROLE\_ANALYST | 3 | Analyst. | | USER\_ROLE\_BUSINESS\_USER | 4 | Business User. | ### UserStatus (synq.users.v1.UserStatus) UserStatus is where a member is in the invitation lifecycle of the workspace. | Name | Number | Description | | - | - | - | | USER\_STATUS\_UNSPECIFIED | 0 | none | | USER\_STATUS\_ACTIVE | 1 | The member can sign in to the workspace. | | USER\_STATUS\_INVITED | 2 | The member was invited and has not signed in since. | ### 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. | ### 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 | ### 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 | ### 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 | ### 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. | ### 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. | ### 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 | ### 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 | ### SqlTestDeploymentRuleType (synq.datachecks.sqltests.v1.SqlTestDeploymentRuleType) SqlTestDeploymentRuleType identifies which kind of selection a deployment rule uses. The value corresponds to the populated `config` oneof arm on SqlTestDeploymentRule / SqlTestDeploymentRuleView. Use it with ListSqlTestDeploymentRulesRequest.rule\_types to return only rules of selected kinds. | Name | Number | Description | | - | - | - | | SQL\_TEST\_DEPLOYMENT\_RULE\_TYPE\_UNSPECIFIED | 0 | No filter — when used in a request, rules of any type are returned. | | SQL\_TEST\_DEPLOYMENT\_RULE\_TYPE\_QUERY | 1 | Rule with `query_config`: selects tables/views by query and deploys tests on the matches. | | SQL\_TEST\_DEPLOYMENT\_RULE\_TYPE\_EXCLUSIVE\_QUERY | 2 | Rule with `exclusive_query_config`: a query whose matches are exclusively owned by this rule. | | SQL\_TEST\_DEPLOYMENT\_RULE\_TYPE\_STATIC | 3 | Rule with `static_config`: targets a single fixed table or view. | | SQL\_TEST\_DEPLOYMENT\_RULE\_TYPE\_EXCLUSIVE\_STATIC | 4 | Rule with `exclusive_static_config`: a single fixed table or view, exclusively owned. | ### SqlTestSkipReason (synq.datachecks.sqltests.v1.SqlTestSkipReason) SqlTestSkipReason is the checkable form of the `reason` string carried by SqlTestsDeploymentOverview\.SkippedTable and .SkippedTest, mirroring the SCREAMING\_SNAKE tokens documented on those fields one-for-one. It also carries the reason a SqlTestDeploymentChange deletes a test, which has no string form. The set is open by design — a producer may report a reason before this enum has a matching value for it — so a client must treat SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED (and any value this client predates) as "skipped, reason unrecognised" rather than as proof nothing applies. | Name | Number | Description | | - | - | - | | SQL\_TEST\_SKIP\_REASON\_UNSPECIFIED | 0 | none | | SQL\_TEST\_SKIP\_REASON\_HIGHER\_PRIORITY\_RULE | 1 | none | | SQL\_TEST\_SKIP\_REASON\_NO\_INTEGRATION | 2 | none | | SQL\_TEST\_SKIP\_REASON\_TEST\_PREPARATION\_FAILED | 3 | none | | SQL\_TEST\_SKIP\_REASON\_TEST\_OWNED\_BY\_OTHER\_RULE | 4 | none | | SQL\_TEST\_SKIP\_REASON\_MISSING\_COLUMNS | 5 | The table's schema is known and lacks a column the test reads. | | SQL\_TEST\_SKIP\_REASON\_SCHEMA\_UNAVAILABLE | 6 | No schema is known for the table yet, so column tests cannot be checked. | # 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) * [bi\_tool\_lineage](examples/golang/bi_tool_lineage) * [create\_dataproduct](examples/golang/create_dataproduct) * [datachecks](examples/golang/datachecks) * [deliveries](examples/golang/deliveries) * [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) * [monitors\_history](examples/golang/monitors_history) * [monitors\_predictions](examples/golang/monitors_predictions) * [omni\_types](examples/golang/omni_types) * [owners\_ownership](examples/golang/owners_ownership) * [replication\_lineage](examples/golang/replication_lineage) * [token\_auth](examples/golang/token_auth) #### http * [users\_management](examples/http/users_management) #### python * [alerts\_management](examples/python/alerts_management) * [bi\_tool\_lineage](examples/python/bi_tool_lineage) * [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) * [users\_management](examples/python/users_management) # 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} # For other regions: api.us.synq.io for US, api.au.synq.io for AU. curl -d "client_id=&client_secret=&grant_type=client_credentials" -X POST https://developer.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 62 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. | | `DeleteComment`
*synq.issues.v2.IssuesService*
`DELETE /api/issues/v2/{issue_id}/comment/{comment_id}` | Delete a comment on an issue. Only the actor who posted the comment may | | `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` | | | `DeleteComment`
*synq.incidents.v1.IncidentsService*
`DELETE /api/incidents/v1/{incident_id}/comment/{comment_id}` | Delete a comment on an incident. Only the actor who posted the comment may | | `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. | | `BatchGetEntityUsage`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/usage` | Read how each asked entity is used over the window, in one line: what loads it, what runs and | | `BatchGetPopularity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/popularity` | Read how popular each asked entity is over the window: its counted reads and writes per measure, | | `GetActivityOverview`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/overview` | Read a workspace's queries and their cost per group of logins, per platform, and its most read | | `GetEntityActivitySeries`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/series` | Read how access to one entity moves over the window: per direction, a point per UTC hour, a point | | `ListAccessSignals`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/signals` | List the entities of the workspace, or of a selection, that one signal names, such as the tables | | `ListActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-list` | List the workspace's actors, the service accounts, tools, people, logins nothing classifies and | | `BatchGetEntityAnnotations`
*synq.entities.annotations.v1.AnnotationsService*
`POST /api/entities/annotations/v1/batchGet` | Read the annotations carried by specific entities. | | `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. | | `ListCheckRelationships`
*synq.entities.custom.v1.ChecksRelationshipsService*
`POST /api/entities/custom/v1/check-relationships/list` | List every relationship that attaches a check to the entities it | | `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 the features of one entity, or of every custom entity in the | | `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 for each of the requested entities, | | `ListJoinPatterns`
*synq.entities.sql\_insights.v1.SqlInsightsService*
`GET /api/sql-insights/v1/join-patterns` | ListJoinPatterns lists how other SQL joins a table, or one of its columns: | | `ListSqlConstructs`
*synq.entities.sql\_insights.v1.SqlInsightsService*
`GET /api/sql-insights/v1/constructs` | ListSqlConstructs returns the distribution of SQL constructs across all | | `ListEntityTraitDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-traits/list` | List every trait a selection query can filter entities by. | | `ListEntityTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-types/list` | List every kind of entity in your workspace, the built-in types and your own. | | `ListExecutionTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/execution-types/list` | List every kind of run Coalesce Quality records against an entity. | | `ListPlatformDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/platforms/list` | List every platform Coalesce Quality connects to, with its display name. | | `GetDiffByCommit`
*synq.git.commits.v1.CommitsService*
`GET /api/git/v1/commit/{commit_sha}` | | | `BatchGetEntityKnowledge`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/entities/by-id` | Read the knowledge held about entities: the description people wrote for | | `BatchGetKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/pages/by-id` | Read knowledge pages by id: their content, where they sit in the tree, | | `ListKnowledgePageLinks`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages/{page_id}/links` | List what is pinned to a knowledge page, in either direction: the ids of | | `ListKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages` | List the ids of knowledge pages, ordered by name, optionally narrowed by a | | `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. | | `ListEntityTraitDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-traits/list` | List every trait a selection query can filter entities by. | | `ListEntityTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-types/list` | List every kind of entity in your workspace, the built-in types and your own. | | `ListExecutionTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/execution-types/list` | List every kind of run Coalesce Quality records against an entity. | | `ListPlatformDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/platforms/list` | List every platform Coalesce Quality connects to, with its display name. | ## 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... | | `CreateFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha` | Create a fold. Repeating the same request returns the fold it created; | | `DeleteFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/delete` | Delete a fold. Deleting a fold that does not exist succeeds. | | `RenameFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/rename` | Change the name shown on a fold's node. | | `SetFoldEnabled`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/enabled` | Switch a fold on or off. A fold switched off is kept and listed, and | | `UpdateFoldMatcher`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/matcher` | Change which entities a fold matches. The fold's node keeps its entity id. | ## 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. | | `BatchGetEntityUsage`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/usage` | Read how each asked entity is used over the window, in one line: what loads it, what runs and | | `GetActorSummary`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-summary` | Read what one actor read, built and wrote over the window, what its queries cost per compute and | | `ListEntityActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actors` | Read who read and wrote each asked entity over the window: the jobs, the service accounts, the | | `ListRelationships`
*synq.entities.custom.v1.RelationshipsService*
`POST /api/entities/custom/v1/relationships/list` | List relationships touching the given entities, or every relationship in | | `GetImpact`
*synq.entities.impact.v1.ImpactService*
`POST /api/impact/v1` | | | `BatchGetFoldNodes`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/nodes/batch-get` | Read fold nodes by entity id: which fold a node in a lineage response | | `BatchGetFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/batch-get` | Read folds by id. An id with no fold is absent from the response. | | `ListFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`GET /api/lineage/folds/v1alpha` | List the ids of every fold in the workspace, switched off ones included, | | `PreviewFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/preview` | Show what a matcher would fold, before it is saved: how many entities and | | `GetLineage`
*synq.entities.lineage.v1.LineageService*
`POST /api/lineage/v1` | | | `BatchOrchestration`
*synq.entities.orchestration.v1.OrchestrationService*
`GET /api/orchestration/v1` | BatchOrchestration returns, for each requested entity, the jobs, job steps and tasks that ran it | ## 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 | | - | - | | `BatchDeleteSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`DELETE /api/datachecks/sql-test-deployment-rules/v1/batch` | | | `BatchDeploySqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/batch/deployed` | | | `DeleteSqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`DELETE /api/datachecks/sql-test-deployment-rules/v1/{id}` | | | `DeploySqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/deployed` | Deploy (create or update) a SqlTestDeploymentRule and immediately sync tests | | `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. | | `BatchGetSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/by-id` | | | `GetSqlTestDeployDeleteOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/{id}/deleted` | Preview the effect of deleting a rule, without deleting it. | | `GetSqlTestDeployOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/overview` | Preview the effect of deploying a rule (which have not yet been saved), without | | `ListSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1` | | | `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 | | - | - | | `AddUserRole`
*synq.users.v1.UsersService*
`POST /api/users/v1/roles` | Grants a role to a user in the workspace. | | `DeleteUserAliases`
*synq.users.v1.UsersService*
`POST /api/users/v1/aliases/delete` | Removes aliases from users. | | `RemoveUserRole`
*synq.users.v1.UsersService*
`POST /api/users/v1/roles/remove` | Withdraws a role from a user in the workspace. | | `UpsertUserAliases`
*synq.users.v1.UsersService*
`PUT /api/users/v1/aliases` | Links aliases to users. | ## 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*
`POST /api/users/v1/batch-get` | | | `GetByAlias`
*synq.users.v1.UsersService*
`POST /api/users/v1/by-alias` | | | `GetByEmail`
*synq.users.v1.UsersService*
`GET /api/users/v1/by-email` | | | `GetUserAliases`
*synq.users.v1.UsersService*
`GET /api/users/v1/aliases` | | | `GetUserIdentities`
*synq.users.v1.UsersService*
`GET /api/users/v1/identities` | Returns all canonical identity strings for a user. | | `ListUsers`
*synq.users.v1.UsersService*
`GET /api/users/v1` | | ## 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` | | | `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 | | `ListMonitorSegments`
*synq.monitors.segments.v1.MonitorSegmentsService*
`GET /api/monitors/segments/v1` | Lists the segments a monitor has ingested so far, with their raw value and | ## 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` | | | `BatchUpdateMonitorSegmentLabels`
*synq.monitors.segments.v1.MonitorSegmentsService*
`POST /api/monitors/segments/v1/labels` | Sets or clears the label of one or more segments. | ## 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. | | `Create`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2` | Create a new alert configuration. | | `Delete`
*synq.alerts.services.v2.AlertsService*
`DELETE /api/alerts/v2` | Delete an existing alert configuration. | | `Rename`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/rename` | Rename an existing alert configuration. | | `SendTestAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/test` | Delivers a static test message to the given targets so you can confirm that | | `ToggleEnabled`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/toggle` | Enables or disables an existing alert configuration. | | `ToggleIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/incident-owner` | Turns the workspace's incident-owner alert on or off. This alert notifies | | `UpdateSettings`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/settings` | Update the trigger and/or the kind-specific settings of an alert. | | `UpdateTargets`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/targets` | Replace the delivery targets of an existing alert configuration. | | `UpdateTemplate`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/template` | Set or clear the message template of an existing alert configuration. | | `Upsert`
*synq.alerts.services.v2.AlertsService*
`PUT /api/alerts/v2` | Creates the alert when no alert holds `fqn`, otherwise replaces the stored | ## 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. | | `BatchGet`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/get` | Get multiple alert configurations by their identifiers. | | `GetIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`GET /api/alerts/v2/incident-owner` | Reports whether the workspace's incident-owner alert is on. This alert has | | `List`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/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 | | - | - | | `BatchGetEntityOverlays`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/by-id` | For each entity, list every overlay that claims it. | | `BatchGetOverlayMemberCounts`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/member-counts` | Count the members of each named overlay. | | `GetCoverageSummary`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage-summary` | Count coverage over one or more named candidate sets, without listing the | | `ListEntityCoverage`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage` | List the candidate assets together with the overlays claiming each, and | | `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 | | `BatchGetEntityOverlays`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/by-id` | For each entity, list every overlay that claims it. | | `BatchGetOverlayMemberCounts`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/member-counts` | Count the members of each named overlay. | | `GetCoverageSummary`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage-summary` | Count coverage over one or more named candidate sets, without listing the | | `ListEntityCoverage`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage` | List the candidate assets together with the overlays claiming each, and | ## 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. | ## Read Usage `SCOPE_USAGE_GET` View workspace usage and quota metrics. | Method | Description | | - | - | | `GetUsage`
*synq.domains.v1.DomainsService*
`GET /api/domains/v1/usage` | Report how many domains the workspace uses, split into top-level and sub-domains. | | `GetUsage`
*synq.domains.v2.DomainsService*
`GET /api/domains/v2/usage` | Report how many domains the workspace uses, split into top-level and sub-domains. | ## 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 | | `BatchGet`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/get` | Get multiple alert configurations by their identifiers. | | `GetIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`GET /api/alerts/v2/incident-owner` | Reports whether the workspace's incident-owner alert is on. This alert has | | `List`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/list` | Retrieves a list of alert configurations based on filters. | | `BatchGetSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/by-id` | | | `GetSqlTestDeployDeleteOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/{id}/deleted` | Preview the effect of deleting a rule, without deleting it. | | `GetSqlTestDeployOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/overview` | Preview the effect of deploying a rule (which have not yet been saved), without | | `ListSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1` | | | `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 | | `BatchGetEntityUsage`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/usage` | Read how each asked entity is used over the window, in one line: what loads it, what runs and | | `BatchGetPopularity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/popularity` | Read how popular each asked entity is over the window: its counted reads and writes per measure, | | `GetActivityOverview`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/overview` | Read a workspace's queries and their cost per group of logins, per platform, and its most read | | `GetActorSummary`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-summary` | Read what one actor read, built and wrote over the window, what its queries cost per compute and | | `GetEntityActivitySeries`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/series` | Read how access to one entity moves over the window: per direction, a point per UTC hour, a point | | `ListAccessSignals`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/signals` | List the entities of the workspace, or of a selection, that one signal names, such as the tables | | `ListActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-list` | List the workspace's actors, the service accounts, tools, people, logins nothing classifies and | | `ListEntityActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actors` | Read who read and wrote each asked entity over the window: the jobs, the service accounts, the | | `ListPersonActivity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/person` | Read what one person's logins read and wrote over the window, per entity, direction and measure. | | `BatchGetEntityAnnotations`
*synq.entities.annotations.v1.AnnotationsService*
`POST /api/entities/annotations/v1/batchGet` | Read the annotations carried by specific entities. | | `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. | | `BatchGetCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/batch-get` | Read the categories of specific checks. Ids that do not exist are omitted | | `ListCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/vocabulary` | List the workspace's category vocabulary: the category names in use on | | `ListCategorisationFilters`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/filters` | List the attribute values the workspace's checks actually have — the | | `ListCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/list` | List the workspace's checks with their resolved categories. Returns every | | `BatchGetRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/batch-get` | Read specific rules by id — typically to resolve the `rule_id` a | | `GetRecategorisationStatus`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/recategorisation-status` | Progress of the re-categorisation sweep a rule change schedules. The sweep | | `ListRuleMatches`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/matches` | Report how many checks each rule currently categorises, with a sample of | | `ListRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/list` | List the rules that apply to the caller's workspace — its own rules plus | | `PreviewRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/preview` | Report what a candidate rule would change, without saving it. | | `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. | | `ListCheckRelationships`
*synq.entities.custom.v1.ChecksRelationshipsService*
`POST /api/entities/custom/v1/check-relationships/list` | List every relationship that attaches a check to the entities it | | `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 the features of one entity, or of every custom entity in the | | `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` | List relationships touching the given entities, or every relationship in | | `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` | | | `BatchGetFoldNodes`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/nodes/batch-get` | Read fold nodes by entity id: which fold a node in a lineage response | | `BatchGetFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/batch-get` | Read folds by id. An id with no fold is absent from the response. | | `ListFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`GET /api/lineage/folds/v1alpha` | List the ids of every fold in the workspace, switched off ones included, | | `PreviewFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/preview` | Show what a matcher would fold, before it is saved: how many entities and | | `GetLineage`
*synq.entities.lineage.v1.LineageService*
`POST /api/lineage/v1` | | | `BatchOrchestration`
*synq.entities.orchestration.v1.OrchestrationService*
`GET /api/orchestration/v1` | BatchOrchestration returns, for each requested entity, the jobs, job steps and tasks that ran it | | `BatchGetPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/batch-get` | Read logins by platform user id. Ids no integration declared and with no activity in the window | | `ListLinkSuggestions`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/link-suggestions` | Suggest which workspace member each unclassified login may belong to, by matching the login | | `ListPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/list` | List the workspace's logins by their share of the workspace's activity, highest first. The first | | `BatchGetServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/batch-get` | Read service accounts by id, built-in ids included. Ids that do not exist are left out. | | `ListServiceAccountSuggestions`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/suggestions` | Suggest service accounts for the logins the evidence says are not a person, each as a change set | | `ListServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/list` | List every workspace service account, then every built-in one, in the order they apply, and the | | `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 for each of the requested entities, | | `ListJoinPatterns`
*synq.entities.sql\_insights.v1.SqlInsightsService*
`GET /api/sql-insights/v1/join-patterns` | ListJoinPatterns lists how other SQL joins a table, or one of its columns: | | `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` | | | `BatchGetEntityKnowledge`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/entities/by-id` | Read the knowledge held about entities: the description people wrote for | | `BatchGetKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/pages/by-id` | Read knowledge pages by id: their content, where they sit in the tree, | | `ListKnowledgePageLinks`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages/{page_id}/links` | List what is pinned to a knowledge page, in either direction: the ids of | | `ListKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages` | List the ids of knowledge pages, ordered by name, optionally narrowed by a | | `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}` | | | `History`
*synq.monitors.history.v1.HistoryService*
`GET /api/monitors/history/v1` | | | `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 | | `ListMonitorSegments`
*synq.monitors.segments.v1.MonitorSegmentsService*
`GET /api/monitors/segments/v1` | Lists the segments a monitor has ingested so far, with their raw value and | | `BatchGetEntityOverlays`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/by-id` | For each entity, list every overlay that claims it. | | `BatchGetOverlayMemberCounts`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/member-counts` | Count the members of each named overlay. | | `GetCoverageSummary`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage-summary` | Count coverage over one or more named candidate sets, without listing the | | `ListEntityCoverage`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage` | List the candidate assets together with the overlays claiming each, and | | `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*
`GET /api/users/v1/by-email` | | | `GetUserIdentities`
*synq.users.v1.UsersService*
`GET /api/users/v1/identities` | Returns all canonical identity strings for a user. | | `ListUsers`
*synq.users.v1.UsersService*
`GET /api/users/v1` | | ## MCP Write Access `SCOPE_MCP_WRITE` Use any write MCP (Model Context Protocol) tool, including tools added in the future. | Method | Description | | - | - | | `Create`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2` | Create a new alert configuration. | | `Delete`
*synq.alerts.services.v2.AlertsService*
`DELETE /api/alerts/v2` | Delete an existing alert configuration. | | `Rename`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/rename` | Rename an existing alert configuration. | | `SendTestAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/test` | Delivers a static test message to the given targets so you can confirm that | | `ToggleEnabled`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/toggle` | Enables or disables an existing alert configuration. | | `ToggleIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/incident-owner` | Turns the workspace's incident-owner alert on or off. This alert notifies | | `UpdateSettings`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/settings` | Update the trigger and/or the kind-specific settings of an alert. | | `UpdateTargets`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/targets` | Replace the delivery targets of an existing alert configuration. | | `Upsert`
*synq.alerts.services.v2.AlertsService*
`PUT /api/alerts/v2` | Creates the alert when no alert holds `fqn`, otherwise replaces the stored | | `DeleteSqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`DELETE /api/datachecks/sql-test-deployment-rules/v1/{id}` | | | `DeploySqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/deployed` | Deploy (create or update) a SqlTestDeploymentRule and immediately sync tests | | `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); | | `DeleteCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/delete` | Clear the explicit categories of one or more checks, on both dimensions. | | `UpsertCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories` | Set the category of one or more checks explicitly. An explicit category is | | `DeleteRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/delete` | Delete a categorisation rule. Checks the rule categorised fall back to the | | `UpsertRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules` | Create or update a categorisation rule. | | `ApplyServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/apply` | Write a planned change set, all of it or nothing. It is refused with FAILED\_PRECONDITION when the | | `PlanServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/plan` | Report what a change set would change, without writing it: every login slice whose | | `CreateIncident`
*synq.incidents.v1.IncidentsService*
`POST /api/incidents/v1` | | | `DeleteComment`
*synq.incidents.v1.IncidentsService*
`DELETE /api/incidents/v1/{incident_id}/comment/{comment_id}` | Delete a comment on an incident. Only the actor who posted the comment may | | `PostComment`
*synq.incidents.v1.IncidentsService*
`POST /api/incidents/v1/{incident_id}/comment` | Post a comment on an incident. | | `DeleteComment`
*synq.issues.v2.IssuesService*
`DELETE /api/issues/v2/{issue_id}/comment/{comment_id}` | Delete a comment on an issue. Only the actor who posted the comment may | | `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` | | | `BatchUpdateMonitorSegmentLabels`
*synq.monitors.segments.v1.MonitorSegmentsService*
`POST /api/monitors/segments/v1/labels` | Sets or clears the label of one or more segments. | | `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 | | `UpdateDeploymentCategories`
*synq.agent.recon.v1.SuiteDeploymentService* | Change the categories declared for a deployment's reconciliation checks | | `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 | | `BatchGetCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/batch-get` | Read the categories of specific checks. Ids that do not exist are omitted | | `DeleteCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/delete` | Clear the explicit categories of one or more checks, on both dimensions. | | `ListCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/vocabulary` | List the workspace's category vocabulary: the category names in use on | | `ListCategorisationFilters`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/filters` | List the attribute values the workspace's checks actually have — the | | `ListCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/list` | List the workspace's checks with their resolved categories. Returns every | | `UpsertCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories` | Set the category of one or more checks explicitly. An explicit category is | | `BatchGetRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/batch-get` | Read specific rules by id — typically to resolve the `rule_id` a | | `DeleteRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/delete` | Delete a categorisation rule. Checks the rule categorised fall back to the | | `GetRecategorisationStatus`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/recategorisation-status` | Progress of the re-categorisation sweep a rule change schedules. The sweep | | `ListRuleMatches`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/matches` | Report how many checks each rule currently categorises, with a sample of | | `ListRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/list` | List the rules that apply to the caller's workspace — its own rules plus | | `PreviewRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/preview` | Report what a candidate rule would change, without saving it. | | `UpsertRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules` | Create or update a categorisation rule. | ## 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 | | `BatchGetCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/batch-get` | Read the categories of specific checks. Ids that do not exist are omitted | | `ListCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/vocabulary` | List the workspace's category vocabulary: the category names in use on | | `ListCategorisationFilters`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/filters` | List the attribute values the workspace's checks actually have — the | | `ListCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/list` | List the workspace's checks with their resolved categories. Returns every | | `BatchGetRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/batch-get` | Read specific rules by id — typically to resolve the `rule_id` a | | `GetRecategorisationStatus`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/recategorisation-status` | Progress of the re-categorisation sweep a rule change schedules. The sweep | | `ListRuleMatches`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/matches` | Report how many checks each rule currently categorises, with a sample of | | `ListRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/list` | List the rules that apply to the caller's workspace — its own rules plus | | `PreviewRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/preview` | Report what a candidate rule would change, without saving it. | ## 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).* ## Read Deliveries `SCOPE_DELIVERY_READ` Inspect notifications sent to your integrations, including the requests made and the responses received. | Method | Description | | - | - | | `BatchGetDeliveries`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/by-id` | Fetch deliveries by id. Ids that do not exist, or have passed out of the | | `GetDelivery`
*synq.deliveries.v1.DeliveriesService* | Fetch a single delivery by id. `BatchGetDeliveries` does the same for many | | `ListAttempts`
*synq.deliveries.v1.DeliveriesService*
`GET /api/deliveries/v1/{delivery_id}/attempts` | List every attempt made for one delivery, oldest first. A delivery is | | `ListDeliveries`
*synq.deliveries.v1.DeliveriesService*
`GET /api/deliveries/v1` | List deliveries, newest event first. With no `integration_id` this is the | | `SummariseDeliveries`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/summarise` | Count deliveries over a window, bucketed by outcome, by skip reason and by | ## Send and Replay Deliveries `SCOPE_DELIVERY_EDIT` Send a test notification to an integration and replay an earlier delivery. | Method | Description | | - | - | | `Redeliver`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/{delivery_id}/redeliver` | Send an earlier delivery again, to the same integration, with the same | | `SendTestDelivery`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/test` | Send a test delivery to an integration, to confirm the endpoint is reachable | ## Read Recommendations `SCOPE_RECOMMENDATIONS_READ` View the changes Coalesce Quality recommends making in your workspace and the systems it connects to, and what was decided about them. | Method | Description | | - | - | | `BatchGetRecommendations`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/by-id` | Fetch recommendations by id. Ids that are unknown, belong to another | | `ListRecommendations`
*synq.recommendations.v1.RecommendationsService*
`GET /api/recommendations/v1` | List the ids of the workspace's recommendations, optionally limited by | ## Manage Recommendations `SCOPE_RECOMMENDATIONS_EDIT` Dismiss, ignore and restore recommendations. | Method | Description | | - | - | | `BatchGetRecommendations`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/by-id` | Fetch recommendations by id. Ids that are unknown, belong to another | | `DismissRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/dismiss` | Dismiss a recommendation until something new is found about it. Replaces | | `IgnoreRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/ignore` | Ignore a recommendation for good, whatever is found about it later. | | `ListRecommendations`
*synq.recommendations.v1.RecommendationsService*
`GET /api/recommendations/v1` | List the ids of the workspace's recommendations, optionally limited by | | `RestoreRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/restore` | Remove the dismissal or ignore standing against a recommendation, so it | ## Read Platform Users `SCOPE_PLATFORM_USERS_READ` View the logins on your connected platforms, such as warehouse users and service accounts, and what each platform states about them. | Method | Description | | - | - | | `GetActorSummary`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-summary` | Read what one actor read, built and wrote over the window, what its queries cost per compute and | | `ListEntityActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actors` | Read who read and wrote each asked entity over the window: the jobs, the service accounts, the | | `ListPersonActivity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/person` | Read what one person's logins read and wrote over the window, per entity, direction and measure. | | `BatchGetPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/batch-get` | Read logins by platform user id. Ids no integration declared and with no activity in the window | | `ListLinkSuggestions`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/link-suggestions` | Suggest which workspace member each unclassified login may belong to, by matching the login | | `ListPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/list` | List the workspace's logins by their share of the workspace's activity, highest first. The first | ## Link Platform Users `SCOPE_PLATFORM_USER_LINK` Link logins on your connected platforms to workspace members, so their reads count as that member's. | Method | Description | | - | - | | `DeleteUserAliases`
*synq.users.v1.UsersService*
`POST /api/users/v1/aliases/delete` | Removes aliases from users. | | `UpsertUserAliases`
*synq.users.v1.UsersService*
`PUT /api/users/v1/aliases` | Links aliases to users. | ## Read Service Accounts `SCOPE_SERVICE_ACCOUNTS_READ` View service accounts, person links, popularity policies and suggested service accounts. | Method | Description | | - | - | | `BatchGetServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/batch-get` | Read service accounts by id, built-in ids included. Ids that do not exist are left out. | | `ListServiceAccountSuggestions`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/suggestions` | Suggest service accounts for the logins the evidence says are not a person, each as a change set | | `ListServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/list` | List every workspace service account, then every built-in one, in the order they apply, and the | ## Manage Service Accounts `SCOPE_SERVICE_ACCOUNTS_EDIT` Create and change service accounts, person links and popularity policies. | Method | Description | | - | - | | `ApplyServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/apply` | Write a planned change set, all of it or nothing. It is refused with FAILED\_PRECONDITION when the | | `BatchGetServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/batch-get` | Read service accounts by id, built-in ids included. Ids that do not exist are left out. | | `ListServiceAccountSuggestions`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/suggestions` | Suggest service accounts for the logins the evidence says are not a person, each as a change set | | `ListServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/list` | List every workspace service account, then every built-in one, in the order they apply, and the | | `PlanServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/plan` | Report what a change set would change, without writing it: every login slice whose | ## 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` | | `UpdateDeploymentCategories`
*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` | — | | `ValidateSuite`
*synq.agent.recon.v1.YamlService*
`POST /api/agent/recon/v1/yaml/validate` | — | | `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` | | `BatchGet`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/get` | `SCOPE_ALERTS_READ`
`SCOPE_MCP_READ` | | `Create`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `Delete`
*synq.alerts.services.v2.AlertsService*
`DELETE /api/alerts/v2` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `GetIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`GET /api/alerts/v2/incident-owner` | `SCOPE_ALERTS_READ`
`SCOPE_MCP_READ` | | `List`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/list` | `SCOPE_ALERTS_READ`
`SCOPE_MCP_READ` | | `Rename`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/rename` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `SendTestAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/test` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `ToggleEnabled`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/toggle` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `ToggleIncidentOwnerAlert`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/incident-owner` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `UpdateSettings`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/settings` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `UpdateTargets`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/targets` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `UpdateTemplate`
*synq.alerts.services.v2.AlertsService*
`POST /api/alerts/v2/template` | `SCOPE_ALERTS_EDIT` | | `Upsert`
*synq.alerts.services.v2.AlertsService*
`PUT /api/alerts/v2` | `SCOPE_ALERTS_EDIT`
`SCOPE_MCP_WRITE` | | `Iam`
*synq.auth.iam.v1.IamService*
`GET /api/iam/v1` | — | | `BatchDeleteSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`DELETE /api/datachecks/sql-test-deployment-rules/v1/batch` | `SCOPE_DATACHECKS_SQLTESTS_EDIT` | | `BatchDeploySqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/batch/deployed` | `SCOPE_DATACHECKS_SQLTESTS_EDIT` | | `BatchGetSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/by-id` | `SCOPE_DATACHECKS_SQLTESTS_READ`
`SCOPE_MCP_READ` | | `DeleteSqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`DELETE /api/datachecks/sql-test-deployment-rules/v1/{id}` | `SCOPE_DATACHECKS_SQLTESTS_EDIT`
`SCOPE_MCP_WRITE` | | `DeploySqlTestDeploymentRule`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`POST /api/datachecks/sql-test-deployment-rules/v1/deployed` | `SCOPE_DATACHECKS_SQLTESTS_EDIT`
`SCOPE_MCP_WRITE` | | `GetSqlTestDeployDeleteOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/{id}/deleted` | `SCOPE_DATACHECKS_SQLTESTS_READ`
`SCOPE_MCP_READ` | | `GetSqlTestDeployOverview`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1/overview` | `SCOPE_DATACHECKS_SQLTESTS_READ`
`SCOPE_MCP_READ` | | `ListSqlTestDeploymentRules`
*synq.datachecks.sqltests.v1.SqlTestsDeploymentRulesService*
`GET /api/datachecks/sql-test-deployment-rules/v1` | `SCOPE_DATACHECKS_SQLTESTS_READ`
`SCOPE_MCP_READ` | | `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` | | `BatchGetDeliveries`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/by-id` | `SCOPE_DELIVERY_READ` | | `GetDelivery`
*synq.deliveries.v1.DeliveriesService* | `SCOPE_DELIVERY_READ` | | `ListAttempts`
*synq.deliveries.v1.DeliveriesService*
`GET /api/deliveries/v1/{delivery_id}/attempts` | `SCOPE_DELIVERY_READ` | | `ListDeliveries`
*synq.deliveries.v1.DeliveriesService*
`GET /api/deliveries/v1` | `SCOPE_DELIVERY_READ` | | `Redeliver`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/{delivery_id}/redeliver` | `SCOPE_DELIVERY_EDIT` | | `SendTestDelivery`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/test` | `SCOPE_DELIVERY_EDIT` | | `SummariseDeliveries`
*synq.deliveries.v1.DeliveriesService*
`POST /api/deliveries/v1/summarise` | `SCOPE_DELIVERY_READ` | | `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` | | `GetUsage`
*synq.domains.v1.DomainsService*
`GET /api/domains/v1/usage` | `SCOPE_USAGE_GET` | | `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` | | `GetUsage`
*synq.domains.v2.DomainsService*
`GET /api/domains/v2/usage` | `SCOPE_USAGE_GET` | | `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` | | `BatchGetEntityUsage`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/usage` | `SCOPE_ENTITY_READ`
`SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `BatchGetPopularity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/popularity` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `GetActivityOverview`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/overview` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `GetActorSummary`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-summary` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `GetEntityActivitySeries`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/series` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `ListAccessSignals`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/signals` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `ListActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actor-list` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `ListEntityActors`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/actors` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `ListPersonActivity`
*synq.entities.activity.v1alpha.ActivityService*
`POST /api/entities/activity/v1alpha/person` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_MCP_READ` | | `BatchGetEntityAnnotations`
*synq.entities.annotations.v1.AnnotationsService*
`POST /api/entities/annotations/v1/batchGet` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `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` | | `BatchGetCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/batch-get` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `DeleteCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/delete` | `SCOPE_POLICIES_EDIT`
`SCOPE_MCP_WRITE` | | `ListCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/vocabulary` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `ListCategorisationFilters`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/filters` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `ListCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories/list` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `UpsertCheckCategories`
*synq.entities.checks.v2.ChecksCategoriesService*
`POST /api/entities/v2/checks/categories` | `SCOPE_POLICIES_EDIT`
`SCOPE_MCP_WRITE` | | `BatchGetRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/batch-get` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `DeleteRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/delete` | `SCOPE_POLICIES_EDIT`
`SCOPE_MCP_WRITE` | | `GetRecategorisationStatus`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/recategorisation-status` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `ListRuleMatches`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/matches` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `ListRules`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/list` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `PreviewRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules/preview` | `SCOPE_POLICIES_READ`
`SCOPE_POLICIES_EDIT`
`SCOPE_MCP_READ` | | `UpsertRule`
*synq.entities.checks.v2.ChecksCategorisationRulesService*
`POST /api/entities/v2/checks/categorisation-rules` | `SCOPE_POLICIES_EDIT`
`SCOPE_MCP_WRITE` | | `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` | | `ListCheckRelationships`
*synq.entities.custom.v1.ChecksRelationshipsService*
`POST /api/entities/custom/v1/check-relationships/list` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `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` | | `BatchGetFoldNodes`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/nodes/batch-get` | `SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `BatchGetFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/batch-get` | `SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `CreateFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha` | `SCOPE_LINEAGE_EDIT` | | `DeleteFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/delete` | `SCOPE_LINEAGE_EDIT` | | `ListFolds`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`GET /api/lineage/folds/v1alpha` | `SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `PreviewFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/preview` | `SCOPE_LINEAGE_READ`
`SCOPE_MCP_READ` | | `RenameFold`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/rename` | `SCOPE_LINEAGE_EDIT` | | `SetFoldEnabled`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/enabled` | `SCOPE_LINEAGE_EDIT` | | `UpdateFoldMatcher`
*synq.entities.lineage.folds.v1alpha.LineageFoldsService*
`POST /api/lineage/folds/v1alpha/{id}/matcher` | `SCOPE_LINEAGE_EDIT` | | `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` | | `BatchGetPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/batch-get` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_MCP_READ` | | `ListLinkSuggestions`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/link-suggestions` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_MCP_READ` | | `ListPlatformUsers`
*synq.entities.platformusers.v1alpha.PlatformUsersService*
`POST /api/entities/platform-users/v1alpha/list` | `SCOPE_PLATFORM_USERS_READ`
`SCOPE_MCP_READ` | | `ApplyServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/apply` | `SCOPE_SERVICE_ACCOUNTS_EDIT`
`SCOPE_MCP_WRITE` | | `BatchGetServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/batch-get` | `SCOPE_SERVICE_ACCOUNTS_READ`
`SCOPE_SERVICE_ACCOUNTS_EDIT`
`SCOPE_MCP_READ` | | `ListServiceAccountSuggestions`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/suggestions` | `SCOPE_SERVICE_ACCOUNTS_READ`
`SCOPE_SERVICE_ACCOUNTS_EDIT`
`SCOPE_MCP_READ` | | `ListServiceAccounts`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/list` | `SCOPE_SERVICE_ACCOUNTS_READ`
`SCOPE_SERVICE_ACCOUNTS_EDIT`
`SCOPE_MCP_READ` | | `PlanServiceAccountChanges`
*synq.entities.platformusers.v1alpha.ServiceAccountsService*
`POST /api/entities/service-accounts/v1alpha/plan` | `SCOPE_SERVICE_ACCOUNTS_EDIT`
`SCOPE_MCP_WRITE` | | `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` | | `ListJoinPatterns`
*synq.entities.sql\_insights.v1.SqlInsightsService*
`GET /api/sql-insights/v1/join-patterns` | `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` | | `ListEntityTraitDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-traits/list` | `SCOPE_ENTITY_READ`
`SCOPE_ENTITY_TYPE_READ` | | `ListEntityTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/entity-types/list` | `SCOPE_ENTITY_READ`
`SCOPE_ENTITY_TYPE_READ` | | `ListExecutionTypeDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/execution-types/list` | `SCOPE_ENTITY_READ`
`SCOPE_ENTITY_TYPE_READ` | | `ListPlatformDefs`
*synq.entities.typedefs.v1.TypeDefsService*
`POST /api/entities/typedefs/v1/platforms/list` | `SCOPE_ENTITY_READ`
`SCOPE_ENTITY_TYPE_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` | | `DeleteComment`
*synq.incidents.v1.IncidentsService*
`DELETE /api/incidents/v1/{incident_id}/comment/{comment_id}` | `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` | | `DeleteComment`
*synq.issues.v2.IssuesService*
`DELETE /api/issues/v2/{issue_id}/comment/{comment_id}` | `SCOPE_ISSUES_EDIT`
`SCOPE_MCP_WRITE` | | `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` | | `BatchGetEntityKnowledge`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/entities/by-id` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `BatchGetKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`POST /api/knowledge/v1alpha/pages/by-id` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `ListKnowledgePageLinks`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages/{page_id}/links` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `ListKnowledgePages`
*synq.knowledge.v1alpha.KnowledgeService*
`GET /api/knowledge/v1alpha/pages` | `SCOPE_ENTITY_READ`
`SCOPE_MCP_READ` | | `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`
`SCOPE_MCP_READ` | | `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` | `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` | | `BatchUpdateMonitorSegmentLabels`
*synq.monitors.segments.v1.MonitorSegmentsService*
`POST /api/monitors/segments/v1/labels` | `SCOPE_MONITORS_CUSTOM_EDIT`
`SCOPE_MCP_WRITE` | | `ListMonitorSegments`
*synq.monitors.segments.v1.MonitorSegmentsService*
`GET /api/monitors/segments/v1` | `SCOPE_MONITORS_READ`
`SCOPE_MCP_READ` | | `BatchGetEntityOverlays`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/by-id` | `SCOPE_OWNERS_READ`
`SCOPE_DATAPRODUCT_READ`
`SCOPE_MCP_READ` | | `BatchGetOverlayMemberCounts`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/member-counts` | `SCOPE_OWNERS_READ`
`SCOPE_DATAPRODUCT_READ`
`SCOPE_MCP_READ` | | `GetCoverageSummary`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage-summary` | `SCOPE_OWNERS_READ`
`SCOPE_DATAPRODUCT_READ`
`SCOPE_MCP_READ` | | `ListEntityCoverage`
*synq.overlays.v1.OverlaysService*
`POST /api/overlays/v1/coverage` | `SCOPE_OWNERS_READ`
`SCOPE_DATAPRODUCT_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` | | `DescribeResolverQl`
*synq.queries.v1.QueriesService*
`POST /api/queries/v1/describe-resolver-ql` | — | | `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` | | `BatchGetRecommendations`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/by-id` | `SCOPE_RECOMMENDATIONS_READ`
`SCOPE_RECOMMENDATIONS_EDIT` | | `DismissRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/dismiss` | `SCOPE_RECOMMENDATIONS_EDIT` | | `IgnoreRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/ignore` | `SCOPE_RECOMMENDATIONS_EDIT` | | `ListRecommendations`
*synq.recommendations.v1.RecommendationsService*
`GET /api/recommendations/v1` | `SCOPE_RECOMMENDATIONS_READ`
`SCOPE_RECOMMENDATIONS_EDIT` | | `RestoreRecommendation`
*synq.recommendations.v1.RecommendationsService*
`POST /api/recommendations/v1/{recommendation_id}/restore` | `SCOPE_RECOMMENDATIONS_EDIT` | | `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` | — | | `AddUserRole`
*synq.users.v1.UsersService*
`POST /api/users/v1/roles` | `SCOPE_USER_EDIT` | | `BatchGetUsers`
*synq.users.v1.UsersService*
`POST /api/users/v1/batch-get` | `SCOPE_USER_READ` | | `DeleteUserAliases`
*synq.users.v1.UsersService*
`POST /api/users/v1/aliases/delete` | `SCOPE_USER_EDIT`
`SCOPE_PLATFORM_USER_LINK` | | `GetByAlias`
*synq.users.v1.UsersService*
`POST /api/users/v1/by-alias` | `SCOPE_USER_READ` | | `GetByEmail`
*synq.users.v1.UsersService*
`GET /api/users/v1/by-email` | `SCOPE_USER_READ`
`SCOPE_MCP_READ` | | `GetUserAliases`
*synq.users.v1.UsersService*
`GET /api/users/v1/aliases` | `SCOPE_USER_READ` | | `GetUserIdentities`
*synq.users.v1.UsersService*
`GET /api/users/v1/identities` | `SCOPE_USER_READ`
`SCOPE_MCP_READ` | | `ListUsers`
*synq.users.v1.UsersService*
`GET /api/users/v1` | `SCOPE_USER_READ`
`SCOPE_MCP_READ` | | `RemoveUserRole`
*synq.users.v1.UsersService*
`POST /api/users/v1/roles/remove` | `SCOPE_USER_EDIT` | | `UpsertUserAliases`
*synq.users.v1.UsersService*
`PUT /api/users/v1/aliases` | `SCOPE_USER_EDIT`
`SCOPE_PLATFORM_USER_LINK` | # 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). ParseYaml refuses two types of suite with INVALID_ARGUMENT and a SuiteValidationFailure detail: - A suite with `setup_file` or `teardown_file`. These fields refer to files that the server cannot read. - A suite with `reporting.level: detailed`. To find all other problems in a suite, use ValidateSuite. # 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. # ValidateSuite Source: https://docs.synq.io/api-reference/synqagentreconv1yamlservice/validatesuite /api-reference/openapi.yaml post /api/agent/recon/v1/yaml/validate ValidateSuite checks a suite and gives all the problems that it finds. Each problem has the path of its field. ValidateSuite does not save the suite, so an editor can call it after each change. ValidateSuite does the same checks as `synq-recon check-config` without `--db`. It also does the checks that apply only to suites that run in Coalesce Quality. ValidateSuite does not connect to a warehouse. Thus it does not find a query that refers to a table that does not exist. ValidateSuite does not compare the connection names with the integrations of the workspace. A suite gets its integrations when it runs or when you promote it. # 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. # BatchGet Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/batchget /api-reference/openapi.yaml post /api/alerts/v2/get Get multiple alert configurations by their identifiers. # Create Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/create /api-reference/openapi.yaml post /api/alerts/v2 Create a new alert configuration. # Delete Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/delete /api-reference/openapi.yaml delete /api/alerts/v2 Delete an existing alert configuration. The config can be identified by either ID or FQN. # GetIncidentOwnerAlert Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/getincidentowneralert /api-reference/openapi.yaml get /api/alerts/v2/incident-owner Reports whether the workspace's incident-owner alert is on. This alert has no other configuration and does not appear in List or BatchGet; turn it on or off with ToggleIncidentOwnerAlert. # List Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/list /api-reference/openapi.yaml post /api/alerts/v2/list Retrieves a list of alert configurations based on filters. # Rename Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/rename /api-reference/openapi.yaml post /api/alerts/v2/rename Rename an existing alert configuration. The config can be identified by either ID or FQN. # SendTestAlert Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/sendtestalert /api-reference/openapi.yaml post /api/alerts/v2/test Delivers a static test message to the given targets so you can confirm that delivery reaches each channel before relying on a real alert. Nothing is stored and the targets need not belong to a saved alert, so this can be called while an alert is still being authored. # ToggleEnabled Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/toggleenabled /api-reference/openapi.yaml post /api/alerts/v2/toggle Enables or disables an existing alert configuration. The config can be identified by either ID or FQN. # ToggleIncidentOwnerAlert Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/toggleincidentowneralert /api-reference/openapi.yaml post /api/alerts/v2/incident-owner Turns the workspace's incident-owner alert on or off. This alert notifies each incident's owner on its configured channels and has no other configuration, so it is managed here rather than through Create / Delete and does not appear in List or BatchGet. Read its current state with GetIncidentOwnerAlert. # UpdateSettings Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/updatesettings /api-reference/openapi.yaml post /api/alerts/v2/settings Update the trigger and/or the kind-specific settings of an alert. The config can be identified by either ID or FQN. # UpdateTargets Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/updatetargets /api-reference/openapi.yaml post /api/alerts/v2/targets Replace the delivery targets of an existing alert configuration. The config can be identified by either ID or FQN. # UpdateTemplate Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/updatetemplate /api-reference/openapi.yaml post /api/alerts/v2/template Set or clear the message template of an existing alert configuration. The config can be identified by either ID or FQN. # Upsert Source: https://docs.synq.io/api-reference/synqalertsservicesv2alertsservice/upsert /api-reference/openapi.yaml put /api/alerts/v2 Creates the alert when no alert holds `fqn`, otherwise replaces the stored alert with the state given here in a single write. Use it to make a stored alert match a declared state, e.g. when deploying alerts from configuration as code. See UpsertRequest for which fields cannot change. # Iam Source: https://docs.synq.io/api-reference/synqauthiamv1iamservice/iam /api-reference/openapi.yaml get /api/iam/v1 Iam returns information about caller authentication # BatchDeleteSqlTestDeploymentRules Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchdeletesqltestdeploymentrules /api-reference/openapi.yaml delete /api/datachecks/sql-test-deployment-rules/v1/batch # BatchDeploySqlTestDeploymentRules Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchdeploysqltestdeploymentrules /api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/batch/deployed # BatchGetSqlTestDeploymentRules Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/batchgetsqltestdeploymentrules /api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/by-id # DeleteSqlTestDeploymentRule Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/deletesqltestdeploymentrule /api-reference/openapi.yaml delete /api/datachecks/sql-test-deployment-rules/v1/{id} # DeploySqlTestDeploymentRule Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/deploysqltestdeploymentrule /api-reference/openapi.yaml post /api/datachecks/sql-test-deployment-rules/v1/deployed Deploy (create or update) a SqlTestDeploymentRule and immediately sync tests onto its current match set. # GetSqlTestDeployDeleteOverview Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/getsqltestdeploydeleteoverview /api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1/{id}/deleted Preview the effect of deleting a rule, without deleting it. # GetSqlTestDeployOverview Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/getsqltestdeployoverview /api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1/overview Preview the effect of deploying a rule (which have not yet been saved), without deploying it. # ListSqlTestDeploymentRules Source: https://docs.synq.io/api-reference/synqdatacheckssqltestsv1sqltestsdeploymentrulesservice/listsqltestdeploymentrules /api-reference/openapi.yaml get /api/datachecks/sql-test-deployment-rules/v1 # 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). # BatchGetDeliveries Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/batchgetdeliveries /api-reference/openapi.yaml post /api/deliveries/v1/by-id Fetch deliveries by id. Ids that do not exist, or have passed out of the retention window, are omitted from the response rather than causing an error. Unlike `ListDeliveries`, this always returns the routing provenance. # ListAttempts Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/listattempts /api-reference/openapi.yaml get /api/deliveries/v1/{delivery_id}/attempts List every attempt made for one delivery, oldest first. A delivery is attempted at most ten times, so the result is small and is not paginated. # ListDeliveries Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/listdeliveries /api-reference/openapi.yaml get /api/deliveries/v1 List deliveries, newest event first. With no `integration_id` this is the whole workspace's feed; with one it is that integration's. # Redeliver Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/redeliver /api-reference/openapi.yaml post /api/deliveries/v1/{delivery_id}/redeliver Send an earlier delivery again, to the same integration, with the same event. The replay is a new delivery with its own id, linked to the original through `redelivery_of`, and appears in `ListDeliveries` like any other. It is signed with the integration's current secret rather than the one the original used, which makes it the way to confirm that a rotated secret is accepted by the receiver. Retrying this call sends the delivery again. Rate-limited per integration; over the limit it fails with `RESOURCE_EXHAUSTED` rather than queueing. # SendTestDelivery Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/sendtestdelivery /api-reference/openapi.yaml post /api/deliveries/v1/test Send a test delivery to an integration, to confirm the endpoint is reachable and that it accepts what is sent. It is always sent, whatever event types the integration subscribes to — a test that silently matches nothing would report the same as a broken endpoint. Returns the id of the delivery it created. The send is asynchronous: poll `BatchGetDeliveries` with that id until the outcome leaves `OUTCOME_PENDING`. Retrying this call sends another test. Rate-limited per integration; over the limit it fails with `RESOURCE_EXHAUSTED` rather than queueing. # SummariseDeliveries Source: https://docs.synq.io/api-reference/synqdeliveriesv1deliveriesservice/summarisedeliveries /api-reference/openapi.yaml post /api/deliveries/v1/summarise Count deliveries over a window, bucketed by outcome, by skip reason and by HTTP status class. Use it to watch your own delivery failure rate without paging through the feed. # 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 Report how many domains the workspace uses, split into top-level and sub-domains. # 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 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). # BatchGetEntityUsage Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/batchgetentityusage /api-reference/openapi.yaml post /api/entities/activity/v1alpha/usage Read how each asked entity is used over the window, in one line: what loads it, what runs and builds it, what else writes it, and who reads it, such as "loaded by Fivetran, orchestrated by Airflow, transformed by dbt, read by Looker Studio, 3 people and 12 logins". Each role names its actor at the most precise level known: a job or app, else a service account, else the tool. It answers "what runs this" for a table or a model, and GetActorSummary answers "what this job runs". It names tools, jobs and service accounts, never a login. # BatchGetPopularity Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/batchgetpopularity /api-reference/openapi.yaml post /api/entities/activity/v1alpha/popularity Read how popular each asked entity is over the window: its counted reads and writes per measure, and its rank in each pool it has reads in. An entity is answered with the entities it is the same as, such as a dbt model and the table it builds. Every asked id has an answer, an empty one when nothing counted. # GetActivityOverview Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/getactivityoverview /api-reference/openapi.yaml post /api/entities/activity/v1alpha/overview Read a workspace's queries and their cost per group of logins, per platform, and its most read entities. It names groups and entities, never a login or a person. # GetActorSummary Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/getactorsummary /api-reference/openapi.yaml post /api/entities/activity/v1alpha/actor-summary Read what one actor read, built and wrote over the window, what its queries cost per compute and platform, and when it works. The actor is asked for by name, so nothing is left out for being Coalesce Quality's own access, a writer's own read or a policy. What a person did is personal data: a person, or a login, is answered only to that person, or to a caller holding the platform users scope, which a Developer and an Admin have. Anyone else gets PERMISSION_DENIED. A job, a service account, a tool and Coalesce Quality are answered to every caller, and without the platform users scope the answer names no login. # GetEntityActivitySeries Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/getentityactivityseries /api-reference/openapi.yaml post /api/entities/activity/v1alpha/series Read how access to one entity moves over the window: per direction, a point per UTC hour, a point per day in the asked time zone, and a weekday and hour grid. A direction's total is the sum of its actors in ListEntityActors under the same lens. It names tools, never a login. # ListAccessSignals Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/listaccesssignals /api-reference/openapi.yaml post /api/entities/activity/v1alpha/signals List the entities of the workspace, or of a selection, that one signal names, such as the tables a pipeline builds and nobody reads, or the tables nobody touched. A signal is computed from the window's access on each call, so a service account change shows on the next one. It names entities and tools, never a login. # ListActors Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/listactors /api-reference/openapi.yaml post /api/entities/activity/v1alpha/actor-list List the workspace's actors, the service accounts, tools, people, logins nothing classifies and Coalesce Quality, each with the totals GetActorSummary has for it: its queries and their weights, its reads, inputs and writes, and the entities it read and wrote. A login can be in several actors, such as its service account and the tool that issued its queries, so the actors never add up to the workspace: GetActivityOverview is the split that does. Only a caller holding the platform users scope sees people and logins: any other gets the rest with people_hidden set. # ListEntityActors Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/listentityactors /api-reference/openapi.yaml post /api/entities/activity/v1alpha/actors Read who read and wrote each asked entity over the window: the jobs, the service accounts, the tools and the logins. Anyone who reads lineage, and the reliability agent, is served. Only a caller holding the platform users scope sees the logins: any other gets every logins list empty and logins_hidden set. # ListPersonActivity Source: https://docs.synq.io/api-reference/synqentitiesactivityv1alphaactivityservice/listpersonactivity /api-reference/openapi.yaml post /api/entities/activity/v1alpha/person Read what one person's logins read and wrote over the window, per entity, direction and measure. What a colleague read is personal data, so a user caller needs the platform users scope from its role, which a Developer and an Admin have. Logins in a service account, and Coalesce Quality's own queries, are never part of the answer. # BatchGetEntityAnnotations Source: https://docs.synq.io/api-reference/synqentitiesannotationsv1annotationsservice/batchgetentityannotations /api-reference/openapi.yaml post /api/entities/annotations/v1/batchGet Read the annotations carried by specific entities. ListAnnotations answers what the workspace annotates by and how often; this answers what one entity carries. They are separate reads because an entity's annotations are not part of the entity: `synq.entities.v1.Entity` is the shape `synq.entities.custom.v1.UpsertEntity` accepts, so the `annotations` field on it is what a producer ASSERTS about an entity, and answering a read with it would make a read-edit-write round trip write one entity's annotations onto another. # 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". # BatchGetCheckCategories Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/batchgetcheckcategories /api-reference/openapi.yaml post /api/entities/v2/checks/categories/batch-get Read the categories of specific checks. Ids that do not exist are omitted from the response rather than causing an error, so a partially-stale list of ids still returns what it can. # DeleteCheckCategories Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/deletecheckcategories /api-reference/openapi.yaml post /api/entities/v2/checks/categories/delete Clear the explicit categories of one or more checks, on both dimensions. Each check falls back to its producer-declared or rule-computed category. Idempotent — clearing a check that has no explicit category succeeds. # ListCategories Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/listcategories /api-reference/openapi.yaml post /api/entities/v2/checks/categories/vocabulary List the workspace's category vocabulary: the category names in use on each dimension, whether a workspace or platform rule produces each one, and how many checks carry it. Use it to populate a category picker so a workspace converges on one spelling per concept, and to see how much of the workspace is still uncategorised. # ListCategorisationFilters Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/listcategorisationfilters /api-reference/openapi.yaml post /api/entities/v2/checks/categories/filters List the attribute values the workspace's checks actually have — the platforms, entity types, packages and kinds available to build a categorisation rule or a listing filter from. Pass `selected` to narrow each list to values that co-occur with the current selection, so a rule editor never offers a combination that matches nothing. A list never constrains itself: choosing one platform still leaves every other platform selectable. # ListCheckCategories Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/listcheckcategories /api-reference/openapi.yaml post /api/entities/v2/checks/categories/list List the workspace's checks with their resolved categories. Returns every check by default; the filters combine, so one call answers questions like "which dbt tests still have no governance category" or "which checks did this rule categorise". # UpsertCheckCategories Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategoriesservice/upsertcheckcategories /api-reference/openapi.yaml post /api/entities/v2/checks/categories Set the category of one or more checks explicitly. An explicit category is authoritative for its check: it overrides both the producer-declared category and anything the categorisation rules compute, and it survives every later rule change. Each dimension updates independently. A field that is omitted leaves that dimension as it is; a field set to the empty string clears the explicit category on that dimension, so the check falls back to its producer-declared or rule-computed value. Repeating the same request converges to the same state rather than accumulating changes. # BatchGetRules Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/batchgetrules /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/batch-get Read specific rules by id — typically to resolve the `rule_id` a ResolvedCategory carries into the rule that produced it. Ids the caller cannot see, or that do not exist, are omitted from the response rather than causing an error. # DeleteRule Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/deleterule /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/delete Delete a categorisation rule. Checks the rule categorised fall back to the next rule that matches them, or become uncategorised. Idempotent — deleting an already-deleted or unknown rule succeeds. Pass `etag` to guard against deleting a concurrently-edited rule. # GetRecategorisationStatus Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/getrecategorisationstatus /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/recategorisation-status Progress of the re-categorisation sweep a rule change schedules. The sweep normally completes in seconds, so this is how to confirm that the workspace's existing checks have caught up with the new rules — not something a client has to wait on. # ListRuleMatches Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/listrulematches /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/matches Report how many checks each rule currently categorises, with a sample of them — the state already applied, not a projection. Use it to show "categorises N checks" next to each rule, and to spot a rule that has stopped matching anything. For the full, paginated list of one rule's checks, call ChecksCategoriesService.ListCheckCategories with the rule id. # ListRules Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/listrules /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/list List the rules that apply to the caller's workspace — its own rules plus the platform-provided ones — in the order they are tried. Narrow with `dimension` and `scope`. # PreviewRule Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/previewrule /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules/preview Report what a candidate rule would change, without saving it. The candidate is slotted into the workspace's live rule set — replacing an existing rule when `id` names one — and the whole resolution is run over every check, so scope, priority, explicit categories and producer-declared categories are all honoured. The response separates the candidate's raw reach from its real effect, which are rarely the same number. Preview a rule before saving it: one that matches broadly can recategorise a large part of a workspace in a single sweep. # UpsertRule Source: https://docs.synq.io/api-reference/synqentitieschecksv2checkscategorisationrulesservice/upsertrule /api-reference/openapi.yaml post /api/entities/v2/checks/categorisation-rules Create or update a categorisation rule. The rule id is supplied by the caller (a UUID), which makes this operation idempotent — repeating the same request converges to the same rule rather than creating a duplicate. On create, `dimension`, `title`, `category` and `matcher` are required. On update, a field that is set is written and a field that is omitted is left unchanged. To guard against overwriting a concurrent edit, pass the `etag` you last read. Saving a rule schedules a sweep that recategorises the workspace's existing checks. It normally completes in seconds; GetRecategorisationStatus confirms it. # 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. The response says which of them actually removed something. # ListCheckRelationships Source: https://docs.synq.io/api-reference/synqentitiescustomv1checksrelationshipsservice/listcheckrelationships /api-reference/openapi.yaml post /api/entities/custom/v1/check-relationships/list List every relationship that attaches a check to the entities it validates, across the whole workspace. # 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. The response reports what each requested relationship did, and under which (check, checked) pair of entities it was stored. # 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 the features of one entity, or of every custom entity in the workspace when entity_id is left unset. # 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. The response says which of them actually removed something, so a caller reconciling a set of edges can tell a withdrawal from a no-op. # ListRelationships Source: https://docs.synq.io/api-reference/synqentitiescustomv1relationshipsservice/listrelationships /api-reference/openapi.yaml post /api/entities/custom/v1/relationships/list List relationships touching the given entities, or every relationship in the workspace when ids is left empty. # 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. The response reports what each requested relationship did to the stored graph, and under which pair of entities it was stored. Read it: a relationship whose endpoints resolve to a pair another relationship in the same batch also resolves to is one edge, and only the last write to it survives. # 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 # BatchGetFoldNodes Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/batchgetfoldnodes /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/nodes/batch-get Read fold nodes by entity id: which fold a node in a lineage response stands for, and which entities it showed. An id is answered for as long as lineage may still return it; an id with nothing to answer is absent from the response. # BatchGetFolds Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/batchgetfolds /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/batch-get Read folds by id. An id with no fold is absent from the response. # CreateFold Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/createfold /api-reference/openapi.yaml post /api/lineage/folds/v1alpha Create a fold. Repeating the same request returns the fold it created; creating a different fold under an id already in use is refused with ALREADY_EXISTS. # DeleteFold Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/deletefold /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/delete Delete a fold. Deleting a fold that does not exist succeeds. # ListFolds Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/listfolds /api-reference/openapi.yaml get /api/lineage/folds/v1alpha List the ids of every fold in the workspace, switched off ones included, oldest first. Read the folds with `BatchGetFolds`. # PreviewFold Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/previewfold /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/preview Show what a matcher would fold, before it is saved: how many entities and lineage edges it matches, a sample of them, and the entities that stop being shown on the same node as a folded one. Answered from the lineage the workspace has now, without any fold applied. # RenameFold Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/renamefold /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/rename Change the name shown on a fold's node. # SetFoldEnabled Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/setfoldenabled /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/enabled Switch a fold on or off. A fold switched off is kept and listed, and lineage shows the entities it matched as their own nodes again. # UpdateFoldMatcher Source: https://docs.synq.io/api-reference/synqentitieslineagefoldsv1alphalineagefoldsservice/updatefoldmatcher /api-reference/openapi.yaml post /api/lineage/folds/v1alpha/{id}/matcher Change which entities a fold matches. The fold's node keeps its entity id. # 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 returns, for each requested entity, the jobs, job steps and tasks that ran it in the last 31 days (upstream), and the entities it ran (downstream). # BatchGetPlatformUsers Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/batchgetplatformusers /api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/batch-get Read logins by platform user id. Ids no integration declared and with no activity in the window are left out. # ListLinkSuggestions Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/listlinksuggestions /api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/link-suggestions Suggest which workspace member each unclassified login may belong to, by matching the login against the members the caller passes. Accept a suggestion with synq.users.v1 UsersService.UpsertUserAliases. A login already linked is skipped only when the caller lists its platform_user_id among a member's identities. # ListPlatformUsers Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaplatformusersservice/listplatformusers /api-reference/openapi.yaml post /api/entities/platform-users/v1alpha/list List the workspace's logins by their share of the workspace's activity, highest first. The first page carries a summary of the whole window. # ApplyServiceAccountChanges Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/applyserviceaccountchanges /api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/apply Write a planned change set, all of it or nothing. It is refused with FAILED_PRECONDITION when the token is not from a plan of exactly this change set against the workspace as it is now: plan it again. A change to an account or person link whose etag no longer matches is refused with ABORTED, and nothing is written. Caller-supplied ids and etags make a retry converge. # BatchGetServiceAccounts Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/batchgetserviceaccounts /api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/batch-get Read service accounts by id, built-in ids included. Ids that do not exist are left out. # ListServiceAccounts Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/listserviceaccounts /api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/list List every workspace service account, then every built-in one, in the order they apply, and the person links in a second list. # ListServiceAccountSuggestions Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/listserviceaccountsuggestions /api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/suggestions Suggest service accounts for the logins the evidence says are not a person, each as a change set with its evidence. A login a workspace account, a person link or Coalesce Quality takes is left out. A login only a built-in account holds is suggested too, so it can get an account of its own. A suggestion changes nothing by itself: edit it if needed, plan it with PlanServiceAccountChanges, then apply it. # PlanServiceAccountChanges Source: https://docs.synq.io/api-reference/synqentitiesplatformusersv1alphaserviceaccountsservice/planserviceaccountchanges /api-reference/openapi.yaml post /api/entities/service-accounts/v1alpha/plan Report what a change set would change, without writing it: every login slice whose classification moves, how many counted reads each adds or removes, and the entities whose rank moves most. The plan_token it returns is what ApplyServiceAccountChanges takes. # 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 for each of the requested entities, keyed by their synq path: the set of detected SQL constructs and, when the request asks for them, the joins that building the entity makes. Every requested path appears in the response, including a path with no SQL details and a path matching no entity; both are returned with an empty set of constructs and no joins. # ListJoinPatterns Source: https://docs.synq.io/api-reference/synqentitiessql_insightsv1sqlinsightsservice/listjoinpatterns /api-reference/openapi.yaml get /api/sql-insights/v1/join-patterns ListJoinPatterns lists how other SQL joins a table, or one of its columns: every join key that the SQL of a table, view or model in the workspace uses to join the requested entity, read from the requested entity's side, and which SQL makes it. It is the reverse of `BatchSqlDetails` joins, which say how building one entity joins others: here the requested entity is the one being joined. The requested entity is taken together with every entity that is the same object, like a dbt model, the table it builds and that table in a catalog, so asking about any of them returns the joins on all of them. # 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. Every count is a number of entities, not a number of occurrences: an entity whose SQL contains five GROUP BY clauses adds one to the HAS_GROUP_BY count, not five. 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. # ListEntityTraitDefs Source: https://docs.synq.io/api-reference/synqentitiestypedefsv1typedefsservice/listentitytraitdefs /api-reference/openapi.yaml post /api/entities/typedefs/v1/entity-traits/list List every trait a selection query can filter entities by. Read it before writing a selection that uses `traits`, and to show a person what one covers. A trait name this list does not contain selects nothing, so reading the list is how you tell a trait that does not exist from one your client is too old to know about. # ListEntityTypeDefs Source: https://docs.synq.io/api-reference/synqentitiestypedefsv1typedefsservice/listentitytypedefs /api-reference/openapi.yaml post /api/entities/typedefs/v1/entity-types/list List every kind of entity in your workspace, the built-in types and your own. The built-in half covers every value of `synq.entities.v1.EntityType` this server serves, so this is also how you discover a type that your generated code is too old to name. Your own types have no enum value of their own — each one is identified by its `type_id`. # ListExecutionTypeDefs Source: https://docs.synq.io/api-reference/synqentitiestypedefsv1typedefsservice/listexecutiontypedefs /api-reference/openapi.yaml post /api/entities/typedefs/v1/execution-types/list List every kind of run Coalesce Quality records against an entity. A dbt invocation, a warehouse query job, a detected schema change. Use it to name the `execution_type` that execution and run endpoints return. # ListPlatformDefs Source: https://docs.synq.io/api-reference/synqentitiestypedefsv1typedefsservice/listplatformdefs /api-reference/openapi.yaml post /api/entities/typedefs/v1/platforms/list List every platform Coalesce Quality connects to, with its display name. Use it to name the platform on an entity — "BigQuery", "Microsoft SQL Server" — rather than deriving a name from the enum value. # 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 # DeleteComment Source: https://docs.synq.io/api-reference/synqincidentsv1incidentsservice/deletecomment /api-reference/openapi.yaml delete /api/incidents/v1/{incident_id}/comment/{comment_id} Delete a comment on an incident. Only the actor who posted the comment may delete it. Deleting an already-deleted comment succeeds. # 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 Accepts what a DataHub REST emitter sends when its server is set to `/api/ingest/airflow/v1`: it posts to `{server}/aspects?action=ingestProposal`. # 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. # DeleteComment Source: https://docs.synq.io/api-reference/synqissuesv2issuesservice/deletecomment /api-reference/openapi.yaml delete /api/issues/v2/{issue_id}/comment/{comment_id} Delete a comment on an issue. Only the actor who posted the comment may delete it. Deleting an already-deleted comment succeeds. # 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. # BatchGetEntityKnowledge Source: https://docs.synq.io/api-reference/synqknowledgev1alphaknowledgeservice/batchgetentityknowledge /api-reference/openapi.yaml post /api/knowledge/v1alpha/entities/by-id Read the knowledge held about entities: the description people wrote for each one, and the knowledge pages pinned to it. An entity with no knowledge is absent from the response, as is an id that names no entity. Returns UNAVAILABLE when the knowledge could not be read, which is worth retrying. # BatchGetKnowledgePages Source: https://docs.synq.io/api-reference/synqknowledgev1alphaknowledgeservice/batchgetknowledgepages /api-reference/openapi.yaml post /api/knowledge/v1alpha/pages/by-id Read knowledge pages by id: their content, where they sit in the tree, who owns them and how they are tagged. A page that does not exist, or was deleted, is absent from the response. Set `skip_content` to read everything but the content, for showing a listing. # ListKnowledgePageLinks Source: https://docs.synq.io/api-reference/synqknowledgev1alphaknowledgeservice/listknowledgepagelinks /api-reference/openapi.yaml get /api/knowledge/v1alpha/pages/{page_id}/links List what is pinned to a knowledge page, in either direction: the ids of the entities and of the other knowledge pages. # ListKnowledgePages Source: https://docs.synq.io/api-reference/synqknowledgev1alphaknowledgeservice/listknowledgepages /api-reference/openapi.yaml get /api/knowledge/v1alpha/pages List the ids of knowledge pages, ordered by name, optionally narrowed by a part of their name and by certification. Deprecated pages are left out unless asked for. Read the pages with `BatchGetKnowledgePages`. # 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 # 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. # BatchUpdateMonitorSegmentLabels Source: https://docs.synq.io/api-reference/synqmonitorssegmentsv1monitorsegmentsservice/batchupdatemonitorsegmentlabels /api-reference/openapi.yaml post /api/monitors/segments/v1/labels Sets or clears the label of one or more segments. Segments are addressed by the id ListMonitorSegments returns. A segment id encodes a sanitised form of the segment value, so it cannot be constructed from that value: read the ids first, then write against them. # ListMonitorSegments Source: https://docs.synq.io/api-reference/synqmonitorssegmentsv1monitorsegmentsservice/listmonitorsegments /api-reference/openapi.yaml get /api/monitors/segments/v1 Lists the segments a monitor has ingested so far, with their raw value and current label. A segment appears only once data has been observed for it, so a monitor that has not run yet lists none. # BatchGetEntityOverlays Source: https://docs.synq.io/api-reference/synqoverlaysv1overlaysservice/batchgetentityoverlays /api-reference/openapi.yaml post /api/overlays/v1/by-id For each entity, list every overlay that claims it. The response has one entry per requested id, in the order you asked, so you can match results positionally and never have to tell "absent" from "empty". An entity that belongs to no overlay comes back with empty lists. Freshness. Which overlays exist and what they are attached to is up to date the moment you change it — create an overlay, delete one, point an ownership at a different data product, and the next call reflects it. What each overlay *contains* is recomputed periodically, so an asset that newly satisfies an existing rule — a table appearing in a folder a rule watches — shows up shortly afterwards rather than instantly. Returns PERMISSION_DENIED if your credential can read neither data products nor owners. If it can read one but not the other, the call succeeds and the list you may not read comes back empty rather than failing. # BatchGetOverlayMemberCounts Source: https://docs.synq.io/api-reference/synqoverlaysv1overlaysservice/batchgetoverlaymembercounts /api-reference/openapi.yaml post /api/overlays/v1/member-counts Count the members of each named overlay. The cheap way to answer "how big is this" — use it for a summary line or a badge. When you need the assets themselves, list them through the service that defines the overlay. Counts distinct members, so an owner responsible for two data products that overlap is not charged twice for the assets they share. Same freshness as `BatchGetEntityOverlays`: counts follow the periodic recomputation of what each overlay contains. Returns PERMISSION_DENIED if your credential can read neither data products nor owners. # GetCoverageSummary Source: https://docs.synq.io/api-reference/synqoverlaysv1overlaysservice/getcoveragesummary /api-reference/openapi.yaml post /api/overlays/v1/coverage-summary Count coverage over one or more named candidate sets, without listing the assets themselves. The aggregate behind a coverage dashboard. Each selection you send comes back as one row of totals, keyed by the label you gave it, so a breakdown by type, platform, folder or domain is one round trip rather than one call per bucket. There is no server-side grouping, on purpose. This service knows what claims an asset, not what kind of thing the asset is, so naming the selections yourself — `with_type("dbt_model")`, `in_folder(...)`, `in_domain(...)` — keeps the buckets in your own vocabulary and costs the same. Selections are counted independently and may overlap. An asset in two of them is counted in both. Returns PERMISSION_DENIED unless your credential can read both data products and owners. Every row names both, and a zero that was never looked at is indistinguishable from a zero that was. # ListEntityCoverage Source: https://docs.synq.io/api-reference/synqoverlaysv1overlaysservice/listentitycoverage /api-reference/openapi.yaml post /api/overlays/v1/coverage List the candidate assets together with the overlays claiming each, and narrow them to what is or is not covered. This is the question behind a governance audit: of the assets you care about, which belong to no data product, and which have nobody responsible for them. You give the candidate set as a query — every asset, one platform, one folder, one domain — and each row comes back carrying the same owner and data-product lists `BatchGetEntityOverlays` returns, so a single call is both the count and the worklist. `total_count` is how many candidates match `filter` across every page, so you can say "312 of 4,190 tables are in no data product" without paging to the end. Freshness. By default this reads the same periodically recomputed membership the rest of this service reads, and tells you how old it is in `members_computed_at`. Ask for `FRESHNESS_LIVE` when the answer has to reflect every definition as of now — it re-resolves them, which is far slower and far more expensive, so keep it for a one-off audit rather than a page that refreshes. Returns PERMISSION_DENIED if your credential can read neither data products nor owners, and also if `filter` names a kind it may not read: an empty list must not be the answer to both "nothing is uncovered" and "you may not look". A kind you may not read still comes back as an empty list on each row, as it does elsewhere in this service. Returns INVALID_ARGUMENT if the selection resolves to more assets than one call will report on — see `CoverageSelection` for the limit and for how to choose a candidate set worth reading. # 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. # DescribeResolverQl Source: https://docs.synq.io/api-reference/synqqueriesv1queriesservice/describeresolverql /api-reference/openapi.yaml post /api/queries/v1/describe-resolver-ql Describe the ResolverQL this deployment accepts: every function with its arguments and documentation, the category order to group them by, and the accepted values of every enum-typed argument. Read it before authoring a selection, and validate against it rather than against a copy compiled into your client. The language gains functions and accepted values as Coalesce Quality supports more, and a client working from its own table both misses what was added and refuses a query this server would compile. Nothing is passed, and no permission is needed beyond being authenticated — so a client holding a narrow credential, one that may write a deployment rule but cannot read entities, can still find out how to write the selection it is being asked for. Read it as an answer for your workspace, not as a constant. Most of it is the same for everyone, but the entity types you defined yourself are part of the language too: today they are reachable only through `ResolverQlEnumDomain.pattern`, which is why that field exists, and named by `synq.entities.typedefs.v1.TypeDefsService.ListEntityTypeDefs`. Caching it for the life of your process is fine; re-read it after you add or rename an entity type of your own. # 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. # BatchGetRecommendations Source: https://docs.synq.io/api-reference/synqrecommendationsv1recommendationsservice/batchgetrecommendations /api-reference/openapi.yaml post /api/recommendations/v1/by-id Fetch recommendations by id. Ids that are unknown, belong to another workspace, no longer exist because the condition cleared, or concern an integration the credential cannot read are omitted from the response rather than erroring. # DismissRecommendation Source: https://docs.synq.io/api-reference/synqrecommendationsv1recommendationsservice/dismissrecommendation /api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/dismiss Dismiss a recommendation until something new is found about it. Replaces an ignore. Dismissing again records the recommendation as it reads now, so it stays hidden until something newer than that is found. Returns NOT_FOUND when the recommendation does not exist in the workspace, and PERMISSION_DENIED when it concerns an integration the credential cannot edit. # IgnoreRecommendation Source: https://docs.synq.io/api-reference/synqrecommendationsv1recommendationsservice/ignorerecommendation /api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/ignore Ignore a recommendation for good, whatever is found about it later. Replaces a dismissal. Ignoring an ignored recommendation succeeds without change. Returns NOT_FOUND when the recommendation does not exist in the workspace, and PERMISSION_DENIED when it concerns an integration the credential cannot edit. # ListRecommendations Source: https://docs.synq.io/api-reference/synqrecommendationsv1recommendationsservice/listrecommendations /api-reference/openapi.yaml get /api/recommendations/v1 List the ids of the workspace's recommendations, optionally limited by target and state. Fetch the recommendations themselves with `BatchGetRecommendations`. Ids are returned in a stable order, so paging is consistent while recommendations are added or removed. Returns INVALID_ARGUMENT for a malformed cursor. # RestoreRecommendation Source: https://docs.synq.io/api-reference/synqrecommendationsv1recommendationsservice/restorerecommendation /api-reference/openapi.yaml post /api/recommendations/v1/{recommendation_id}/restore Remove the dismissal or ignore standing against a recommendation, so it is open again. Restoring a recommendation nobody decided about succeeds without change. Returns NOT_FOUND when the recommendation does not exist in the workspace, and PERMISSION_DENIED when it concerns an integration the credential cannot edit. # 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. # AddUserRole Source: https://docs.synq.io/api-reference/synqusersv1usersservice/adduserrole /api-reference/openapi.yaml post /api/users/v1/roles Grants a role to a user in the workspace. Granting a role the user already holds succeeds without change. Granting a role to a user who is not a member of the workspace makes them a member; such a user can only be named by their synq or email identity. # BatchGetUsers Source: https://docs.synq.io/api-reference/synqusersv1usersservice/batchgetusers /api-reference/openapi.yaml post /api/users/v1/batch-get # DeleteUserAliases Source: https://docs.synq.io/api-reference/synqusersv1usersservice/deleteuseraliases /api-reference/openapi.yaml post /api/users/v1/aliases/delete Removes aliases from users. A platform user alias removes only that login, every other alias type removes the user's alias of that type. The scopes are checked per alias, as for UpsertUserAliases. # GetByAlias Source: https://docs.synq.io/api-reference/synqusersv1usersservice/getbyalias /api-reference/openapi.yaml post /api/users/v1/by-alias # GetByEmail Source: https://docs.synq.io/api-reference/synqusersv1usersservice/getbyemail /api-reference/openapi.yaml get /api/users/v1/by-email # GetUserAliases Source: https://docs.synq.io/api-reference/synqusersv1usersservice/getuseraliases /api-reference/openapi.yaml get /api/users/v1/aliases # GetUserIdentities Source: https://docs.synq.io/api-reference/synqusersv1usersservice/getuseridentities /api-reference/openapi.yaml get /api/users/v1/identities 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:", and the "platform_user:" id of every linked platform user. # ListUsers Source: https://docs.synq.io/api-reference/synqusersv1usersservice/listusers /api-reference/openapi.yaml get /api/users/v1 # RemoveUserRole Source: https://docs.synq.io/api-reference/synqusersv1usersservice/removeuserrole /api-reference/openapi.yaml post /api/users/v1/roles/remove Withdraws a role from a user in the workspace. Withdrawing a role the user does not hold succeeds without change. Withdrawing the user's last role removes them from the workspace, together with their linked aliases. # UpsertUserAliases Source: https://docs.synq.io/api-reference/synqusersv1usersservice/upsertuseraliases /api-reference/openapi.yaml put /api/users/v1/aliases Links aliases to users. A platform user alias needs SCOPE_PLATFORM_USER_LINK, every other alias type SCOPE_USER_EDIT. A request holding an alias the caller may not write is refused as a whole, and nothing is written. # 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. 5. **Check what arrived**: every delivery is recorded with the request sent, the response returned and — when nothing was sent — the reason. See [Debugging Deliveries](/api-reference/webhook-deliveries). ### 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. To confirm your endpoint is on the new secret without waiting for a real event, replay an earlier delivery: a replay is signed with the current secret only. See [Redeliver](/api-reference/webhook-deliveries#redeliver). ### 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. # Debugging Deliveries Source: https://docs.synq.io/api-reference/webhook-deliveries See what Coalesce Quality sent to your webhook, PagerDuty or Opsgenie integration, why a notification did not arrive, and replay it # Deliveries Every notification Coalesce Quality sends to one of your integrations is recorded: the request as it was sent, the response your endpoint returned, how long it took, and — when nothing was sent at all — the reason. Open it under **Settings > Integrations > your integration > Deliveries**. The tab is available for every integration that receives notifications: **webhooks**, **PagerDuty** and **Opsgenie**. Everything below applies to all three, and everything visible there is also readable over the API — see [Over the API](#over-the-api). Deliveries are kept for **90 days**. ## What a delivery is One **delivery** is one event addressed to one integration. An event that matches three integrations produces three deliveries. They share an **event id** and each has its own delivery id. The event id is the same `event_id` your endpoint received in the webhook payload, so you can go from a payload you have in hand to the delivery that produced it — and to every other integration that got the same event. Each delivery has one or more **attempts**. An attempt is one HTTP request and whatever came back. ## Outcomes | Outcome | What it means | What to do | | - | - | - | | **Delivered** | Your endpoint accepted it. Only a `2xx` counts. | Nothing. | | **Pending** | Accepted and queued, with an attempt still to come. The row shows when the next attempt is due. | Wait. If it stays pending, check that your endpoint is reachable. | | **Failed** | Your endpoint rejected it outright, or it was still failing when the retries ran out. Nothing further will be attempted. | Read the attempts, fix the endpoint, then **Redeliver**. | | **Skipped** | The integration was found and its own configuration meant nothing was sent. | See [Why nothing was sent](#why-nothing-was-sent). | | **Not routed** | No integration could be resolved for the event. | See [Why nothing was sent](#why-nothing-was-sent). | A status code is not an outcome. A `500` that will be retried and a `500` that exhausted the retries are the same status and different outcomes, which is why the outcome is what to filter and alert on. ### Retries A failing delivery is retried up to **10 times** with exponential backoff, over roughly 30 minutes. * Only a `2xx` response counts as delivered. * A `400`, `404` or `422` is treated as permanent and not retried: those say the request itself is wrong, and repeating it will not change the answer. * A `5xx`, a timeout and a connection failure are retried. * A `3xx` is **not followed** and is retried like any other transient failure. A delivery can carry credentials scoped to one host, so following a redirect could send them somewhere else. Point the integration at the final URL rather than at something that redirects. Retries reuse the original signing timestamp, so a timestamp tolerance in your [signature verification](/api-reference/webhook#verifying-webhook-signatures) has to allow for the retry window. ## Why nothing was sent A delivery that sent nothing always records a reason. Each one names something specific to change. | Reason | What it means | The fix | | - | - | - | | **Event type not subscribed** | The integration does not list this event type. | Add it under the integration's event types. | | **Event type unsupported by integration** | The destination has no representation for this kind of event. PagerDuty and Opsgenie carry issue and incident lifecycle events, not every webhook event type. | Nothing to fix. Use a webhook integration if you need this event type. | | **No action for lifecycle state** | The change of state maps to no action on the destination — for example a status change that PagerDuty or Opsgenie has no equivalent for. | Nothing to fix. | | **Integration not found** | The integration the event was addressed to no longer exists. | Expected shortly after deleting an integration. Otherwise contact support. | | **Integration disabled** | The integration exists but is switched off. | Enable it. | | **Empty event subject** | The event carried no issue or incident to describe. | Contact support. | This is the answer to "my alerting has gone quiet". A workspace whose deliveries are all **Skipped** with *Event type not subscribed* is configured to send nothing, which looks identical to a broken endpoint until you read the reason. Deliveries describe what happened **after** an event was routed to an integration. An alert that was suppressed before that, or that matched no ownership, produces no delivery at all — so an event you expected and cannot find here is a question about the alert configuration, not about the integration. Each delivery names the alert configuration that selected it, which is where to start. ## Reading a request and a response Expand a delivery to see each attempt: the method and URL, the request headers and body, the response status, headers and body, and the duration. ### Withheld header values A header whose value carries a credential is reported by name but its value is never returned. That covers: * headers you marked **secret** on the integration, * credentials Coalesce Quality holds for the destination, such as the Opsgenie API key, * the standard credential-bearing names — `Authorization`, `Proxy-Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, `X-Auth-Token` — whatever they contain, on the request **or** the response side. A withheld header shows a **fingerprint** instead: a short digest, stable for the same value. You cannot read the value from it, but you can compare two deliveries and tell whether the value changed — which is usually the actual question ("is this the same token as the one that worked yesterday"). Alongside it, the **secret version** says which stored secret the value was read from, so a delivery stays attributable across a rotation. The header is still listed. A missing value means withheld, never "no header was sent". ### Signature headers are shown in full `X-Coalesce-Signature` and `X-Coalesce-Timestamp` are returned complete. The signature is a digest of the body and the timestamp is a timestamp; neither is your signing secret, and reproducing a verification that failed needs the exact bytes. See [Verifying Webhook Signatures](/api-reference/webhook#verifying-webhook-signatures). ### Bodies A request body value the destination requires to be secret — a PagerDuty routing key, for instance — is replaced by a marker naming the field it stood in, so the record shows a value was sent rather than implying none was. The reported request size is the real one, before that substitution. A response body is kept up to a fixed size and marked as truncated past it, with the full size reported. The first error line is where the diagnostic value is. ## Redeliver **Redeliver** sends a stored event again, to the same integration, with the same payload. The replay is a new delivery with its own id, linked to the original, and it appears in the feed like any other. It is signed with the integration's **current** signing secret, not the one the original used. That makes it the way to confirm a [secret rotation](/api-reference/webhook#signing-secret) reached your receiver: rotate the secret, update your endpoint, redeliver an earlier event, and a **Delivered** outcome proves the new secret is accepted. There is no need to wait for a real alert, and no need to wait out the 24-hour dual-signing window to find out. Redeliver is rate-limited per integration, so a replay loop cannot hammer an endpoint. Over the limit it is refused rather than queued. ## Send test event **Send test event** delivers a test payload and reports the real outcome, rather than only that it was sent. It is always sent, whatever event types the integration subscribes to. A test that silently matched no subscription would report exactly what a broken endpoint does, and telling those two apart is the only reason to run a test. On Opsgenie it opens a real alert, aliased so repeated tests do not stack up, because that is the only thing the integration does. ## Over the API Everything above is available over the public API. Reading needs a token with **Read Deliveries** (`SCOPE_DELIVERY_READ`); replaying and testing need **Send and Replay Deliveries** (`SCOPE_DELIVERY_EDIT`). Create a token under [API settings](https://app.synq.io/settings/api) and get an access token as described in [Getting Started](/api-reference/getting-started). The examples use the EU endpoint. For other regions use `api.us.synq.io` or `api.au.synq.io`. ### List deliveries ```bash theme={null} curl -G https://developer.synq.io/api/deliveries/v1 \ -H "Authorization: Bearer $TOKEN" \ -d integrationId=d577b364-a867-11ed-b4b2-fe8020e7ba25 \ -d since=2026-08-01T00:00:00Z \ -d pagination.pageSize=50 ``` Deliveries come back newest event first. Pass the response's `pageInfo.lastId` as `pagination.cursor` for the next page; an empty `lastId` means there are no more. Omit `integrationId` for the whole workspace's feed. Add `includeRouting=true` to get the alert configurations that selected each integration — it is off by default because it costs an extra read per delivery. ### Filter by outcome ```bash theme={null} curl -G https://developer.synq.io/api/deliveries/v1 \ -H "Authorization: Bearer $TOKEN" \ -d integrationId=d577b364-a867-11ed-b4b2-fe8020e7ba25 \ -d outcomes=OUTCOME_FAILED \ -d since=2026-08-01T00:00:00Z ``` `outcomes` and `statusCodes` repeat, so `-d outcomes=OUTCOME_FAILED -d outcomes=OUTCOME_SKIPPED` matches either. `eventTypes` filters by event type name, and `eventId` narrows to a single event across every integration it reached. ### Find every integration one event reached ```bash theme={null} curl -G https://developer.synq.io/api/deliveries/v1 \ -H "Authorization: Bearer $TOKEN" \ -d eventId=0b6f9c2e-1a2b-4c3d-9e8f-123456789abc ``` `eventId` is the `event_id` from the webhook payload your endpoint received. ### Fetch the attempts of a delivery ```bash theme={null} curl https://developer.synq.io/api/deliveries/v1//attempts \ -H "Authorization: Bearer $TOKEN" ``` Oldest attempt first. A delivery is attempted at most ten times, so the result is small and is not paginated. It is empty for a delivery that sent nothing, and for one still waiting on its first attempt. The `` is the `id` of a delivery from the list — an opaque value composed by the service. Pass it back as it came; do not build one yourself. ### Replay a delivery ```bash theme={null} curl -X POST https://developer.synq.io/api/deliveries/v1//redeliver \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" -d '{}' ``` The response carries the new delivery's id. The send is asynchronous, so poll for the outcome until it leaves `OUTCOME_PENDING`: ```bash theme={null} curl -X POST https://developer.synq.io/api/deliveries/v1/by-id \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"ids": [""]}' ``` An id that does not exist, or that has passed out of the 90-day window, is absent from the response rather than an error. ### Send a test delivery ```bash theme={null} curl -X POST https://developer.synq.io/api/deliveries/v1/test \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"integrationId": "d577b364-a867-11ed-b4b2-fe8020e7ba25", "message": "checking the new endpoint"}' ``` Returns the id of the delivery it created; poll it the same way. ### Watch your own delivery failure rate ```bash theme={null} curl -X POST https://developer.synq.io/api/deliveries/v1/summarise \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"integrationId": "d577b364-a867-11ed-b4b2-fe8020e7ba25", "since": "2026-08-12T00:00:00Z"}' ``` Counts the window by outcome, by skip reason and by HTTP status class, without paging through the feed. This is the call to alert on if you want to know about a broken receiver before someone notices a missing alert. A full worked example in Go — list, filter, attempts, redeliver and summarise — is on the [examples](/api-reference/examples) page as `deliveries`. ## Related * [Using Webhooks](/api-reference/webhook) — event types, payload schema, custom headers and signature verification. * [PagerDuty](/alert-integrations/pagerduty) and [Opsgenie](/alert-integrations/opsgenie) — setting those integrations up. * [API Scopes](/api-reference/scopes) — the full scope reference. # 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 title 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` title 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. title 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. title ### 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. title 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. title 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. title You can enhance the Owners with your monitoring and alerting preferences. title 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 On macOS, install any of them with Homebrew, and upgrade with `brew upgrade`: ```bash theme={null} brew install getsynq/tap/synqcli brew install getsynq/tap/synq-recon brew install getsynq/tap/synq-scout ``` Homebrew owns the binary once it installs it, so ` upgrade` will point you back to `brew upgrade` rather than replace it. Either way you have an upgrade path — see [Upgrade](#upgrade). Homebrew serves macOS only. Everywhere else — Linux, CI, Windows — take the archives. Every release publishes them for macOS and Linux on both `amd64` and `arm64` (`synqcli` also builds for Windows on both, `synq-recon` on `amd64`), plus a `checksums.txt`. The archive filename carries the version, so it has to be named explicitly. Rather than transcribe one, resolve it: GitHub redirects `/releases/latest` to the tag of the newest release, so reading that redirect gives you the current version with no API token and no rate limit. It is the same lookup each tool's own [`upgrade`](#upgrade) uses. ```bash theme={null} VERSION=$(curl -fsSLI -o /dev/null -w '%{url_effective}' \ https://github.com/getsynq/synqcli/releases/latest | sed 's#.*/v##') 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](https://github.com/getsynq/synqcli/releases) and put `synqcli.exe` on your `PATH`. ```bash theme={null} VERSION=$(curl -fsSLI -o /dev/null -w '%{url_effective}' \ https://github.com/getsynq/synq-recon/releases/latest | sed 's#.*/v##') 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 ``` On Windows, download `synq-recon__windows_amd64.zip` from the [releases page](https://github.com/getsynq/synq-recon/releases) and put `synq-recon.exe` on your `PATH`. It runs DuckDB like the other builds. 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=$(curl -fsSLI -o /dev/null -w '%{url_effective}' \ https://github.com/getsynq/synq-scout/releases/latest | sed 's#.*/v##') 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 binary downloaded this way may be quarantined. If it refuses to start, `xattr -d com.apple.quarantine /usr/local/bin/` clears the flag. The Homebrew install does this for you. ## Upgrade A tool installed from an archive can replace itself: ```bash theme={null} synqcli upgrade --check # what it would do, without doing it synqcli upgrade ``` `upgrade` resolves the latest release, downloads the archive for your platform, verifies it against the release's `checksums.txt`, and runs the new binary once to confirm it works before replacing anything. If the binary lives somewhere you cannot write, it says so and changes nothing — re-run with `sudo`. An install owned by something else is left to its owner: a Homebrew install tells you to run `brew upgrade`, and a container or Kubernetes deployment should take a newer image rather than replace the binary inside it. Each tool also mentions a newer release on stderr, at most once a day. That check reads a tag from a public GitHub URL and sends nothing but the tool name and version — no credentials, no workspace, no identity. It never delays the command it runs beside and never reports its own failure, so a machine with no route to the internet behaves exactly like one that is up to date. It is already silent in CI, when output is not a terminal, and inside a container or a Kubernetes pod. To turn it off everywhere: ```bash theme={null} export QUALITY_NO_UPDATE_CHECK=1 # DO_NOT_TRACK=1 has the same effect ``` ## 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. Pin the version in a pipeline — set `VERSION` to a literal instead of resolving `/releases/latest` — so a release cannot change what your build runs without a commit. On a workstation, take the latest. Either way check ` --version` into the build log; it is the first thing anyone asks when a pipeline behaves differently from a laptop. `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 Cloud Bitbucket 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** Navigate to profile 2. On your profile page, click **Repositories**, then click the name of your repository Select repository ### Access Repository Settings 3. From your repository, click **Settings** Repository 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** 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) Configure deploy key **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 # Agent Workflow Source: https://docs.synq.io/custom-integrations/agent-workflow A self-contained brief for a coding agent writing a custom integration against the Coalesce Quality API This page is written to be handed to a coding agent. Point it here and describe your tool: > Read [https://docs.synq.io/custom-integrations/agent-workflow](https://docs.synq.io/custom-integrations/agent-workflow) and follow it. > Write an integration for ``. Its API is at ``. Everything an agent needs is below. The rest of this section is the same material for a human reader. *** ## Your task Write a program that reads a tool Coalesce Quality has no integration for and publishes it to the Coalesce Quality catalog over the public API: entities, schemas, lineage, checks and run status. The program must be **idempotent**. It runs on a schedule, not once. Running it twice produces the same estate. ## Ground rules Read all of these before writing code. Each one exists because getting it wrong produces a valid-looking write and a broken catalog, with no error anywhere. 1. **The entity id is a lowercase slug built from the source system's stable id.** Restrict it to `A-Z a-z 0-9 : _ . -`, shaped `::::`. Every human-readable string — the title, accents, spaces — goes in `name` and `description` instead. See [Entity ids](#entity-ids). 2. **Declare schemas before writing any lineage.** A `SELECT *` expands only over an entity whose columns are known. Skip this and table-level edges still appear while column-level ones silently do not. Note that a *declared* `ColumnLineage` edge is **not** validated against the upstream schema — a typo in `upstream_column` is accepted and yields a broken hop, so verification in step 9 is what catches it. 3. **Bind every name in SQL that is not a warehouse object.** A `SqlDefinition` resolves names that live at a warehouse address. Anything else resolves to nothing and is dropped with no error. See [Binding](#binding-non-warehouse-names). 4. **Never send `category` or `governance_category` on a check.** They are resolved by the workspace's own categorisation rules, and a producer value outranks those rules. Send `package` and `kind` only. 5. **`feature_id` is a stable constant, never generated.** A fresh id each run creates a new feature instead of replacing the previous one. 6. **The entity group is sent whole, every run.** A partial send is a deletion of everything omitted. If reading the source tool can fail halfway, skip the group write that run. 7. **Read the lineage back at the end and fail loudly.** Assert the edges you expect, not merely that some edge exists, and exit non-zero on a timeout or a non-OK CLL state. This is the only thing that distinguishes a working integration from a broken one. Keep it in production. 8. **Set the gRPC authority when building the channel**, or every RPC returns `UNIMPLEMENTED`. Step 0 below has the option for each language. ## Step 0: setup Everything you need is on this page. Follow it straight through rather than opening the other pages; they say the same things at more length, and the two links that matter are named at the points where you need them. Credentials come from API settings, at `/settings/api` in the customer's own app host (`app.synq.io` EU, `app.us.synq.io` US, `app.au.synq.io` AU), with these scopes: **Edit Entity Types**, **Edit Entities**, **Edit Lineage**, **Edit Executions**, **Read Entities**, **Read Entity Types**, **Read Lineage**. Read them from the environment. Never hardcode them. ``` QUALITY_CLIENT_ID QUALITY_CLIENT_SECRET QUALITY_API_ENDPOINT developer.synq.io (EU) | api.us.synq.io (US) | api.au.synq.io (AU) ``` Exchange for a token at `POST https://$QUALITY_API_ENDPOINT/oauth2/token` with `grant_type=client_credentials`, and send `authorization: Bearer ` on every call. Refresh when `expires_in` elapses. Use the prebuilt SDKs from [buf.build/getsynq/api](https://buf.build/getsynq/api/sdks) rather than generating clients. **Set the gRPC authority explicitly when you build the channel.** Without it the port travels in the `Host` header and **every RPC returns `UNIMPLEMENTED` with no message** — which reads as a missing service, not a routing problem, and is the single most likely reason a first run fails entirely: * Go: `grpc.WithAuthority(endpoint)` as a dial option. * Python: `options=(("grpc.default_authority", endpoint),)` on `grpc.secure_channel`. If an endpoint above does not resolve, the maintained list is the [region table](https://docs.synq.io/security/ip); token exchange and client generation are covered in full by [Getting Started](https://docs.synq.io/api-reference/getting-started). Neither is needed to follow this page. **Before writing code, read one of the complete examples**: [Go](https://github.com/getsynq/api/tree/main/examples/golang/bi_tool_lineage), [Python](https://github.com/getsynq/api/tree/main/examples/python/bi_tool_lineage). They are verified against a live workspace and cover every step here. ## Step 1: map the source tool Enumerate the kinds of object the tool has, and for each one decide: * **Does it transform data?** → trait `is_model` * **Is it a raw external input?** → trait `is_source` * **Is it read by a person: a dashboard, a report?** → trait `is_bi_like` * **Does it validate another object?** → trait `is_test_type` * **Is it infrastructure nobody wants drawn?** → trait `is_ignored_in_lineage` Traits combine. A saved query that transforms data *and* is read by a person is both `is_model` and `is_bi_like`. Then decide, per kind of edge between objects, which lineage mechanism applies: | The downstream object has | Use | | - | - | | SQL, reading real warehouse tables | `SqlDefinition` | | SQL, naming something with no warehouse address | `SqlDefinition` + `references` | | No SQL, but a known column mapping | `ColumnLineage` | | No SQL and no columns | `Relationship` | | A validation role over another object | `CheckCategory` + check relationship | Prefer `SqlDefinition` wherever there is SQL. A declaration is a snapshot; a parse follows the query. Write this mapping down in the source file as a comment before implementing it. It is the design, and it is what a reviewer needs. ## Entity ids A custom entity is named by `CustomIdentifier { id: "" }`. **The id is a slug, not a label.** It is a machine identifier. Everything a person reads goes in `name` (up to 500 characters, any UTF-8) and `description` (Markdown) — separate fields with no restriction. Never put a title, a path with spaces, or accented text in the id; put it in `name`. Build every id to these three rules: 1. **From the source system's stable id**, never a display name. A title changes; a primary key does not. Changing an id creates a second entity rather than renaming the first. 2. **From the alphabet `A-Z a-z 0-9 : _ . -` only.** That is what the platform preserves verbatim. Use `::` as the separator and prefix with the tool and object kind: `::::`. 3. **Lowercased.** Ids are case-sensitive, so `Metabase::Question::87` and `metabase::question::87` are two entities and nothing warns you. Lowercase at the single place you build ids. ``` metabase::question::87 good metabase::Revenue by category bad — a title, a space, a capital ``` Ignore this and the write normalises silently: truncated at 200 bytes (hash tail if longer), non-ASCII replaced by its literal escape text (`zamówienia` becomes `zam_u00f3wienia`), and every other character folded to `_`. **Two ids differing only in folded characters become the same entity** — `metabase/question/87` and `metabase question 87` both become `metabase_question_87`, second write overwriting the first. The stored id is `custom-`, which is what the API returns as `entity_id`. ### Naming entities you did not create Lineage points at warehouse tables, dbt models and dashboards that already exist. **Use the structured variant for the platform** — `bigquery_table`, `snowflake_table`, `databricks_table`, `postgres_table`, `mysql_table`, `clickhouse_table`, `redshift_table`, `trino_table`, `mssql_table`, `oracle_table`, `athena_table`, `fabric_table`, `dbt_core_node`, `dbt_cloud_node`, `sql_mesh_model`, `sql_mesh_audit`, `airflow_dag`, `airflow_task`, `monitor`, `dataproduct`, `saved_view`. Construct these from the coordinates the source tool reports. `synq_path` is the fallback, for a platform with no structured variant (Looker, Tableau, Coalesce Catalog and anything newer) or when you already hold an entity's opaque `entity_id`. To obtain one: * The app URL `/catalog//overview` — the segment after `/catalog/` is the id. The app host is regional, matching the API endpoint above. * The [MCP server](https://docs.synq.io/scout/mcp): `search_entities` and the other read tools. * A [webhook payload](https://docs.synq.io/api-reference/webhook): each entity carries its `identifier` and an `entity_url` containing the id. * `BatchIdsByCoordinates`, which maps a warehouse name to matching ids. `entity_id` is output only — on a request it is ignored, and the structured variant is what resolves. To name an entity *by* opaque id, set `synq_path` to that string. ### Resolve before you write `synq.entities.resolve.v1.IdentifierResolveService.BatchResolveIdentifiers` turns an identifier of any shape into its `entity_id`, and with `check_existence: true` says whether the entity exists. The two kinds of upstream differ, and this is what tells them apart: * A **custom** entity that does not exist is **rejected** at the write, so a misspelled custom id surfaces immediately. * An entity on a **connected platform** is **not checked**; it binds on next ingestion. So a typo'd warehouse name and a not-yet-crawled table are indistinguishable in the lineage afterwards. Run `BatchResolveIdentifiers` over every connected-platform upstream and fail loudly on anything that does not resolve. It also returns the entity's **identity group** (`identities`, `identity_synq_paths`) — the other identifiers that name the same entity, such as a dbt model and the warehouse table it builds. Use it to detect that two upstreams you were treating as different are one entity before writing two relationships that collapse into one edge. ### Use the read API as input Do not hardcode a table of entity ids. Resolve them at run time: | To answer | Call | | - | - | | Which entity is this warehouse name? | `BatchIdsByCoordinates` | | Does this identifier resolve, and to what? | `BatchResolveIdentifiers` | | Which entity does this name refer to? | `SearchEntities`, `ListEntities` | | What columns does this upstream really have? | `GetSchema` | | Which type numbers are already taken? | `ListTypes`, `ListEntityTypeDefs` | | Where does this entity sit in the folder tree? | `Browse`, `GetFolderOf` | Declaring column lineage against columns read from `GetSchema`, rather than columns the source tool believes exist, is the difference between edges that appear and edges that do not. ## Step 2: types `synq.entities.custom.v1.TypesService.UpsertType`, one per kind. * `type_id` is `1`–`1000`, workspace-wide, with no allocator. * **Call `ListTypes` first** and refuse to start if one of your numbers is taken under a different name. Two integrations picking the same band is otherwise silent corruption. * `name` is a short caption shown on a badge, max 100 chars: `"Kafka Topic"`, not a sentence. * `svg_icon` is required, raw SVG bytes, max 1 MB. * `traits` from step 1. Keep the numbers in a constant table at the top of the file. ## Step 3: entities `synq.entities.custom.v1.EntitiesService.UpsertEntity`, one per object. **Create every entity before anything points at one.** A SQL binding to an entity that does not exist is rejected at the write. * `id` — `CustomIdentifier`, from the source system's stable id. * `type_id` — from step 2. * `name` — as the tool shows it, max 500 chars. Do not shorten it to fit. * `description` — Markdown, max 10 000 chars. * `annotations` — the tool's own filing system: collection, folder, workspace, object kind. Max 20 annotations, each with a name (max 50 chars) and up to 20 values (max 100 chars). These are what people filter the catalog by, so keep them to labels, not prose. Never set `synq_path`, `synq_catalog_url`, `ids` or `synq_paths` — they are returned, not sent. ## Step 4: schemas `FeaturesService.UpsertEntityFeature` with a `schema` feature, `feature_id: "schema"`. Do this **before** step 5. Columns carry a name, native type, description and ordinal position. Give positions for all columns or for none. Max 1000 columns; struct and repeated types nest through `fields`. ## Step 5: lineage ### SqlDefinition `feature_id: "sql"`. One per entity. * `dialect` — one of `SQL_DIALECT_{BIGQUERY,CLICKHOUSE,DATABRICKS,MYSQL,POSTGRESQL,REDSHIFT,SNOWFLAKE,DUCKDB,TRINO,MSSQL,ORACLE,ATHENA,FABRIC}`. * `sql` — as the tool actually executes it, max 1 000 000 chars. * `database_context` — what unqualified names in the SQL resolve against. * `references` — see below. Max 200. ### Binding non-warehouse names A `SqlDefinition` can only resolve names that live at a warehouse address. A saved query, a queue, a service, an API or another custom entity has no address, so `FROM my_upstream` matches nothing, is dropped, and the entity ends up with **no upstream at all and no error**. An empty result is indistinguishable from a query that genuinely reads nothing. This is the single most common way a custom integration ships broken. `references` binds a name, as the SQL writes it, to the entity it stands for: ``` SqlTableReference { instance_name "" empty parts default from database_context database_name "" schema_name "" object_name "order_items_enriched" the name exactly as the SQL writes it entity } ``` * Matching is case-insensitive. * A binding **beats** a real warehouse table of the same name — use it as a deliberate override when you need one. * Empty parts default from `database_context`, exactly as an unqualified name in the SQL does. * Names that **are** warehouse objects need no binding. One definition can read a bound custom entity and a raw table in the same query, binding only the first. * Bindings replace with the definition. One dropped from a later write is gone. ### ColumnLineage `feature_id: "column-lineage"`. One per entity, max 10 000 edges. Use when there is no SQL for a parser to read. Each `ColumnEdge` is `upstream` (an `Identifier`), `upstream_column` and `column`. The two sides are named independently and need not match. * **It replaces whole.** An edge missing from a write is withdrawn. Regenerate it from the tool's metadata every run rather than diffing. * **A column edge declares the table edge it implies.** Do not also write a `Relationship`. * **It wins over `SqlDefinition`.** An entity with both is served from this declaration. So either declare only what the SQL cannot say, or make this the authority for the entity's whole column lineage. * An upstream that does not exist yet is remembered, and the edge appears once it does. * `state_at` defaults to now; set it explicitly when backfilling. ### Relationship `RelationshipsService.UpsertRelationships`, for edges with nothing to say at column grain. At least one endpoint must be a custom entity — two native entities cannot be joined. **Read the response.** Each `RelationshipWriteResult` names the resolved endpoints and an outcome of `CREATED`, `UPDATED`, `DELETED` or `NOT_FOUND`. An edge is held between the entities the endpoints *resolve* to, and one entity accepts several spellings, so two relationships that look different can be the same edge — and only the last write survives. ### Code and Git Optional but worth including: * `code` feature (`feature_id` per file or function, several allowed): the SQL, Python, YAML or JSON behind the entity, max 100 000 chars, with a `code_type` of `CODE_TYPE_{SQL,PYTHON,JSON,YAML,DBT,SQLMESH,LOOKML,JAVASCRIPT,BASH,DAX,JAVA,SCALA,TEXT,MARKDOWN}`. * `git_file_reference` feature: repository URL (SSH preferred), branch, file path. With a code integration connected, Coalesce Quality reads the file's history and shows recent commits against the entity when it fails. ## Step 6: checks For objects that validate other objects — an alert, a test, a monitor in the source tool. 1. `ChecksRelationshipsService.UpsertCheckRelationships` with `check`, `checked` and optional `checked_columns`. 2. `check_category` feature, `feature_id: "check"`, carrying `package` (a grouping, max 50 chars) and `kind` (what the tool calls it, max 50 chars). **That order matters.** Attaching a check relationship schedules no re-publish of the derived check record, while writing a feature does. Writing the feature first leaves the check's stored state stale until the entity is written again. If you ever delete a check relationship, re-write the feature afterwards for the same reason. **Do not set `category` or `governance_category`.** They are resolved by the workspace's own [categorisation rules](https://docs.synq.io/analytics/check-categories) from `package` and `kind`. A producer value outranks those rules, so deriving one from the tool's alert kind — the obvious thing to do — silently switches off every rule the workspace wrote, with nothing in the product explaining why. A check is not a stage data flows through. Do not also give it a lineage edge. ## Step 7: the entity group `GroupsService.UpsertEntitiesGroup` with one `group_id` for your integration and **every entity id it owns**. The server diffs your set against the previous one and deletes what is missing. That is what makes deletion work without keeping state on your side. ``` run 1: group = A, B, C run 2: group = B, C, D -> A is deleted ``` A partial send is a deletion of everything omitted. If the source read can fail partway, skip the group write for that run. Log `deleted_ids` from the response. **A group deletes entities only.** It does not remove features, relationships or check relationships belonging to entities that still exist. A dashboard repointed at a different model, a check that was removed, a `SqlDefinition` that is no longer relevant — none of those are cleaned up by the group write, and they stay in the graph indefinitely. So the run also has to reconcile what it wrote last time: 1. Read the current state: `ListEntityFeatures` (with `entity_id` unset for the whole workspace), `ListRelationships`, `ListCheckRelationships`. 2. Diff against the state you are about to write. 3. Withdraw what is gone, **before** the group write: `DeleteEntityFeature`, `DeleteRelationships`, `DeleteCheckRelationships`. 4. Then write the group, which removes the entities themselves. Withdrawing edges before deleting entities is the order that leaves no dangling references. ## Step 8: executions `EntityExecutionsService.UpsertExecution`, so entities have health rather than just a position in a graph. * `status` — `EXECUTION_STATUS_{OK,WARN,ERROR,CRITICAL}`. * `created_at` — required, must be in the past, rejected before 2022-01-01. * `started_at` / `finished_at` — for long runs. * `extras.executed_sql` — the SQL that ran. Report what the tool tells you and nothing more. A run that has not happened yet is simply not reported. `UpsertLogEntry` attaches log output without changing status. ## Step 9: verify Call `LineageService.GetLineage` with `lineage_direction: LINEAGE_DIRECTION_UPSTREAM` and a `start_point.entities` naming an entity at the bottom of your graph. Lineage is computed asynchronously, so poll with a deadline. **A non-empty result is not success.** Assert the specific nodes and edges you expect. A declared column edge with a typo'd `upstream_column` still produces one hop while the chain beyond it is silently lost, so "at least one edge exists" passes on a graph that is broken. Fail the program, with a non-zero exit status, on any of: * an expected node or edge missing from the response, * a node whose `cll_details.cll_state` is neither OK nor unspecified — `RESOLUTION_FAILED` is usually a name you should have bound in step 5 and did not, * the poll deadline expiring, or the read erroring. A timeout that logs and returns normally is the failure mode to avoid: it reports success for a graph that never materialised. ## Definition of done Check each of these before reporting the work complete: * [ ] Ids are lowercase slugs from the source system's stable ids, in `A-Z a-z 0-9 : _ . -` * [ ] No title, accent, space or other human-readable text is in an id; it is in `name` * [ ] `ListTypes` is called before claiming type numbers * [ ] Every type declares its traits * [ ] Every entity with columns declares its schema, before lineage is written * [ ] Every non-warehouse name in a `SqlDefinition` has a `references` binding * [ ] Every upstream is resolved with `BatchResolveIdentifiers` before lineage is written * [ ] Checks send `package` and `kind` only * [ ] All `feature_id` values are constants * [ ] The group is sent whole, and skipped entirely on a partial source read * [ ] Obsolete features, relationships and check relationships are explicitly deleted; the group write alone does not remove them * [ ] Credentials are read from the environment * [ ] The program polls `GetLineage` at the end and exits non-zero when it is empty * [ ] Running the program twice produces no change on the second run ## Reference * [Modelling your tool](/custom-integrations/modelling) — the decisions in more depth * [Building an integration](/custom-integrations/building-an-integration) — the same steps with Go and Python code * [API surface](/custom-integrations/api-surface) — every method, scope and limit * [gRPC API reference](/api-reference/api) — generated from the protos * [API scopes](/api-reference/scopes) — every scope and the methods it unlocks * [Protos](https://github.com/getsynq/api/tree/main/protos) and [SDKs](https://buf.build/getsynq/api/sdks) * [Examples](https://github.com/getsynq/api/tree/main/examples) — runnable Go and Python Questions that this page does not answer go to your Technical Account Manager — see [Support](/support/support). # API Surface Source: https://docs.synq.io/custom-integrations/api-surface Every service a custom integration calls, the scope each method needs, and the limits that apply The methods a custom integration uses, grouped by what they do. Full generated reference: [gRPC API](/api-reference/api), [API Scopes](/api-reference/scopes), [OpenAPI spec](https://github.com/getsynq/api/blob/main/openapi.yaml). All services are under `synq.entities.*`. REST paths are given for the transcoded HTTP API; the same methods are available over gRPC. ## Write ### Types `synq.entities.custom.v1.TypesService` | Method | REST | Scope | | - | - | - | | `UpsertType` | `POST /api/entities/custom/v1/types` | Edit Entity Types | | `DeleteType` | `DELETE /api/entities/custom/v1/types` | Edit Entity Types | | `ListTypes` | `POST /api/entities/custom/v1/types/list` | Read Entity Types | `Type` carries `type_id` (`1`–`1000`), `name` (max 100 chars), `svg_icon` (max 1 MB) and `traits`. ### Entities `synq.entities.custom.v1.EntitiesService` | Method | REST | Scope | | - | - | - | | `UpsertEntity` | `POST /api/entities/custom/v1/entities` | Edit Entities | | `DeleteEntity` | `DELETE /api/entities/custom/v1/entities` | Edit Entities | | `ListEntities` | `GET /api/entities/custom/v1/entities` | Read Entities | `Entity` carries `id`, `type_id`, `name` (max 500 chars), `description` (max 10 000 chars, Markdown) and up to 20 `annotations`. Each annotation has a name (max 50 chars) and up to 20 values (max 100 chars each). `synq_path`, `synq_catalog_url`, `ids` and `synq_paths` are returned, never sent. ### Features `synq.entities.custom.v1.FeaturesService` | Method | REST | Scope | | - | - | - | | `UpsertEntityFeature` | `POST /api/entities/custom/v1/features` | Edit Entities | | `DeleteEntityFeature` | `DELETE /api/entities/custom/v1/features` | Edit Entities | | `ListEntityFeatures` | `POST /api/entities/custom/v1/features/list` | Read Entities | A `Feature` is `entity_id` + `feature_id` (max 255 chars, **stable**) + one of: | Feature | Per entity | Limits | | - | - | - | | `sql_definition` | one | `sql` max 1 000 000 chars, `references` max 200 | | `schema` | one | `columns` max 1000, nested `fields` max 100 per column | | `column_lineage` | one | `edges` max 10 000, column names max 255 chars | | `check_category` | one | `package` and `kind` max 50 chars each | | `code` | many | `content` max 100 000 chars, `name` max 50 chars | | `git_file_reference` | many | `repository_url` and `file_path` max 255 chars, `branch_name` required, max 244 bytes | `ListEntityFeatures` with `entity_id` unset returns the features of every custom entity in the workspace. ### Groups `synq.entities.custom.v1.GroupsService` | Method | REST | Scope | | - | - | - | | `UpsertEntitiesGroup` | `POST /api/entities/custom/v1/groups` | Edit Entities | | `DeleteEntitiesGroup` | `DELETE /api/entities/custom/v1/groups` | Edit Entities | | `ListEntityGroups` | `POST /api/entities/custom/v1/groups/list` | Read Entities | `UpsertEntitiesGroup` replaces the group's membership whole and returns `deleted_ids` — the entities that were in the group and are not in this write. ### Relationships `synq.entities.custom.v1.RelationshipsService` | Method | REST | Scope | | - | - | - | | `UpsertRelationships` | `POST /api/entities/custom/v1/relationships` | Edit Lineage | | `DeleteRelationships` | `DELETE /api/entities/custom/v1/relationships` | Edit Lineage | | `ListRelationships` | `POST /api/entities/custom/v1/relationships/list` | Read Lineage | Both writes return one `RelationshipWriteResult` per requested relationship, in request order, each with the resolved endpoints and an outcome of `CREATED`, `UPDATED`, `DELETED` or `NOT_FOUND`. At least one endpoint must be a custom entity. ### Check relationships `synq.entities.custom.v1.ChecksRelationshipsService` | Method | REST | Scope | | - | - | - | | `UpsertCheckRelationships` | `POST /api/entities/custom/v1/check-relationships` | Edit Entities | | `DeleteCheckRelationships` | `DELETE /api/entities/custom/v1/check-relationships` | Edit Entities | | `ListCheckRelationships` | `POST /api/entities/custom/v1/check-relationships/list` | Read Entities | A `CheckRelationship` is `check` + `checked` + optional `checked_columns`. The pair is the identity; restating it with a different column list replaces the stored one. ### Executions `synq.entities.custom.v1.EntityExecutionsService` | Method | REST | Scope | | - | - | - | | `UpsertExecution` | `POST /api/entities/custom/executions/v1` | Edit Executions | | `UpsertLogEntry` | `POST /api/entities/custom/executions/v1/log-entry` | Edit Executions or Edit Execution Logs | `Execution` requires `id`, `status` and `created_at`. Status is one of `EXECUTION_STATUS_OK`, `_WARN`, `_ERROR`, `_CRITICAL`. `created_at` must be in the past and later than 2022-01-01. `extras` can carry the executed SQL. ## Read Reading back is how you verify a write landed. These are the methods worth calling. | Method | Service | REST | Scope | | - | - | - | - | | `BatchResolveIdentifiers` | `synq.entities.resolve.v1.IdentifierResolveService` | `POST /api/resolve/v1/by-id` | Read Entities | | `GetLineage` | `synq.entities.lineage.v1.LineageService` | `POST /api/lineage/v1` | Read Lineage | | `GetImpact` | `synq.entities.impact.v1.ImpactService` | `POST /api/impact/v1` | Read Lineage | | `GetSchema` | `synq.entities.schemas.v1.SchemasService` | `GET /api/schema/v1` | Read Entities | | `SearchEntities` | `synq.entities.entities.v1.EntitiesService` | `GET /api/entities/v1/search` | Read Entities | | `BatchGetEntities` | `synq.entities.entities.v1.EntitiesService` | `POST /api/entities/v1/by-id` | Read Entities | | `BatchGetEntityAnnotations` | `synq.entities.annotations.v1.AnnotationsService` | `POST /api/entities/annotations/v1/batchGet` | Read Entities | | `ListEntityTypeDefs` | `synq.entities.typedefs.v1.TypeDefsService` | `POST /api/entities/typedefs/v1/entity-types/list` | Read Entities or Read Entity Types | | `GetLatestExecutions` | `synq.entities.executions.v2.EntityExecutionsService` | see [API reference](/api-reference/api) | Read Executions | | `BatchIdsByCoordinates` | `synq.entities.coordinates.v1.DatabaseCoordinatesService` | `POST /api/coordinates/v1/database/by-fqn` | Read Entities | `BatchIdsByCoordinates` is how you turn a warehouse name your tool reports into the entity id Coalesce Quality holds for it — useful when your tool names tables as strings. `BatchResolveIdentifiers` turns an identifier of **any** shape into its `entity_id`, and with `check_existence: true` reports whether the entity exists. It also returns the entity's whole **identity group** — the other identifiers naming the same entity, such as a dbt model and the warehouse table it builds. Run it over the upstreams your integration is about to name. A **custom** entity that does not exist is rejected at the write, so you find that one either way; an entity on a **connected platform** is not checked and binds on next ingestion, so a typo'd warehouse name and a not-yet-crawled table look identical afterwards. Resolving separates them. The read methods above are meant to be driven from your integration as input, not only used to verify a write. Resolving coordinates, schemas and type numbers at run time is what keeps a mapping from drifting against a hardcoded table of ids. ## Identifiers A custom entity is named by `CustomIdentifier`: ```json theme={null} { "custom": { "id": "metabase::question::87" } } ``` The `id` is a **slug**, not a label: keep it to a lowercase `A-Z a-z 0-9 : _ . -` string built from the source system's stable id, and put everything human-readable in `name` and `description`. On write it is truncated at 200 bytes with a hash tail if longer, non-ASCII is replaced by its literal escape text, and every other character is folded to `_` — so two ids differing only in folded characters are **the same entity**, while ids differing only in case are **two**. The stored id is `custom-`. Entities from connected platforms are named by their platform's own variant — `bigquery_table`, `snowflake_table`, `databricks_table`, `postgres_table`, `mysql_table`, `clickhouse_table`, `redshift_table`, `trino_table`, `mssql_table`, `oracle_table`, `athena_table`, `fabric_table`, `dbt_core_node`, `dbt_cloud_node`, `sql_mesh_model`, `sql_mesh_audit`, `airflow_dag`, `airflow_task`, `monitor`, `dataproduct`, `saved_view`. Prefer these wherever one exists for the platform. `synq_path` is the fallback variant, for a platform with no structured form — Looker, Tableau, Coalesce Catalog and anything added since — or for passing through an `entity_id` you already hold. Every identifier the API **returns** also carries `entity_id`, the entity's opaque id, and it is the `/catalog/` segment of the entity's app URL. It is output only: on a request it is ignored, and the structured variant is what resolves. To name an entity by opaque id on a request, put it in the `synq_path` variant. Ways to obtain an `entity_id`: the app URL after `/catalog/`, the [MCP read tools](/scout/mcp), the `entity_url` in a [webhook payload](/api-reference/webhook), or `BatchIdsByCoordinates`. ## Enums **`SqlDialect`** — `BIGQUERY`, `CLICKHOUSE`, `DATABRICKS`, `MYSQL`, `POSTGRESQL`, `REDSHIFT`, `SNOWFLAKE`, `DUCKDB`, `TRINO`, `MSSQL`, `ORACLE`, `ATHENA`, `FABRIC`. **`CodeType`** — `SQL`, `PYTHON`, `JSON`, `YAML`, `DBT`, `SQLMESH`, `LOOKML`, `JAVASCRIPT`, `BASH`, `DAX`, `JAVA`, `SCALA`, `TEXT`, `MARKDOWN`. ## Pagination The `List*` methods on the custom services take an optional `Pagination`. Omitting it, or sending a zero `page_size`, returns everything in one response — there is no server-side default page size. To page, set `page_size` and pass the previous response's `page_info.last_id` as `pagination.cursor`, until `last_id` comes back empty. Not every list paginates: `ListEntityTypeDefs`, `ListExecutionTypeDefs` and `ListPlatformDefs` take no pagination at all and always return the full set. ## Idempotency Every `Upsert*` and `Delete*` method here is idempotent in **effect**: re-sending the same state converges on the same result, and deleting something that does not exist succeeds. It is not a no-op on the wire. An upsert always writes, restamping `updated_at` and re-triggering the fan-out that write implies, so a re-sync is not free — send it on a schedule, not in a tight loop. # Building an Integration Source: https://docs.synq.io/custom-integrations/building-an-integration From credentials to a verified graph: the steps a custom integration runs, in order, in Go and Python A custom integration is a program that reads your tool and writes what it finds to the Coalesce Quality API. It is **idempotent** — running it twice produces the same estate — so it is a cron job, not a migration. Every snippet below is taken from the runnable examples in [getsynq/api/examples](https://github.com/getsynq/api/tree/main/examples). Pick a language in any code block and the rest of the page follows. The complete program these come from is [`bi_tool_lineage`](https://github.com/getsynq/api/tree/main/examples/golang/bi_tool_lineage) ([Python](https://github.com/getsynq/api/tree/main/examples/python/bi_tool_lineage)) — a whole BI tool modelled end to end, run against a live workspace. ## Credentials Create client credentials in API settings — `/settings/api` in your own app, which is `app.synq.io` for EU, `app.us.synq.io` for US and `app.au.synq.io` for AU. Grant these scopes: | Scope | Needed for | | - | - | | **Edit Entity Types** | Step 1 | | **Edit Entities** | Steps 2, 3, 4, 6, 7 | | **Edit Lineage** | Step 5 | | **Edit Executions** | Step 8 | | **Read Entities**, **Read Entity Types**, **Read Lineage** | Steps 1 and 9 | [Getting Started](/api-reference/getting-started) covers exchanging them for an access token and generating or installing a client — follow it rather than the short version, it is generated from the API itself and stays current. Your region's API endpoint is in the [region table](/security/ip). What is specific to this guide is the environment it expects and the gRPC channel: ```bash Go theme={null} export QUALITY_CLIENT_ID=... export QUALITY_CLIENT_SECRET=... export QUALITY_API_ENDPOINT=... # your region's API endpoint go get buf.build/gen/go/getsynq/api/grpc/go go get buf.build/gen/go/getsynq/api/protocolbuffers/go ``` ```bash Python theme={null} export QUALITY_CLIENT_ID=... export QUALITY_CLIENT_SECRET=... export QUALITY_API_ENDPOINT=... # your region's API endpoint pip install grpcio protobuf requests pip install getsynq-api-protocolbuffers-python getsynq-api-grpc-python \ --extra-index-url https://buf.build/gen/python ``` Send the token as `authorization: Bearer ` on every call and refresh it when `expires_in` elapses. **Set the gRPC authority explicitly** — without it the port travels in the `Host` header and every RPC returns `UNIMPLEMENTED` with no message, which reads as a missing service rather than a routing miss: ```go Go theme={null} import ( "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/oauth" ) cfg := clientcredentials.Config{ ClientID: os.Getenv("QUALITY_CLIENT_ID"), ClientSecret: os.Getenv("QUALITY_CLIENT_SECRET"), TokenURL: "https://" + endpoint + "/oauth2/token", } conn, err := grpc.NewClient(endpoint+":443", grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), grpc.WithPerRPCCredentials(oauth.TokenSource{ TokenSource: cfg.TokenSource(ctx), }), // Required. Without it the port travels in the Host header and every RPC // comes back UNIMPLEMENTED with no message. grpc.WithAuthority(endpoint), ) ``` ```python Python theme={null} import grpc, requests, time class TokenSource: def __init__(self, client_id, client_secret, api_endpoint): self.token_url = f"https://{api_endpoint}/oauth2/token" self.client_id, self.client_secret = client_id, client_secret self.obtain_token() def obtain_token(self): resp = requests.post(self.token_url, data={ "client_id": self.client_id, "client_secret": self.client_secret, "grant_type": "client_credentials", }) resp.raise_for_status() self.token = resp.json() self.expires_at = time.time() + self.token["expires_in"] def get_token(self) -> str: if time.time() > self.expires_at: self.obtain_token() return self.token["access_token"] class TokenAuth(grpc.AuthMetadataPlugin): def __init__(self, source): self._source = source def __call__(self, context, callback): callback([("authorization", f"Bearer {self._source.get_token()}")], None) channel = grpc.secure_channel( f"{endpoint}:443", grpc.composite_channel_credentials( grpc.ssl_channel_credentials(), grpc.metadata_call_credentials(TokenAuth(TokenSource(cid, secret, endpoint))), ), # Required. Without an explicit authority the port travels in the Host # header and every RPC comes back UNIMPLEMENTED with no message. options=(("grpc.default_authority", endpoint),), ) ``` ## 1. Types One `UpsertType` per kind of thing your tool has. Declare [traits](/custom-integrations/modelling#2-entity-types-and-their-traits) — they decide how your entities rank, sort and behave platform-wide. ```go Go theme={null} types := []*entitiesv1.Type{ { TypeId: 31, Name: "Metabase Model", SvgIcon: iconLayers, Traits: &entitiesv1.TypeTraits{IsModel: proto.Bool(true)}, }, { TypeId: 32, Name: "Metabase Question", SvgIcon: iconChart, // A question transforms data AND is read by a person, so it is both. Traits: &entitiesv1.TypeTraits{IsModel: proto.Bool(true), IsBiLike: proto.Bool(true)}, }, { TypeId: 34, Name: "Metabase Alert", SvgIcon: iconWarning, // A check, not a stage data flows through. Traits: &entitiesv1.TypeTraits{IsTestType: proto.Bool(true)}, }, } for _, t := range types { if _, err := api.types.UpsertType(ctx, &customv1.UpsertTypeRequest{Type: t}); err != nil { return err } } ``` ```python Python theme={null} types = [ type_pb2.Type( type_id=31, name="Metabase Model", svg_icon=ICON_LAYERS, traits=type_traits_pb2.TypeTraits(is_model=True), ), type_pb2.Type( type_id=32, name="Metabase Question", svg_icon=ICON_CHART, # A question transforms data AND is read by a person, so it is both. traits=type_traits_pb2.TypeTraits(is_model=True, is_bi_like=True), ), type_pb2.Type( type_id=34, name="Metabase Alert", svg_icon=ICON_WARNING, # A check, not a stage data flows through. traits=type_traits_pb2.TypeTraits(is_test_type=True), ), ] for t in types: api.types.UpsertType(types_service_pb2.UpsertTypeRequest(type=t)) ``` Type numbers are `1`–`1000` and workspace-wide, with no allocator. Call `ListTypes` first and refuse to start if one of your numbers is taken under a different name — that is the only protection against two integrations picking the same band. ## 2. Entities One `UpsertEntity` per object. **Create every entity before anything points at one**: a SQL binding to an entity that does not exist is rejected at the write, and an entity group whose members do not all exist is not a set anyone can reconcile against. ```go Go theme={null} entity := &entitiesv1.Entity{ Id: customID("metabase::question::87"), TypeId: 32, Name: "Revenue by product category", Description: "Revenue split by category, last 90 days.", Annotations: []*entitiesv1.Annotation{ {Name: "metabase.collection", Values: []string{"Commercial"}}, {Name: "metabase.kind", Values: []string{"question"}}, }, } _, err := api.entities.UpsertEntity(ctx, &customv1.UpsertEntityRequest{Entity: entity}) ``` ```python Python theme={null} entity = entity_pb2.Entity( id=custom_id("metabase::question::87"), type_id=32, name="Revenue by product category", description="Revenue split by category, last 90 days.", annotations=[ annotation_pb2.Annotation(name="metabase.collection", values=["Commercial"]), annotation_pb2.Annotation(name="metabase.kind", values=["question"]), ], ) api.entities.UpsertEntity(entities_service_pb2.UpsertEntityRequest(entity=entity)) ``` Where `customID` builds the identifier: ```go Go theme={null} func customID(id string) *entitiesv1.Identifier { return &entitiesv1.Identifier{ Id: &entitiesv1.Identifier_Custom{ Custom: &entitiesv1.CustomIdentifier{Id: id}, }, } } ``` ```python Python theme={null} def custom_id(id_: str) -> identifier_pb2.Identifier: return identifier_pb2.Identifier(custom=identifier_pb2.CustomIdentifier(id=id_)) ``` **The id is a slug; the readable text belongs in `name`.** Keep it to a lowercase `A-Z a-z 0-9 : _ . -` slug built from the source system's stable id. Anything else is folded on write — `metabase/question/87` and `metabase question 87` are **the same entity** — and ids are case-sensitive, so a capital makes a different one. `name` takes 500 characters of any UTF-8, which is where the title, the accents and the spaces go. See [Entity ids](/custom-integrations/modelling#1-entity-ids). To point at an entity from a connected platform, use that platform's own identifier variant rather than `custom`: ```go Go theme={null} &entitiesv1.Identifier{ Id: &entitiesv1.Identifier_BigqueryTable{ BigqueryTable: &entitiesv1.BigqueryTableIdentifier{ Project: cfg.project, Dataset: cfg.dataset, Table: "order_items", }, }, } ``` ```python Python theme={null} identifier_pb2.Identifier( bigquery_table=identifier_pb2.BigqueryTableIdentifier( project=cfg.project, dataset=cfg.dataset, table="order_items", ) ) ``` Where the platform has no structured variant, or you already hold the entity's opaque `entity_id`, use the `synq_path` variant instead — see [Finding the entity\_id](/custom-integrations/modelling#finding-the-entity-id-of-an-existing-entity). Annotations are your tool's own filing system carried across, so the catalog can be filtered the way the tool is browsed. Keep them to labels a person would pick out of a list; prose belongs in the description, which accepts Markdown. ## 3. Schemas Declare columns **before** any lineage step. A `SELECT *` expands only over an entity whose columns are known, and a declared column edge only shows against a column the entity has. Skip this and the table-level edges still appear, with nothing saying the column ones are missing. ```go Go theme={null} schema := &customfeaturesv1.Schema{StateAt: timestamppb.Now()} for i, c := range columns { schema.Columns = append(schema.Columns, &entitiesv1.SchemaColumn{ Name: c.name, NativeType: c.nativeType, Description: c.desc, OrdinalPosition: int32(i + 1), }) } _, err := api.features.UpsertEntityFeature(ctx, &customv1.UpsertEntityFeatureRequest{ Feature: &customv1.Feature{ EntityId: customID("metabase::question::87"), // One schema feature per entity, so the id is a constant. Never generate // it — a fresh id on every run creates a new feature each time instead // of replacing the previous one. FeatureId: "schema", Feature: &customv1.Feature_Schema{Schema: schema}, }, }) ``` ```python Python theme={null} schema = schema_pb2.Schema( state_at=now(), columns=[ entities_schema_pb2.SchemaColumn( name=c.name, native_type=c.native_type, description=c.desc, ordinal_position=i + 1, ) for i, c in enumerate(columns) ], ) api.features.UpsertEntityFeature( features_service_pb2.UpsertEntityFeatureRequest( feature=features_service_pb2.Feature( entity_id=custom_id("metabase::question::87"), # One schema feature per entity, so the id is a constant. Never # generate it — a fresh id on every run creates a new feature each # time instead of replacing the previous one. feature_id="schema", schema=schema, ) ) ) ``` ## 4. Lineage features ### SqlDefinition, with bindings The mechanism to reach for first. Give the SQL as the tool executes it, plus the dialect and a `database_context` for unqualified names. A name in the SQL that is **not a warehouse object** — another custom entity, a queue, a service — resolves to nothing and is silently dropped. `references` binds such a name to the entity it stands for. Names that *are* warehouse objects need no binding. ```go Go theme={null} _, err := api.features.UpsertEntityFeature(ctx, &customv1.UpsertEntityFeatureRequest{ Feature: &customv1.Feature{ EntityId: customID("metabase::question::87"), FeatureId: "sql", Feature: &customv1.Feature_SqlDefinition{ SqlDefinition: &customfeaturesv1.SqlDefinition{ StateAt: timestamppb.Now(), Dialect: entitiesv1.SqlDialect_SQL_DIALECT_BIGQUERY, Sql: question.sql, DatabaseContext: warehouseContext(cfg), References: []*customfeaturesv1.SqlTableReference{{ // The name exactly as the SQL writes it. Matched // case-insensitively; leave database_name and schema_name // empty to default them from database_context. ObjectName: "order_items_enriched", Entity: customID("metabase::model::31"), }}, }, }, }, }) ``` ```python Python theme={null} api.features.UpsertEntityFeature( features_service_pb2.UpsertEntityFeatureRequest( feature=features_service_pb2.Feature( entity_id=custom_id("metabase::question::87"), feature_id="sql", sql_definition=sql_definition_pb2.SqlDefinition( state_at=now(), dialect=sql_dialect_pb2.SQL_DIALECT_BIGQUERY, sql=question.sql, database_context=warehouse_context(cfg), references=[ sql_definition_pb2.SqlTableReference( # The name exactly as the SQL writes it. Matched # case-insensitively; leave database_name and schema_name # empty to default them from database_context. object_name="order_items_enriched", entity=custom_id("metabase::model::31"), ) ], ), ) ) ) ``` The bindings are part of the definition and replace with it: one dropped from a later write is gone, and the lineage it produced is withdrawn. ### ColumnLineage For a component with no SQL at all. State each edge outright. The declaration is complete and replaces the previous one whole, so regenerate it from your tool's metadata every run rather than diffing. ```go Go theme={null} var edges []*customfeaturesv1.ColumnEdge for _, card := range dashboard.cards { edges = append(edges, &customfeaturesv1.ColumnEdge{ Upstream: customID(fmt.Sprintf("metabase::question::%d", card.fromQuestion)), UpstreamColumn: card.fromColumn, // The two sides are named independently, so they need not match. Column: card.field, }) } _, err := api.features.UpsertEntityFeature(ctx, &customv1.UpsertEntityFeatureRequest{ Feature: &customv1.Feature{ EntityId: customID("metabase::dashboard::9"), // Only one column-lineage feature per entity, so a stable id is how it // is edited. FeatureId: "column-lineage", Feature: &customv1.Feature_ColumnLineage{ ColumnLineage: &customfeaturesv1.ColumnLineage{ StateAt: timestamppb.Now(), Edges: edges, }, }, }, }) ``` ```python Python theme={null} edges = [ column_lineage_pb2.ColumnEdge( upstream=custom_id(f"metabase::question::{c.from_question}"), upstream_column=c.from_column, # The two sides are named independently, so they need not match. column=c.field, ) for c in dashboard.cards ] api.features.UpsertEntityFeature( features_service_pb2.UpsertEntityFeatureRequest( feature=features_service_pb2.Feature( entity_id=custom_id("metabase::dashboard::9"), # Only one column-lineage feature per entity, so a stable id is how # it is edited. feature_id="column-lineage", column_lineage=column_lineage_pb2.ColumnLineage(state_at=now(), edges=edges), ) ) ) ``` An upstream on a connected platform works the same way, and does not have to exist yet — the edge is remembered and appears once the entity is ingested. Declaring a column edge also declares the table edge it implies. ### Code and Git `Code` carries the SQL, Python, YAML or JSON behind the entity for display; several per entity. `GitFileReference` says where that code lives, so a connected [code integration](/code-integrations/overview) can show recent commits against the entity when it fails. ## 5. Relationships For edges with nothing to say at column grain. **Read the response** — an edge is held between the two entities the endpoints *resolve* to, so two relationships that look different can be the same edge, and only the last write survives. ```go Go theme={null} resp, err := api.relationships.UpsertRelationships(ctx, &customv1.UpsertRelationshipsRequest{ Relationships: []*customv1.Relationship{{ Upstream: customID("metabase::dashboard::9"), Downstream: customID("metabase::subscription::4"), }}, }) if err != nil { return err } for _, r := range resp.GetResults() { fmt.Printf("%s -> %s %s\n", r.GetRelationship().GetUpstream().GetEntityId(), r.GetRelationship().GetDownstream().GetEntityId(), r.GetOutcome(), ) } ``` ```python Python theme={null} resp = api.relationships.UpsertRelationships( relationships_service_pb2.UpsertRelationshipsRequest( relationships=[ relationships_service_pb2.Relationship( upstream=custom_id("metabase::dashboard::9"), downstream=custom_id("metabase::subscription::4"), ) ] ) ) for r in resp.results: outcome = relationships_service_pb2.RelationshipWriteOutcome.Name(r.outcome) print(f"{r.relationship.upstream.entity_id} -> " f"{r.relationship.downstream.entity_id} {outcome}") ``` ## 6. Checks Something that validates another entity is not a stage data flows through. Attach it with a check relationship, **then** give it a `CheckCategory` feature — attaching schedules no re-publish of the derived check record, while writing a feature does, so the reverse order leaves that record stale until the entity is written again. ```go Go theme={null} _, err := api.features.UpsertEntityFeature(ctx, &customv1.UpsertEntityFeatureRequest{ Feature: &customv1.Feature{ EntityId: customID("metabase::alert::12"), FeatureId: "check", Feature: &customv1.Feature_CheckCategory{ // category and governance_category are left unset on purpose: a // producer value outranks the workspace's categorisation rules. CheckCategory: &customfeaturesv1.CheckCategory{ Package: "metabase", Kind: alert.kind, }, }, }, }) _, err = api.checkRelationships.UpsertCheckRelationships(ctx, &customv1.UpsertCheckRelationshipsRequest{ CheckRelationships: []*customv1.CheckRelationship{{ Check: customID("metabase::alert::12"), Checked: customID("metabase::question::87"), CheckedColumns: []string{"revenue"}, }}, }) ``` ```python Python theme={null} api.features.UpsertEntityFeature( features_service_pb2.UpsertEntityFeatureRequest( feature=features_service_pb2.Feature( entity_id=custom_id("metabase::alert::12"), feature_id="check", # category and governance_category are left unset on purpose: a # producer value outranks the workspace's categorisation rules. check_category=checks_pb2.CheckCategory(package="metabase", kind=alert.kind), ) ) ) api.check_relationships.UpsertCheckRelationships( checks_relationships_service_pb2.UpsertCheckRelationshipsRequest( check_relationships=[ checks_relationships_service_pb2.CheckRelationship( check=custom_id("metabase::alert::12"), checked=custom_id("metabase::question::87"), checked_columns=["revenue"], ) ] ) ) ``` **Leave `category` and `governance_category` unset.** They are resolved by your workspace's own [categorisation rules](/analytics/check-categories), and a value sent by a producer outranks those rules. Deriving one from your tool's alert kind — the obvious thing to do — silently switches off every rule the workspace wrote, and nothing in the product explains why. ## 7. The entity group One group naming **every entity your integration owns**, every run. The server diffs it against the previous set and deletes what is missing, so an object deleted in your tool disappears from the catalog with no state kept on your side. ```go Go theme={null} ids := everyEntity() // the FULL set, every run resp, err := api.groups.UpsertEntitiesGroup(ctx, &customv1.UpsertEntitiesGroupRequest{ Group: &customv1.Group{GroupId: "metabase", EntityIds: ids}, }) if err != nil { return err } for _, deleted := range resp.GetDeletedIds() { fmt.Printf("deleted (gone from the tool): %s\n", deleted.GetCustom().GetId()) } ``` ```python Python theme={null} ids = every_entity() # the FULL set, every run resp = api.groups.UpsertEntitiesGroup( groups_service_pb2.UpsertEntitiesGroupRequest( group=groups_service_pb2.Group(group_id="metabase", entity_ids=ids) ) ) for deleted in resp.deleted_ids: print(f"deleted (gone from the tool): {deleted.custom.id}") ``` **A partial send is a deletion of everything omitted.** If reading your tool can fail halfway, skip the group write for that run and let the next complete one reconcile. **A group deletes entities only** — not the features, relationships or check relationships of entities that still exist. A repointed dashboard, a removed check or a stale `SqlDefinition` survives the group write and stays in the graph. So each run also reconciles what the last one wrote: read the current state with `ListEntityFeatures` (leave `entity_id` unset for the whole workspace), `ListRelationships` and `ListCheckRelationships`; diff it against what you are about to write; then call `DeleteEntityFeature`, `DeleteRelationships` and `DeleteCheckRelationships` for what is gone — **before** the group write, so no edge is left pointing at an entity that is about to go. ## 8. Executions What gives a custom entity a status rather than just a position in a graph. `created_at` is required and must be in the past, so a run that has not happened yet is simply not reported. ```go Go theme={null} _, err := api.executions.UpsertExecution(ctx, &customv1.UpsertExecutionRequest{ Execution: &customv1.Execution{ Id: customID("metabase::dashboard::9"), Status: customv1.ExecutionStatus_EXECUTION_STATUS_OK, Message: "All cards refreshed.", CreatedAt: timestamppb.New(finished), StartedAt: timestamppb.New(started), FinishedAt: timestamppb.New(finished), }, }) ``` ```python Python theme={null} api.executions.UpsertExecution( entity_executions_service_pb2.UpsertExecutionRequest( execution=entity_executions_service_pb2.Execution( id=custom_id("metabase::dashboard::9"), status=entity_executions_service_pb2.EXECUTION_STATUS_OK, message="All cards refreshed.", created_at=finished, started_at=started, finished_at=finished, ) ) ) ``` Status is `OK`, `WARN`, `ERROR` or `CRITICAL`. `UpsertLogEntry` attaches log output without changing status. ## 9. Read it back Every way a custom integration goes wrong produces a valid-looking write and an empty graph, and the write side cannot tell the difference. End the program by reading its own lineage back. Lineage is computed asynchronously, so poll. ```go Go theme={null} depth := int32(10) resp, err := api.lineage.GetLineage(ctx, &lineagev1.GetLineageRequest{ LineageDirection: lineagev1.LineageDirection_LINEAGE_DIRECTION_UPSTREAM, StartPoint: &lineagev1.GetLineageStartPoint{ From: &lineagev1.GetLineageStartPoint_Entities{ Entities: &lineagev1.EntitiesStartPoint{ Entities: []*entitiesv1.Identifier{customID("metabase::dashboard::9")}, }, }, }, MaxDepth: &depth, }) if err != nil { return err } lin := resp.GetLineage() if len(lin.GetNodeDependencies()) == 0 { return fmt.Errorf("no upstream lineage: the writes landed but nothing resolved") } for _, d := range lin.GetNodeDependencies() { fmt.Printf("%s -> %s\n", nodeName(lin.GetNodes()[d.GetSourceNodeIdx()]), nodeName(lin.GetNodes()[d.GetTargetNodeIdx()]), ) } ``` ```python Python theme={null} resp = api.lineage.GetLineage( lineage_service_pb2.GetLineageRequest( lineage_direction=lineage_direction_pb2.LINEAGE_DIRECTION_UPSTREAM, start_point=lineage_service_pb2.GetLineageStartPoint( entities=lineage_service_pb2.EntitiesStartPoint( entities=[custom_id("metabase::dashboard::9")] ) ), max_depth=10, ) ) lin = resp.lineage if not lin.node_dependencies: raise RuntimeError("no upstream lineage: the writes landed but nothing resolved") for d in lin.node_dependencies: print(f"{node_name(lin.nodes[d.source_node_idx])} -> " f"{node_name(lin.nodes[d.target_node_idx])}") ``` A node carries every identifier that resolves to it, so `nodeName` picks the shape that says what the node *is* — prefer the `custom` variant when present. Check for the edges you expect, not merely that some edge came back. A declared column edge naming a column the upstream does not have still produces one hop while the rest of the chain is lost, so a non-empty result can still be a broken graph. Poll with a deadline, and exit non-zero when it expires rather than logging and returning. For column-level lineage, start from `EntityColumnsStartPoint` instead, naming the entity and the columns. The response then populates `column_dependencies`, and each node's `cll_details.cll_state` says whether the parse succeeded. A state of `RESOLUTION_FAILED` on a node is usually a name your `SqlDefinition` should have bound and did not. This is not a first-version-only step. Keep it in the production integration. ## Checklist before you ship * Ids are lowercase slugs from the source system's stable id, in `A-Z a-z 0-9 : _ . -` * The title and any other human-readable text is in `name`, never in an id * Every type declares its traits, and its number was checked with `ListTypes` first * Every entity with columns declares its schema, before any lineage is written * Every name in a `SqlDefinition` that is not a warehouse object has a binding * Every upstream resolves, checked with `BatchResolveIdentifiers` (`check_existence: true`) * Check entities send `package` and `kind`, and leave both categories unset * One group holds everything, sent whole on every run, never from a partial read * `feature_id` values are stable strings, not generated per run * The program reads its own lineage back and fails loudly when it is missing ## Next Every method, the scope it needs, and the limits A page to point a coding agent at, so it writes the integration for you # Modelling Your Tool Source: https://docs.synq.io/custom-integrations/modelling Choosing entity types, traits and the right lineage mechanism for each hop in your tool's graph Before writing any code, four decisions. They are listed in order of how expensive they are to get wrong. ## 1. Entity ids Every entity is named by a `CustomIdentifier` — one string, unique within your workspace. **Treat it as a slug, not a label.** It is a machine identifier: something a URL, a log line and a config file can all carry unchanged. Everything a person reads goes in `name` and `description`, which are separate fields and have no such restriction. ``` id metabase::question::87 name Revenue by product category — EMEA, Q3 ``` The id never has to carry the title. The catalog shows `name`, which takes up to 500 characters of any UTF-8 you like: accents, punctuation, spaces, the tool's own wording. The id only has to be stable and unique. ### Building the slug Two rules, and a third worth adopting. **Build it from the source system's stable id, never from a title.** Everything hangs off the id: lineage edges, schemas, executions, check relationships, ownership, a saved view somebody built. Changing an id does not rename an entity — it creates a second one and orphans the first. A title changes; a primary key does not. **Restrict it to `A-Z a-z 0-9 : _ . -`.** That is the alphabet the platform preserves verbatim. `::` is its conventional separator, and `.`, `-` and `_` pass through untouched. A prefix naming the tool and the object kind keeps two integrations in one workspace from colliding, and keeps ids legible in a URL. **Lowercase everything.** Ids are case-sensitive, so `Metabase::Question::87` and `metabase::question::87` are two separate entities. Nothing warns you. Lowercasing at the one place you build ids removes the whole class of bug, and costs nothing — the readable form lives in `name` regardless. ``` metabase::question::87 good — stable id, safe alphabet, lowercase metabase::Revenue by category bad — a title, a space, and a capital ``` ### What happens if you ignore this The string you send is not stored verbatim. Three things happen to it, in order: 1. It is truncated at **200 bytes**, with the tail replaced by a hash of the whole input so two long ids sharing a prefix do not collapse into one. 2. Non-ASCII characters are replaced by their literal escape text, so `zamówienia` becomes `zam_u00f3wienia`. 3. Every character outside `A-Z a-z 0-9 : _ . -` is folded to `_`. **Two ids that differ only in folded characters become the same entity.** `metabase/question/87` and `metabase question 87` both normalise to `metabase_question_87` — one entity, silently, with the second write overwriting the first. Slashes, spaces, `#`, `@`, `+` and `~` all fold. So does every accented character, into an escape sequence nobody wants to read. Put that text in `name`, where it belongs and where it survives intact. The stored id is your slug prefixed with `custom-`, and that is what the API returns as `entity_id`: ``` you send metabase::question::87 stored as custom-metabase::question::87 ``` ### Finding the entity\_id of an existing entity Custom lineage points at entities that already exist — warehouse tables, dbt models, dashboards. **Always prefer the structured variant for the platform**: `bigquery_table`, `snowflake_table`, `dbt_core_node` and the rest name an entity in the terms the platform itself uses, which is what makes them readable, stable and checkable. `synq_path` is the fallback. Reach for it in two cases: the platform has no structured variant (Looker, Tableau, Coalesce Catalog and anything added since are addressable only this way), or you already hold the entity's opaque `entity_id` and would rather pass it through than take it apart. Four ways to get one: * **From the app URL.** The catalog page for an entity is `/catalog//overview`, where the app host is your region's (`app.synq.io`, `app.us.synq.io`, `app.au.synq.io`). In `https://app.synq.io/catalog/ch-nogwv291ou.europe_west4.gcp.clickhouse.cloud::default::runs/overview` the id is `ch-nogwv291ou.europe_west4.gcp.clickhouse.cloud::default::runs`. * **From the MCP server.** `search_entities` and the other read tools return entities with their ids — see [Scout MCP](/scout/mcp). * **From a webhook payload.** Every entity in an event carries its `identifier` and an `entity_url` whose `/catalog/` segment is the id — see [Webhooks](/api-reference/webhook). * **From the API.** Every identifier the API *returns* carries `entity_id`, and `BatchIdsByCoordinates` turns a warehouse name into the ids that match it. `entity_id` is output only. On a request it is ignored and the structured variant is what resolves, so to name an entity *by* its opaque id, set the `synq_path` variant to that string. ### Resolve identifiers before you write lineage `BatchResolveIdentifiers` (`synq.entities.resolve.v1`) turns any identifier — of any shape — into its `entity_id`, and with `check_existence: true` tells you whether the entity is actually there. **The two kinds of upstream behave differently, and this is what tells them apart:** * A **custom** entity that does not exist is **rejected** at the write. Nothing else would report a misspelled custom id, so the API refuses rather than accepting a declaration that produces nothing. * An entity on a **connected platform** is not checked. It binds when that platform is next ingested, so an edge written before the table is crawled is correct and is remembered. That second case is the one to resolve up front: a not-yet-ingested table and a typo'd warehouse name are indistinguishable from the lineage you get back. It also answers a question the write API cannot. A single entity is reachable by several identifiers — a dbt model and the warehouse table it builds are **one identity**, named two ways. `BatchResolveIdentifiers` returns the whole identity group in `identities` and `identity_synq_paths`, so you can tell that two identifiers you were treating as different upstreams are the same entity, before writing two relationships that turn out to be one edge. ### The read API is input, not just verification A custom integration does not only write. The public API's read surface is there to be driven from your integration, and using it is usually the difference between a mapping that guesses and one that resolves: * **`BatchIdsByCoordinates`** — your tool reports a table as a string like `analytics.order_items`. This maps warehouse coordinates to the entity ids that match, so you can bind a name without hardcoding which warehouse it lives in. * **`SearchEntities`** and **`ListEntities`** — find the entity your tool's metadata refers to when it gives you a name rather than an address. * **`GetSchema`** — read an upstream's real columns, so the column lineage you declare names columns that exist rather than columns your tool believes exist. * **`ListEntityTypeDefs`** and **`ListTypes`** — what types the workspace already has, which is how you avoid claiming a type number another integration is using. * **`Browse`** and **`GetFolderOf`** — where entities sit in the workspace's folder tree. Treat these as the configuration input for the mapping, resolved at run time, rather than building a static table of ids into your integration and watching it drift. ## 2. Entity types and their traits A type is a kind of thing in your tool. It carries a short name, an SVG icon, and a set of **traits** that every entity of the type inherits. | Trait | Declares that entities of this type are | Effect | | - | - | - | | `is_model` | transformation models, the dbt-model analog | Canonical-entity ranking, monitorability, lineage treated as a transformation stage | | `is_source` | raw external inputs to the graph | Ranked and rendered as a source | | `is_bi_like` | dashboards, reports, other BI artifacts | Treated as a consumption endpoint | | `is_test_type` | checks, pairing with declarative checks | Participates in coverage and check reporting | | `is_ignored_in_lineage` | infrastructure you do not want drawn | Excluded from lineage rendering | Traits are the difference between a catalog that understands your tool and one that merely lists it. A type with no traits still appears everywhere, but it does not rank against dbt models when Coalesce Quality picks a canonical entity, and it will not be offered where a model is expected. Types are numbered `1`–`1000` per workspace, and the number is the identity — reusing one redefines the type. Keep a table of them in your integration's source. ## 3. Which lineage mechanism This is the decision that repays thinking. Coalesce Quality offers four, and the right one depends on what the hop actually has. | You have | Use | Why | | - | - | - | | SQL, over real warehouse tables | `SqlDefinition` | Both table and column grain are derived from the SQL, and stay correct when the SQL changes | | SQL, naming something the warehouse cannot address | `SqlDefinition` + `references` | The binding says what the name means; everything else is derived as usual | | Rows copied between two tables you already have (replication, CDC, a loader) | An entity for the copy, with `SqlDefinition` + `references` | Column grain across the hop, even when the two tables are in different warehouses | | No SQL, but you know the column mapping | `ColumnLineage` | Declare the answer instead of deriving one | | No SQL and no columns | `Relationship` | The edge is real; there is nothing to say at column grain | | Something that validates another entity | `CheckCategory` + a check relationship | A check is not a stage data flows through | **Reach for `SqlDefinition` first.** A declaration is a snapshot of what was true when it was written; a parse follows the query. Every other mechanism is for what SQL cannot say. ### SqlDefinition Give the SQL as the tool actually executes it, plus the dialect. Coalesce Quality parses it and derives table-level and column-level lineage. ``` dialect: SQL_DIALECT_BIGQUERY sql: SELECT customer_id, SUM(net_revenue) AS revenue FROM analytics.order_items_enriched GROUP BY 1 ``` `database_context` supplies the instance, database and schema that unqualified names in the SQL resolve against — the same defaults the warehouse itself would apply. ### SqlDefinition references — the binding A `SqlDefinition` resolves names that live at a warehouse address. Anything else — another custom entity, a queue, a service, an API, a saved query in a BI tool — has no address, so `FROM order_items_enriched` matches nothing and is dropped. **There is no error for this.** An empty result looks exactly like a query that genuinely reads nothing, which is why it is the most common way a custom integration ships broken. `SqlDefinition.references` binds the name, as the SQL writes it, to the entity it stands for. Three consequences: * **A binding beats the warehouse.** If a real table shared the name, the binding still wins — which is what makes it usable as a deliberate override. * **Empty parts default from `database_context`**, exactly as an unqualified name in the SQL does. A binding of just `object_name: "orders_topic"`, under a definition whose database is `kafka`, matches both `FROM kafka.orders_topic` and `FROM orders_topic`. * **Names that *are* warehouse objects need no binding.** One definition can read a bound custom entity and a raw warehouse table in the same query, binding only the first. Matching is case-insensitive. The bindings are part of the definition and replace with it: a binding dropped from a later write is gone, and the lineage it produced is withdrawn. ### A copy between two tables you already have A replication tool, a CDC pipeline or your own loader copies a table into another database or warehouse. Both tables are already in Coalesce Quality; the hop between them is not. Model the copy itself as a custom entity, **one per copied table**. It is what fails, lags or drops a column, so it is where an incident belongs. One entity for a whole connection would make every source table upstream of every target table it writes. Give that entity a `SqlDefinition` describing the copy, and bind **both** table names: ``` dialect: SQL_DIALECT_POSTGRESQL sql: INSERT INTO target_table (id, customer_id, total_amount) SELECT id, customer_id, total FROM source_table references: source_table -> the source table's identifier target_table -> the target table's identifier ``` * **The SQL is parsed, never run.** `source_table` and `target_table` are placeholders that only have to match the references. A bound name resolves straight to its entity, on whichever platform that is, so the source and the target can be in different warehouses. Use the source side's dialect. * **Write the column list on the `INSERT`.** It pairs each selected column with its target column, renames included. The lineage runs source column → copy → target column. * **No relationships are needed.** The same definition gives the table-level edges too. [`replication_lineage`](https://github.com/getsynq/api/tree/main/examples/golang/replication_lineage) is a runnable example. ### ColumnLineage For a component with no SQL for a parser to read — a transformation written in Python, a hand-maintained mapping, a dashboard field assembled by the tool's own engine. You state each edge: upstream entity, upstream column, this entity's column. ``` upstream = metabase::question::87, upstream_column = revenue, column = revenue ``` Three things to know: * **It replaces whole.** An edge missing from a write is withdrawn, and deleting the feature withdraws all of them. Only one `ColumnLineage` per entity, so re-writing it under the same `feature_id` is how it is edited. * **A column edge declares the table edge it implies.** The entity appears downstream of each upstream named here whether or not a `Relationship` also says so. * **It wins over `SqlDefinition`.** An entity with both is served from the declaration in the SQL-lineage view — an explicit statement outranks a derived one. So declare here only what the SQL cannot say, or state the entity's whole column lineage here and treat it as the authority. `state_at` defaults to now; set it explicitly when backfilling so an older declaration does not overwrite a fresher one. ### Relationship A plain upstream/downstream edge between two entities, with nothing said at column grain. Use it where there genuinely are no columns — a subscription, an export job, a notification. Relationships join a custom entity to another custom entity, or a custom entity to a native one. **Two native entities cannot be joined** — their lineage comes from their own integrations. When your tool is what moves data between two of them, model it as described in [A copy between two tables you already have](#a-copy-between-two-tables-you-already-have). An edge is held between the two *entities* the endpoints resolve to, not between the identifiers as written, and one entity accepts several spellings. The write response reports the resolved pair and what the write did (`CREATED`, `UPDATED`, `DELETED`, `NOT_FOUND`) — read it rather than assuming, because two relationships that resolve to the same pair are one edge and only the last write survives. ### Checks Something that validates another entity is not a stage data flows through, so it does not get a lineage edge. Give the entity a `CheckCategory` feature and attach it with a **check relationship**, optionally naming the columns it covers. ``` package: "metabase" grouping of check kinds kind: "alert" what kind of check this is, in your tool's own words ``` **Write the check relationship before the `CheckCategory` feature.** Attaching a check schedules no re-publish of its derived record, while writing a feature does — so doing it the other way round leaves the check's stored state stale until the entity is written again. **Leave `category` and `governance_category` unset.** They are resolved by your workspace's own [categorisation rules](/analytics/check-categories), and a value sent by a producer outranks those rules. Deriving one from your tool's alert kind — the obvious thing to do — silently switches off every rule the workspace wrote, and nothing in the product explains why. Send `package` and `kind`, which is what your tool actually says, and let the rules decide. ## 4. Declare the schema, or lose the column grain silently Declare every entity's columns before anything reads them. This is the step most easily skipped and the most expensive to skip: a `SELECT *` over a bound entity expands only over an entity whose columns are known. Skip it and the table-level edges still appear, with only the column-level ones missing and nothing saying so. **A declared `ColumnLineage` edge is not checked against the upstream's schema.** The read joins on the column names the two sides state, so a typo in `upstream_column` is accepted and produces a broken hop rather than an error — the edge exists, and the chain beyond it does not. Declaring the schema does not protect you here; reading the lineage back is what catches it. Columns carry a name, a native type, a description, an ordinal position, and may nest for struct and repeated types. Give ordinal positions for all columns or for none — when absent they follow list order. ## Reading the graph back Every way this goes wrong produces a valid-looking write and an empty graph. The two are indistinguishable from the write side, so a custom integration ends by reading its own lineage back and checking it is there. Lineage is computed asynchronously, so the read polls. This is worth keeping in the production integration, not just in the first version. ## Next The walkthrough, in order, with the code Every method, scope and limit # Custom Integrations Source: https://docs.synq.io/custom-integrations/overview Put a tool Coalesce Quality has no integration for into the catalog yourself, with lineage, schemas, checks and run status Coalesce Quality ships integrations for warehouses, dbt, SQLMesh, orchestrators, BI tools and catalogs. This section is about everything else: a tool you built in-house, one you are piloting, a streaming platform, a reverse-ETL job, a machine learning pipeline, an internal service that reads a table and writes a file. You describe it over the public API, and it becomes a first-class part of the catalog — it appears in lineage, carries a schema, has a status, is covered by checks, and can be owned, alerted on and put in a data product like anything else. ## What you can express | Concept | What it is | | - | - | | **Entity type** | A kind of thing in your tool — `Kafka Topic`, `Feature View`, `Notebook`. Carries an icon and behavioural traits | | **Entity** | One instance of that kind: a slug id for machines, plus a name, description and annotations for people | | **Schema** | The columns the entity has, so column-level lineage and column-level checks can reach it | | **Lineage** | What flows into it: derived from SQL, declared column by column, or stated as a plain edge | | **Executions** | The runs of the entity, so it has a health status rather than just a position in a graph | | **Checks** | Entities that validate other entities, attached to what they check | | **Code** | The SQL, Python or configuration behind the entity, and the file in Git it lives in | | **Group** | The set of entities your integration owns, which is what makes deletion work | ## When you need one Reach for a custom integration when the thing you care about is **not addressable in a warehouse**. If it has a table name, Coalesce Quality can already see it through the warehouse integration, and the more direct routes are the ones to use: * A **dbt** or **SQLMesh** project — use the [dbt](/dbt-integrations/dbt-core) or [SQLMesh](/sqlmesh-integrations/sqlmesh) integration. * **Airflow**, or any orchestrator that speaks OpenLineage — use the [orchestration integrations](/orchestration-integrations/airflow). * A **BI tool we support** — [Looker](/bi-integrations/looker), [Tableau](/bi-integrations/tableau), [Omni](/bi-integrations/omni). * **Tests you already run in the warehouse** — [SQL tests](/monitors/sql-tests) express those without any code. Everything else is a custom integration: a BI tool we have no connector for, a Kafka topic, an S3 export, a feature store, an internal API that serves a dataset, a Python job that transforms data outside SQL. ## What it looks like when it works A field on a dashboard that runs no SQL at all, in a tool with no integration, traced back to the physical warehouse columns it came from: ``` dashboard.revenue_by_category.revenue <- question.revenue <- model.net_revenue <- order_items.quantity <- order_items.unit_price <- order_items.discount ``` Three of those four hops use a different mechanism, because each hop has different information available. Choosing correctly per hop is the part worth thinking about; [Modelling your tool](/custom-integrations/modelling) is the decision. ## Where to go next Which lineage mechanism for which hop, what traits do, and the two mistakes that produce a valid-looking write and an empty graph The walkthrough: credentials, types, entities, features, groups, executions, verification Every service and method involved, the scope each one needs, and the limits Runnable Go and Python programs, including a whole BI tool modelled end to end ## Support Questions about modelling a tool of your own go to your Technical Account Manager — see [Support](/support/support). # 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 title * 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` title
* 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. title # 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. title ### 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)* title ### 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)) title * **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) ### Creating a data product programmatically The asset selection you build in the wizard is a membership query, and it can be written directly rather than clicked. * **Public API** — `synq.dataproducts.v2.DataproductsService` lists products, fetches one with its membership definition, resolves the assets currently in it, and upserts or deletes it. Reading needs a token with `SCOPE_DATAPRODUCT_READ`, writing needs `SCOPE_DATAPRODUCT_EDIT`. See the [API reference](/api-reference/api) and [API scopes](/api-reference/scopes). * **MCP** — the [data product tools](/scout/mcp#data-products) let an AI assistant review what exists, draft a membership query, and save the product once you approve. Reading is covered by read-only consent; saving and deleting need the Governance permission and are confirmation-gated. # 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* title *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. title 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**. dbt Core token management interface From the token management screen, you can: * Create new tokens for different environments * Invalidate compromised tokens * Copy token snippets for easy integration List of dbt Core integration tokens # 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 `catalog.json` is only written by `dbt docs generate`. `dbt run`, `dbt test` and `dbt build` don't produce it. See **Send catalog.json** below. **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} RUN wget -O /usr/bin/synq-dbt https://github.com/getsynq/synq-dbt/releases/latest/download/synq-dbt-amd64-linux && \ chmod +x /usr/bin/synq-dbt ``` `latest/download` always resolves to the newest release. To pin an image to a known version instead, replace it with `download/v2.1.0` — the tags are on the [releases page](https://github.com/getsynq/synq-dbt/releases). 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} wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/latest/download/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} RUN wget -O /usr/bin/synq-dbt https://github.com/getsynq/synq-dbt/releases/latest/download/synq-dbt-amd64-linux && \ chmod +x /usr/bin/synq-dbt ``` Swap `latest/download` for `download/v2.1.0` if you would rather the image pin a version. ### Linux/macOS **Download and install:** ```shell theme={null} # For Linux wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/latest/download/synq-dbt-amd64-linux # For macOS wget -O ./synq-dbt https://github.com/getsynq/synq-dbt/releases/latest/download/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. ## Send catalog.json None of the commands above write `catalog.json`. Add a separate `docs generate` step to the same job or DAG, after `run` or `build`: ```shell theme={null} synq-dbt build synq-dbt docs generate ``` `synq-dbt docs generate` runs `dbt docs generate`, which queries your warehouse and writes `catalog.json` to the target directory. `synq-dbt` then uploads it along with the other artifacts. With Airflow or Dagster, add `docs generate` as another `synq-dbt` command, the same way you run `build`. If you run plain `dbt docs generate` instead, upload the catalog afterwards from the same working directory with `synq-dbt synq_upload_artifacts`. If an upload doesn't include `catalog.json`, Coalesce Quality reuses the last catalog it received, but only if it is at most 7 days older than the upload's `manifest.json`. If there is no such catalog, the models are published without column types and descriptions, and the upload gets a recommendation to run `dbt docs generate`. After more than 30 days without a new catalog, the column information from the last one is no longer treated as current. It is replaced wherever the warehouse describes the same table. If you deliberately don't send `catalog.json`, turn on **Skip catalog.json warnings** in the integration's advanced settings. This only hides the recommendation. The 7-day and 30-day rules still apply. ## 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 `quality` configuration to your test's `meta` block: ```sql theme={null} {{ config( meta = { 'quality': {'check_category': 'e2e'} } ) }} ``` The original `synq` namespace remains supported permanently, so existing `meta: {synq: {check_category: ...}}` configurations do not need to change. Use `quality` for new configurations. ## Example: Singular test For a singular test file (e.g., `tests/e2e_order_flow.sql`): ```sql theme={null} {{ config( meta = { 'quality': {'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: quality: check_category: 'data-quality' - not_null: meta: quality: 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 = { 'quality': {'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 instance_name: staging 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). An `mssql` connection can sign in as the agent's own Windows or Kerberos identity instead of a SQL Server login. See [SQL Server: Windows Authentication](/transactional-databases/mssql#windows-authentication). ## ClickHouse: naming the service and choosing a database ClickHouse has no container above a database, so something has to name the service itself. `instance_name` is that name, and `database` is a different setting entirely — the two are a key apart and are easy to swap. ```yaml theme={null} connections: "ch-prod": clickhouse: host: abc123xyz.europe-west4.gcp.clickhouse.cloud port: 9440 instance_name: prod database: analytics username: quality password: ${CLICKHOUSE_PASSWORD} ``` `instance_name` is the name this ClickHouse is published under, and the top element of every asset path and breadcrumb its tables appear in — `prod`, `staging`, `eu-analytics`. Leave it out and the host is used instead, which is correct but unreadable for a ClickHouse Cloud endpoint. Two things follow from it being an identity rather than a label: * **Give the same service the same name everywhere.** It is the agent-side equivalent of **Instance name** on a Coalesce Quality-hosted ClickHouse integration, so a warehouse that moves between the two keeps its assets only if the name matches. * **Pick one and keep it.** Changing it republishes every table under new paths, and the old ones stop being produced. `database` is the database the connection opens with, so an unqualified table name in a SQL test resolves against it. It does not restrict what is scraped: metadata comes from system tables and covers every database the user can see, whatever this says. Omit it to open on `default`. It matches **Default database** on a Coalesce Quality-hosted integration. ## ClickHouse: cluster reads and server settings The examples above are ClickHouse Cloud services, which need neither of the keys below. A self-managed install usually needs `cluster`. ```yaml theme={null} connections: "ch-prod": clickhouse: host: clickhouse.internal port: 9440 username: quality password: ${CLICKHOUSE_PASSWORD} cluster: mode: all_replicas # or single_node name: analytics_cluster # only applies to all_replicas settings: max_execution_time: "300" ``` `cluster` decides how the agent reads ClickHouse system tables. They are per-node, so on a service with more than one replica a plain read reflects whichever replica answered rather than the whole warehouse. See [How metadata is read](/dw-integrations/clickhouse#how-metadata-is-read) for the full explanation; in the agent config: * **Omit `cluster`** to read across a cluster named `default`. Every ClickHouse Cloud service provides one. * **`mode: all_replicas`** with a `name` reads across the cluster you name. List what your server has with `SELECT DISTINCT cluster FROM system.clusters`. This read needs `GRANT REMOTE ON *.*`. * **`mode: single_node`** reads system tables directly on the connected node. This is the only setting that works on an install whose `remote_servers` defines no cluster, and it needs no `REMOTE` grant. Choose it only when the server really is one node: on a service with replicas it reports the metadata of whichever node answered, which looks like a successful but incomplete scrape. `name` does not apply. `settings` are [ClickHouse settings](https://clickhouse.com/docs/operations/settings/settings) applied to every connection the agent opens, written as they would be in a connection string. `true` and `false` become `1` and `0`, whole numbers become integers, anything else is passed through as text. A name given here replaces the value the agent would otherwise use, which is how you raise a default that is too low for your warehouse — `max_execution_time` is the common one. Both are the agent-side equivalents of the **Metadata reads** / **Cluster** and **Additional parameters** settings on a Coalesce Quality-hosted ClickHouse integration. # 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 | | resourcemanager.projects.getIamPolicy | Read the project's IAM policy: the users and service accounts bound to the project, with their roles. | Security Reviewer | platform users | | iam.serviceAccounts.list | List the project's service accounts, with their display name, description and whether they are disabled. | Security Reviewer | platform users | # 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 resourcemanager.projects.getIamPolicy iam.serviceAccounts.list ``` Create role 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` Create 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`. Create JSON key 3. Store the downloaded JSON key file securely. ### Platform users `resourcemanager.projects.getIamPolicy` and `iam.serviceAccounts.list` let Coalesce Quality list who can query the project, so it can tell people from service accounts among the logins in your query history. They read IAM metadata only, never data. Both calls go through Google APIs that have to be enabled in the project the service account belongs to: **Cloud Resource Manager API** and **Identity and Access Management (IAM) API** (`APIs & Services` → `Library`). Without them everything else works, and the integration shows a recommendation naming what is missing. ## 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. Branding configuration 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` Create OAuth client 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). BigQuery API library page ### 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.quality_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)