# Synapse Synapse

Source: https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/

Adding and configuring a Synapse connection within Qualytics empowers the platform to build a symbolic link with your schema to perform operations like data discovery, visualization, reporting, syncing, profiling, scanning, anomaly surveillance, and more.

This documentation provides a step-by-step guide on adding Synapse as a source datastore in Qualytics. It covers the entire process, from initial connection setup to testing and finalizing the configuration. A Synapse datastore can also be the place Qualytics writes to; see [Use as an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#use-as-an-enrichment-destination).

By following these instructions, enterprises can ensure their Synapse environment is properly connected with Qualytics, unlocking the platform's potential to help you proactively manage your full data quality lifecycle.

![synapse-connection-form](https://userguide.qualytics.io/assets/source-datastores/datastore/jdbc/synapse/overview/synapse-connection-form.png)

Let’s get started 🚀

## Synapse Setup Guide

Qualytics connects to Azure Synapse Analytics through the **Microsoft JDBC Driver for SQL Server**, and Synapse follows the same permission model as Microsoft SQL Server. It queries `sys.schemas` joined with `sys.database_principals` to list the schemas, rather than the driver's generic metadata call, which can omit `dbo` depending on the driver version and the permissions in place. Tables, columns, and primary keys come from the standard JDBC metadata APIs.

### Authentication Types

Qualytics supports two authentication types for Synapse:

| Authentication Type | Credentials | When to use |
| --- | --- | --- |
| **Username & Password** (default) | SQL login and password | Workspaces that allow SQL authentication |
| **Service Principal** | Microsoft Entra ID application: Client ID, Client Secret, and Tenant ID | Service accounts managed in Microsoft Entra ID, or workspaces where SQL authentication is disabled ("Microsoft Entra authentication only") |

> **Note**
>
> Service principals authenticate with the client credentials flow, so multi-factor authentication and conditional access policies that apply to interactive users do not affect them. This makes Service Principal the recommended option for unattended access.

### Minimum Synapse Permissions (Source Datastore)

| Permission | Purpose |
| --- | --- |
| `CONNECT` | Allow the user to connect to the database |
| `SELECT ON SCHEMA::<schema_name>` | Read data from all tables and views for profiling and scanning |
| `VIEW DEFINITION ON SCHEMA::<schema_name>` | Read object definitions for metadata discovery |

> **Note: Schemas owned by a user or role you created**
>
> Schema discovery reads the schema list together with each schema's owner, and the permissions
> above are enough for the common case: a login always sees the schemas owned by `dbo`, by another
> built-in user, or by a built-in database role. A schema owned by a user or a role that you
> created yourself is listed only when the connecting login can also see that owner.
>
> So if a schema is missing from the **Schema** list, check who owns it. When a user you created
> owns it, one permission on that user is enough, and it is narrower than `ALTER ANY USER`.
>
> ```sql
> GRANT VIEW DEFINITION ON USER::<owner_name> TO qualytics_read;
> ```
>
> When a role you created owns it, a permission on the role is not enough: Synapse shows such a
> role only to its members and to logins holding `ALTER ANY ROLE`. Add the login to the role
> instead, keeping in mind that membership carries whatever the role itself grants.
>
> ```sql
> ALTER ROLE <role_name> ADD MEMBER qualytics_read;
> ```

### Additional Permissions for an Enrichment Datastore

When Synapse is used as an enrichment datastore, the following additional permissions are required so Qualytics can write its outputs, which are named from the linked source's prefix (for example `_tpch_failed_checks`):

| Permission | Purpose |
| --- | --- |
| `CREATE TABLE` | Create enrichment outputs |
| `INSERT ON SCHEMA::<schema_name>` | Write anomaly records, scan results, and check metrics |
| `UPDATE ON SCHEMA::<schema_name>` | Update enrichment records during rescans |
| `DELETE ON SCHEMA::<schema_name>` | Replace records when a run overwrites an output |
| `ALTER ON SCHEMA::<schema_name>` | Modify enrichment table schemas during version migrations |
| `DROP TABLE` | Replace an output when a run overwrites it (Overwrite remediation, Materialize, Export) or when a schema change requires recreating it. Unlinking never removes written data |

### Example: Source Datastore User (Read-Only)

Replace `<database_name>`, `<schema_name>`, and `<password>` with your actual values.

```sql
-- Create a login at the server level
CREATE LOGIN qualytics_read WITH PASSWORD = '<password>';

-- Switch to the target database
USE <database_name>;

-- Create a user mapped to the login
CREATE USER qualytics_read FOR LOGIN qualytics_read;

-- Grant connection and read-only access
GRANT CONNECT TO qualytics_read;
GRANT SELECT ON SCHEMA::<schema_name> TO qualytics_read;
GRANT VIEW DEFINITION ON SCHEMA::<schema_name> TO qualytics_read;
```

### Serverless SQL Pool: Additional Read Permissions

In a serverless SQL pool, data is usually exposed as views or external tables that read files from Azure Data Lake Storage. When Qualytics queries them, the files are read with the permissions of the Qualytics user, so two permissions are required in addition to the read-only set above:

| Permission | Purpose |
| --- | --- |
| `ADMINISTER DATABASE BULK OPERATIONS` | Allow the user to read the underlying files in storage |
| `REFERENCES ON DATABASE SCOPED CREDENTIAL::<credential_name>` | Allow the user to read through the credential that the views and external tables use to access storage |

```sql
USE <database_name>;

GRANT ADMINISTER DATABASE BULK OPERATIONS TO qualytics_read;
GRANT REFERENCES ON DATABASE SCOPED CREDENTIAL::<credential_name> TO qualytics_read;
```

Repeat the `REFERENCES` grant for each credential used by the views the user should read. To list the credentials in a database, run `SELECT name FROM sys.database_scoped_credentials`.

> **Note**
>
> The credential itself must also be able to reach the storage account: either the workspace Managed Identity holding the **Storage Blob Data Reader** role on the storage account, or a SAS token with **Read** and **List** permissions. If the credential cannot reach storage, queries fail with a misleading "File cannot be opened because it does not exist or it is used by another process" error even when the file exists.

### Example: Enrichment Datastore User (Read-Write)

```sql
-- Create a login at the server level
CREATE LOGIN qualytics_readwrite WITH PASSWORD = '<password>';

-- Switch to the target database
USE <database_name>;

-- Create a user mapped to the login
CREATE USER qualytics_readwrite FOR LOGIN qualytics_readwrite;

-- Grant connection, read-write, and table management access
GRANT CONNECT TO qualytics_readwrite;
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::<schema_name> TO qualytics_readwrite;
GRANT CREATE TABLE TO qualytics_readwrite;
GRANT ALTER ON SCHEMA::<schema_name> TO qualytics_readwrite;
GRANT VIEW DEFINITION ON SCHEMA::<schema_name> TO qualytics_readwrite;
```

### Setting up Service Principal Authentication

Service Principal authentication uses a Microsoft Entra ID application instead of a SQL login. Setup has two parts: registering the application in Azure and granting it access to your Synapse database.

**Part 1: Register an application in Microsoft Entra ID**

1. In the Azure Portal, go to **Microsoft Entra ID** and select **App registrations**, then **New registration**. Give the application a name and register it.
2. On the application's **Overview** page, copy the **Application (client) ID** and the **Directory (tenant) ID**. You will enter these as **Client ID** and **Tenant ID** in the Qualytics connection form.
3. Go to **Certificates & secrets**, create a **New client secret**, and copy the secret **Value** right away (it is only shown once). You will enter this as **Client Secret** in the Qualytics connection form.

> **Warning**
>
> Copy the client secret **Value**, not the Secret ID. Client secrets expire; when a secret expires, create a new one and update the connection in Qualytics.

**Part 2: Grant the application access to your database**

A Microsoft Entra administrator of the Synapse workspace must create a database user for the application and grant it the same permissions as a regular read-only user. Replace `<app_display_name>` and `<schema_name>` with your actual values.

```sql
-- Switch to the target database, then create a user for the application
CREATE USER [<app_display_name>] FROM EXTERNAL PROVIDER;

-- Grant connection and read-only access
GRANT CONNECT TO [<app_display_name>];
GRANT SELECT ON SCHEMA::<schema_name> TO [<app_display_name>];
GRANT VIEW DEFINITION ON SCHEMA::<schema_name> TO [<app_display_name>];
```

> **Note**
>
> For enrichment usage, grant the application the same additional permissions listed under **Additional Permissions for an Enrichment Datastore** above.

> **Note**
>
> Qualytics automatically filters out system schemas (`INFORMATION_SCHEMA`, `sys`, and schemas starting with `db_`) during schema discovery. You do not need to restrict access to these schemas manually.

### Troubleshooting Common Errors

| Error | Likely Cause | Fix |
| --- | --- | --- |
| `Login failed for user` | Incorrect username or password, or the login does not exist | Verify the login exists at the server level with `SELECT name FROM sys.sql_logins` |
| `Cannot open database requested by the login` | The user does not have access to the specified database | Ensure a user is mapped to the login in the target database with `CREATE USER ... FOR LOGIN` |
| `The SELECT permission was denied on object` | The user lacks `SELECT` on one or more tables in the schema | Run `GRANT SELECT ON SCHEMA::<schema_name> TO <user>` |
| `CREATE TABLE permission denied in database` | The enrichment user lacks `CREATE TABLE` permission | Run `GRANT CREATE TABLE TO <user>` |
| `Cannot find the CREDENTIAL '<name>', because it does not exist or you do not have permission` | Serverless SQL pool only: the user cannot use the storage credential behind a view or external table | Run `GRANT REFERENCES ON DATABASE SCOPED CREDENTIAL::<credential_name> TO <user>` in the target database |
| `File '<path>' cannot be opened because it does not exist or it is used by another process` | Serverless SQL pool only: the user lacks bulk read permission, or the storage credential cannot reach the storage account | Grant `ADMINISTER DATABASE BULK OPERATIONS` to the user, and verify the credential's storage access (Managed Identity role or SAS token permissions) |
| `Cannot find the object because it does not exist or you do not have permissions` | The user lacks `VIEW DEFINITION` on the schema | Run `GRANT VIEW DEFINITION ON SCHEMA::<schema_name> TO <user>` |
| `Login failed for user '<token-identified principal>'` | The service principal authenticated with Microsoft Entra ID, but no database user exists for it | Run `CREATE USER [<app_display_name>] FROM EXTERNAL PROVIDER` in the target database |
| `AADSTS7000215: Invalid client secret provided` | The Client Secret is wrong or expired, or the Secret ID was pasted instead of the secret Value | Create a new client secret in the Azure Portal and update the connection with its **Value** |
| `AADSTS700016: Application ... was not found in the directory` | The Client ID or Tenant ID does not match the application registration | Verify both values on the application's **Overview** page in the Azure Portal |

### Detailed Troubleshooting Notes

#### Authentication Errors

The error `Login failed for user` indicates that the credentials are incorrect or the login does not exist at the server level.

Common causes:

- **Incorrect password**: the password does not match the one set for the login.
- **Login does not exist**: the login was never created at the server level with `CREATE LOGIN`.
- **User not mapped**: the login exists but no user is mapped to it in the target database.

> **Note**
>
> With **Username & Password** authentication, Synapse uses the same model as SQL Server: a login must exist at the server level, and a corresponding user must be created in each target database. With **Service Principal** authentication, there is no SQL login; the application authenticates with Microsoft Entra ID, and a database user created with `FROM EXTERNAL PROVIDER` must exist in each target database.

#### Permission Errors

The error `The SELECT permission was denied on object` means the user authenticated successfully but lacks the necessary grants on the target schema.

Common causes:

- **Missing `SELECT ON SCHEMA`**: the user does not have `SELECT` on the target schema.
- **Wrong schema**: the user has permissions on `dbo` but the target tables are in a different schema.
- **Missing `VIEW DEFINITION`**: the user cannot see object metadata needed for schema discovery.

#### Connection Errors

The error `Cannot open database requested by the login` means the user does not have access to the specified database.

Common causes:

- **No user in database**: the login exists but `CREATE USER ... FOR LOGIN` was not run in the target database.
- **Database does not exist**: the database name in the connection form is incorrect.
- **Synapse pool paused**: the dedicated SQL pool is paused and needs to be resumed.

> **Tip**
>
> Start by confirming credentials are valid (authentication errors), then verify schema/table permissions (permission errors), and finally check database access (connection errors).

## Add a Source Datastore

A source datastore is a storage location Qualytics connects to so it can profile, scan, and monitor data. Adding Synapse as a source lets Qualytics query it through the Microsoft JDBC Driver for SQL Server and run quality operations on the tables it discovers.

Before you start, review the [Minimum Synapse Permissions](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#minimum-synapse-permissions-source-datastore) the connecting login needs.

### Field reference

The **Add Datastore** page shows the sections below when Synapse is selected. When reusing an existing connection, the **Connection Properties** and **Secrets Management** sections come already filled in and read-only: Qualytics has already validated those credentials, so you fill in only the **Location** and the **General** fields. To change a saved connection's credentials, edit the connection through the [Manage Connections](https://userguide.qualytics.io/settings/connections/manage-connections/) page; edits there apply to every datastore that reuses the connection.

#### Connection Properties

These fields define the Synapse endpoint Qualytics connects to. They belong to the connection: when reusing an existing connection, they come already filled in and read-only.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Connection Name** | Yes | Text | A label for the saved connection (e.g., `acme_synapse_reporting`), so other datastores can reuse it later. |
| **Host** | Yes | Text | The workspace SQL endpoint (e.g., `acme-ws.sql.azuresynapse.net` for a dedicated pool, or `acme-ws-ondemand.sql.azuresynapse.net` for the serverless pool). |
| **Port** | Yes | Number | The port the endpoint accepts connections on. Defaults to `1433`. |
| **SSL Connection** | No | Checkbox | Ask the driver to encrypt the connection. Cleared by default. Select it when your workspace requires an encrypted connection. |
| **Max Parallelization** | No | Number | Caps how many queries Qualytics runs at the same time against a datastore reached through this connection, from 1 to 100. Leave it empty for no explicit limit. The cap applies per datastore, so datastores sharing this connection each get their own allowance. Sits in the collapsed **Advanced** section of the form. See [Max Parallelization](https://userguide.qualytics.io/source-datastore/datastore/connection/how-it-works/#max-parallelization). |

#### Authentication

Choose how Qualytics authenticates to Synapse. Setting **Type** changes the credential fields shown below it, so pick the tab that matches your choice. These fields also belong to the connection: already filled in and read-only when reusing one. See [Authentication Types](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#authentication-types) for when to use each one.

**Tab: Username & Password**

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Type** | No | Option | Set to **Username & Password**, which is the default (`BASIC` in the API). |
| **User** | Yes | Text | The SQL login Qualytics connects as. |
| **Password** | Yes | Text | The password for that login. |

**Tab: Service Principal**

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Type** | No | Option | Set to **Service Principal** to authenticate through Microsoft Entra ID (`SERVICE_PRINCIPAL` in the API). |
| **Client ID** | Yes | Text | The application (client) ID of the Microsoft Entra ID app registration. Sent as the connection's `username` in the API. |
| **Client Secret** | Yes | Text | The client secret generated for that app registration. Sent as the connection's `password` in the API. |
| **Tenant ID** | Yes | Text | The Microsoft Entra ID tenant ID the app registration belongs to. |

> **Note: Service Principal prerequisites**
>
> The application needs a database user created with `FROM EXTERNAL PROVIDER` in each target database, with the same permissions a login would need. See [Setting up Service Principal Authentication](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#setting-up-service-principal-authentication).

#### Secrets Management

This group is optional: use it only if you want Qualytics to pull credentials from a secrets manager instead of typing them into the form. Turn on **HashiCorp Vault** to show the fields below. Despite the label, any secrets manager that exposes a compatible REST API works, not only HashiCorp Vault; see [HashiCorp Vault](https://userguide.qualytics.io/source-datastore/datastore/connection/hashicorp-vault/deep-dive/introduction/). It also belongs to the connection: read-only when reusing an existing connection.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Login URL** | Yes | Text | The full URL of the login endpoint (e.g., `https://vault.example.com/v1/auth/approle/login`). With Vault namespaces, add the namespace after `/v1/`, as in `/v1/<namespace>/auth/approle/login`. |
| **Credentials Payload** | Yes | Text | A JSON body containing the credentials Vault expects (e.g., `{"role_id":"...","secret_id":"..."}`). |
| **Token JSONPath** | Yes | Text | The JSONPath that extracts the client token from Vault's response. Defaults to `$.auth.client_token`. |
| **Secret URL** | Yes | Text | The full URL of the secret, including `https://` and the host (e.g., `https://vault.example.com/v1/secret/data/synapse`). With Vault namespaces, add the namespace after `/v1/`. |
| **Token Header Name** | Yes | Text | The HTTP header name used to send the token. Defaults to `X-Vault-Token`. |
| **Data JSONPath** | Yes | Text | The JSONPath that extracts the key/value pairs from Vault's response. Use `$.data.data` for a KV version 2 secret (its API path contains `/data/`) and `$.data` for KV version 1 or the database secrets engine. The form pre-fills `$.data`. |

> **Note**
>
> Reference a key from the secret in any **Connection Properties** or **Authentication** field with `${key}`, for example `${password}`. Write it with braces (`${key}`, never `$.key`) and match the key name's case. Qualytics resolves it each time the connection is opened, so a changed value takes effect on the next connection. Setup steps, the namespace rule, and a troubleshooting page are on the [HashiCorp Vault](https://userguide.qualytics.io/source-datastore/datastore/connection/hashicorp-vault/deep-dive/introduction/) pages.

#### Location

Pick the database and the schema or schemas Qualytics should read from. You fill these in on both flows.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Database** | Yes | Option | The database to read from. Click the refresh icon to load the databases the login can see. |
| **Schema** | Yes | Option | One or more schemas inside the selected database. Each schema you pick becomes its own Qualytics datastore. |
| **Instance** | No | Text | The named instance to connect to. A port is always sent with the connection, and Synapse connects on that port and then checks the instance name against it, so fill this in only when the named instance listens on the port you provide. Workspace endpoints do not use named instances. |

> **Note: One datastore per schema**
>
> Selecting more than one schema creates one source datastore per schema, named from the **Name Template**. See [Multi-Schema Source Datastore Creation](https://userguide.qualytics.io/source-datastore/datastore/multi-schema/overview/) for details.

> **Note: System databases**
>
> The `master`, `model`, `msdb`, and `tempdb` databases are left out of discovery, so they do not appear in the **Database** list.

#### General

Common fields for every source datastore, shown below the **Location** section. You fill these in on both flows.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Name Template** | No | Text | Defines the naming pattern for each source datastore being created. Use `{{schema}}` as a placeholder that gets replaced with the actual schema name (e.g., `synapse_{{schema}}` becomes `synapse_sales`). Left empty, the datastore is named from the connection name and the schema. |
| **Group** | No | Option | Organizes your datastores under a shared group in the navigation tree. Select an existing group or create a new one with the **Add New Group** toggle. |
| **Teams** | Yes | Option | Select one or more teams to associate with this source datastore. |
| **Initiate Sync** | No | Checkbox | Automatically sync the datastore to detect containers and fields after creation. |

Below the form, an information banner lists the **Public addresses** and **Private addresses** your datastore connections originate from. Allow the ones that match your network setup through your security groups or firewall rules; see [How Connections Work](https://userguide.qualytics.io/source-datastore/datastore/connection/how-it-works/#finding-the-addresses-to-allow) for where the addresses come from.

### Steps

There are two ways to set up the connection: reuse a connection you already saved (**Existing Connection**) or create a new one from scratch (**New Connection**). The tabs below walk through each option; pick the one you want to follow. Each field is described in the [Field reference](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#source-field-reference) above.

**Tab: New Connection**

**Step 1**: Navigate to the **Datastores** page.

**Step 2**: Click the **Add**  button at the top-right corner and choose **Source** .

**Step 3**: The **Add Datastore** page opens.

**Step 4**: Select **New Connection** next to the **Search**  field.

**Step 5**: Select **Synapse** from the connector grid. Use the search field to filter connectors by name.

**Step 6**: Fill in the **Connection Properties**: the **Connection Name**, **Host**, and **Port**, then the **Authentication** fields for the **Type** you choose.

**Step 7**: Optionally, expand **Secrets Management** to retrieve credentials from a secrets manager.

**Step 8**: Fill in the **Location** fields (**Database** and **Schema**) and the **General** fields.

**Step 9**: Click **Test connection**. A success message confirms that the connection has been verified.

> **Info**
>
> The **Finish** and **Next** buttons stay disabled until the connection test passes on the current values. If the test fails, see [Troubleshooting Common Errors](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#troubleshooting-common-errors).

**Step 10**: Click **Finish** to create the datastore.

> **Tip**
>
> To link a destination so Qualytics can write anomalies and metadata from the first operation, click **Next** instead of **Finish**. See [Use as an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#use-as-an-enrichment-destination) below.

**Step 11**: A success dialog confirms that your datastore has been added. Click **Go to your datastore** to open its page.

**Tab: Existing Connection**

**Step 1**: Navigate to the **Datastores** page.

**Step 2**: Click the **Add**  button at the top-right corner and choose **Source** .

**Step 3**: The **Add Datastore** page opens.

**Step 4**: Select **Existing Connection** next to the **Search**  field.

**Step 5**: Select the saved Synapse connection from the grid. Use the search field to filter connections by name. The **Connection Properties** and **Secrets Management** sections come already filled in and read-only.

> **Tip: Start a new connection from this one**
>
> To use the selected connection as a starting point for a brand-new connection instead, click the **Duplicate as a new connection**  button on the selected connection. The form switches to **New Connection** mode with the connection's settings already filled in for you to adjust.

**Step 6**: Fill in the **Location** fields (**Database** and **Schema**) and the **General** fields. These are the only fields left to fill in.

**Step 7**: Click **Test connection**. A success message confirms that the connection has been verified.

> **Info**
>
> The **Finish** and **Next** buttons stay disabled until the connection test passes on the current values. If the test fails, see [Troubleshooting Common Errors](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#troubleshooting-common-errors).

**Step 8**: Click **Finish** to create the datastore.

> **Tip**
>
> To link a destination so Qualytics can write anomalies and metadata from the first operation, click **Next** instead of **Finish**. See [Use as an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#use-as-an-enrichment-destination) below.

**Step 9**: A success dialog confirms that your datastore has been added. Click **Go to your datastore** to open its page.

## Use as an Enrichment Datastore

An **enrichment datastore** is where Qualytics writes its findings: scan results, source record examples, remediation snapshots, materialized copies, and exports. Keep it on a dedicated schema or storage path, separate from the source data you govern. When a source datastore is linked to it, that source's writes land there. The destination can share the source's connection when those credentials have the required write access.

To use a Synapse datastore as a destination, its connection user needs the write grants listed under [Additional Permissions for an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#additional-permissions-for-enrichment-destination). Then link it from the datastore that will write to it: open its **Settings**  menu, click **Enrichment** , and either pick the Synapse datastore under **Use existing** or create it there under **Add new**. The same choice is offered in the second step of the Add Datastore page. The flow is the same for every connector and is documented once, in [Link an Enrichment Destination](https://userguide.qualytics.io/source-datastore/enrichment-datastore/how-tos/link-enrichment/) and [Link Enrichment on Datastore Creation](https://userguide.qualytics.io/source-datastore/enrichment-datastore/how-tos/link-during-creation/).

The rest of this section covers only what is specific to Synapse: the fields you fill in when creating the destination on Synapse from inside that dialog. For what Qualytics writes and how the outputs are named, see [Enrichment Outputs](https://userguide.qualytics.io/source-datastore/enrichment-datastore/deep-dive/tables/).

### Field reference

The **Enrichment Destination** step shows the sections below when Synapse is selected. When reusing an existing connection, the **Connection Properties** and **Secrets Management** sections come already filled in and read-only.

#### Connection Properties

These fields define the Synapse endpoint Qualytics connects to. They are the same fields as on the source datastore flow, repeated here so this section stands on its own.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Connection Name** | Yes | Text | A label for the saved connection (e.g., `acme_synapse_enrichment`), so other datastores can reuse it later. |
| **Host** | Yes | Text | The workspace SQL endpoint Qualytics writes to. |
| **Port** | Yes | Number | The port the endpoint accepts connections on. Defaults to `1433`. |
| **SSL Connection** | No | Checkbox | Ask the driver to encrypt the connection. Cleared by default. Select it when your workspace requires an encrypted connection. |
| **Max Parallelization** | No | Number | Caps how many queries Qualytics runs at the same time against a datastore reached through this connection, from 1 to 100. Leave it empty for no explicit limit. The cap applies per datastore, so datastores sharing this connection each get their own allowance. Sits in the collapsed **Advanced** section of the form. See [Max Parallelization](https://userguide.qualytics.io/source-datastore/datastore/connection/how-it-works/#max-parallelization). |

#### Authentication

Choose how Qualytics authenticates to Synapse. Setting **Type** changes the credential fields shown below it, so pick the tab that matches your choice. These fields also belong to the connection: already filled in and read-only when reusing one. They are the same fields as on the source datastore flow, repeated here so this section stands on its own.

**Tab: Username & Password**

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Type** | No | Option | Set to **Username & Password**, which is the default (`BASIC` in the API). |
| **User** | Yes | Text | The SQL login Qualytics connects as. It needs the write permissions listed under [Additional Permissions for an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#additional-permissions-for-enrichment-destination). |
| **Password** | Yes | Text | The password for that login. |

**Tab: Service Principal**

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Type** | No | Option | Set to **Service Principal** to authenticate through Microsoft Entra ID (`SERVICE_PRINCIPAL` in the API). |
| **Client ID** | Yes | Text | The application (client) ID of the Microsoft Entra ID app registration. Sent as the connection's `username` in the API. |
| **Client Secret** | Yes | Text | The client secret generated for that app registration. Sent as the connection's `password` in the API. |
| **Tenant ID** | Yes | Text | The Microsoft Entra ID tenant ID the app registration belongs to. |

#### Secrets Management

This group is optional: use it only if you want Qualytics to pull credentials from a secrets manager instead of typing them into the form. Turn on **HashiCorp Vault** to show the fields below. Despite the label, any secrets manager that exposes a compatible REST API works, not only HashiCorp Vault; see [HashiCorp Vault](https://userguide.qualytics.io/source-datastore/datastore/connection/hashicorp-vault/deep-dive/introduction/). It also belongs to the connection: read-only when reusing an existing connection.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Login URL** | Yes | Text | The full URL of the login endpoint (e.g., `https://vault.example.com/v1/auth/approle/login`). With Vault namespaces, add the namespace after `/v1/`, as in `/v1/<namespace>/auth/approle/login`. |
| **Credentials Payload** | Yes | Text | A JSON body containing the credentials Vault expects (e.g., `{"role_id":"...","secret_id":"..."}`). |
| **Token JSONPath** | Yes | Text | The JSONPath that extracts the client token from Vault's response. Defaults to `$.auth.client_token`. |
| **Secret URL** | Yes | Text | The full URL of the secret, including `https://` and the host (e.g., `https://vault.example.com/v1/secret/data/synapse`). With Vault namespaces, add the namespace after `/v1/`. |
| **Token Header Name** | Yes | Text | The HTTP header name used to send the token. Defaults to `X-Vault-Token`. |
| **Data JSONPath** | Yes | Text | The JSONPath that extracts the key/value pairs from Vault's response. Use `$.data.data` for a KV version 2 secret (its API path contains `/data/`) and `$.data` for KV version 1 or the database secrets engine. The form pre-fills `$.data`. |

> **Note**
>
> Reference a key from the secret in any **Connection Properties** or **Authentication** field with `${key}`, for example `${password}`. Write it with braces (`${key}`, never `$.key`) and match the key name's case. Qualytics resolves it each time the connection is opened, so a changed value takes effect on the next connection. Setup steps, the namespace rule, and a troubleshooting page are on the [HashiCorp Vault](https://userguide.qualytics.io/source-datastore/datastore/connection/hashicorp-vault/deep-dive/introduction/) pages.

#### Location

Where Qualytics writes the enrichment tables.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Database** | Yes | Option | The database Qualytics writes the enrichment tables into. Pick exactly one. |
| **Schema** | Yes | Option | The schema inside that database where the enrichment tables are created. Make sure the login has write access to it. |
| **Instance** | No | Text | The named instance to connect to, when the endpoint uses one. Workspace endpoints do not. |

> **Warning**
>
> The account used by an enrichment datastore needs read and write access, while a source datastore needs only read access.

> **Note: Dedicated pool recommended**
>
> Enrichment writes tables, so the target has to accept writes. A serverless SQL pool cannot host the enrichment tables; point the enrichment destination at a dedicated SQL pool or another writable connector.

#### General

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Name** | Yes | Text | The name of the new datastore. |
| **Teams** | Yes | Option | Select one or more teams to associate with the datastore. |

> **Note: Table prefix**
>
> Qualytics generates a **Prefix** from the source datastore's name for Scan, Remediation, and Materialize outputs. Each source sharing a destination needs a unique prefix. Export tables instead use the normalized datastore name. To change the prefix before creating the datastore, click **Edit prefixes**  in the **Prefix** section of this step.

#### Write Behavior

Whether a Scan also writes a snapshot of the anomalous records, and whether Qualytics profiles the written tables after each write.

| Field | Required | Type | Description |
| --- | --- | --- | --- |
| **Remediation Strategy** | No | Choice | Controls whether and how anomalous source records are written to the enrichment destination. **None** does not write them and is the default, **Append** adds the anomalous records after each scan, and **Overwrite** keeps only the records from the latest scan. |
| **Profile written tables in the enrichment destination** | No | Toggle | On by default. After this datastore writes to the destination, Qualytics always adds the written outputs to the destination, names them, and links them to their source. With this on, Qualytics also profiles them, which types their fields and records row counts, so they are ready to use without a manual step. |

### Steps

Fill in these fields under **Add new**, either in the **Enrichment Destination** dialog of the datastore that will write here or in the second step of the Add Datastore page, then click **Test connection** and save. The steps are the same for every connector: see [Link an Enrichment Destination](https://userguide.qualytics.io/source-datastore/enrichment-datastore/how-tos/link-enrichment/) or [Link Enrichment on Datastore Creation](https://userguide.qualytics.io/source-datastore/enrichment-datastore/how-tos/link-during-creation/).

## API Payload Examples

### Creating a Datastore

This section provides a sample payload for creating a datastore. Replace the placeholder values with actual data relevant to your setup.

#### Endpoint (Post)

`/api/datastores` *(post)*

**Tab: Creating a datastore with a new connection**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": false,
        "trigger_sync": true,
        "connection": {
            "name": "your_connection_name",
            "type": "synapse",
            "host": "synapse_host",
            "port": 1433,
            "username": "synapse_username",
            "password": "synapse_password"
        }
    }
```

**Tab: Creating a datastore with Service Principal authentication**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": false,
        "trigger_sync": true,
        "connection": {
            "name": "your_connection_name",
            "type": "synapse",
            "host": "synapse_host",
            "port": 1433,
            "username": "application_client_id",
            "password": "client_secret_value",
            "parameters": {
                "authentication_type": "SERVICE_PRINCIPAL",
                "tenant_id": "directory_tenant_id"
            }
        }
    }
```

**Tab: Creating a datastore with an existing connection**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": false,
        "trigger_sync": true,
        "connection_id": 123
    }
```

**Tab: Create a Source Datastore using the CLI**

```bash
# Step 1: Create a Connection
qualytics connections create \
    --type synapse \
    --name "your_connection_name" \
    --host ${SYNAPSE_HOST} \
    --port 1433 \
    --username ${SYNAPSE_USER} \
    --password ${SYNAPSE_PASSWORD}

# Step 2: Create a Source Datastore
qualytics datastores create \
    --name "your_datastore_name" \
    --connection-name "your_connection_name" \
    --database your_database \
    --schema dbo
```

**Tab: Create a Source Datastore using the CLI (Service Principal)**

```bash
# Step 1: Create a Connection
# Pass the Client ID as the username and the client secret Value as the password.
qualytics connections create \
    --type synapse \
    --name "your_connection_name" \
    --host ${SYNAPSE_HOST} \
    --port 1433 \
    --username ${APPLICATION_CLIENT_ID} \
    --password ${CLIENT_SECRET} \
    --parameters '{"authentication_type": "SERVICE_PRINCIPAL", "tenant_id": "directory_tenant_id"}'

# Step 2: Create a Source Datastore
qualytics datastores create \
    --name "your_datastore_name" \
    --connection-name "your_connection_name" \
    --database your_database \
    --schema dbo
```

> **Note**
>
> Synapse defaults to **Username & Password**, so a Service Principal connection has to set `authentication_type` explicitly. Omitting it creates the connection with SQL login authentication, and the Client ID and secret are then treated as a username and password.

### Create an Enrichment Datastore

#### Endpoint (Post)

`/api/datastores` *(post)*

This section provides a sample payload for creating an enrichment datastore. Replace the placeholder values with actual data relevant to your setup.

**Tab: Creating an enrichment datastore with a new connection**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": true,
        "connection": {
            "name": "your_connection_name",
            "type": "synapse",
            "host": "synapse_host",
            "port": 1433,
            "username": "synapse_username",
            "password": "synapse_password"
        }
    }
```

**Tab: Creating an enrichment datastore with Service Principal authentication**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": true,
        "connection": {
            "name": "your_connection_name",
            "type": "synapse",
            "host": "synapse_host",
            "port": 1433,
            "username": "application_client_id",
            "password": "client_secret_value",
            "parameters": {
                "authentication_type": "SERVICE_PRINCIPAL",
                "tenant_id": "directory_tenant_id"
            }
        }
    }
```

**Tab: Creating an enrichment datastore with an existing connection**

```json
    {
        "name": "your_datastore_name",
        "teams": ["Public"],
        "database": "synapse_database",
        "schema": "synapse_schema",
        "enrichment_only": true,
        "connection_id": 123
    }
```

**Tab: Create an Enrichment Datastore using the CLI**

```bash
# Step 1: Create a Connection
qualytics connections create \
    --type synapse \
    --name "your_connection_name" \
    --host ${SYNAPSE_HOST} \
    --port 1433 \
    --username ${SYNAPSE_USER} \
    --password ${SYNAPSE_PASSWORD}

# Step 2: Create an Enrichment Datastore
qualytics datastores create \
    --name "your_datastore_name" \
    --connection-name "your_connection_name" \
    --database your_database \
    --schema your_enrichment_schema \
    --enrichment-only
```

**Tab: Create an Enrichment Datastore using the CLI (Service Principal)**

```bash
# Step 1: Create a Connection
qualytics connections create \
    --type synapse \
    --name "your_connection_name" \
    --host ${SYNAPSE_HOST} \
    --port 1433 \
    --username ${APPLICATION_CLIENT_ID} \
    --password ${CLIENT_SECRET} \
    --parameters '{"authentication_type": "SERVICE_PRINCIPAL", "tenant_id": "directory_tenant_id"}'

# Step 2: Create an Enrichment Datastore
qualytics datastores create \
    --name "your_datastore_name" \
    --connection-name "your_connection_name" \
    --database your_database \
    --schema your_enrichment_schema \
    --enrichment-only
```

> **Note**
>
> A Service Principal used for enrichment needs write access as well as read access. Grant it the permissions listed under [Additional Permissions for an Enrichment Datastore](https://userguide.qualytics.io/source-datastore/datastore/jdbc/synapse/#additional-permissions-for-enrichment-destination), using the database user created with `FROM EXTERNAL PROVIDER`.

### Link an Enrichment Destination

#### Endpoint (Patch)

`/api/datastores/{datastore-id}/enrichment/{enrichment-id}` *(patch)*

*Last updated: November 3, 2026.*
