Skip to content

Connect SPSync to Microsoft Dataverse

This guide covers Microsoft Dataverse, the data store behind Power Apps and Dynamics 365. SPSync uses one destination kind, dataverse. It creates one Dataverse table for each SharePoint table and upserts rows into it through the Web API.

Underneath, SPSync keeps a local DuckDB file as its working copy and pushes the changed rows to Dataverse after each round. The file must stay at a stable path, or the next round has to be a full load. On the desktop app and the server, SPSync chooses that path itself.

  • A Dataverse environment (Power Platform admin centre, Environments), and its URL, such as https://org.crm.dynamics.com or a regional form like .crm4.dynamics.com, with no path.
  • Nothing to install on the machine that runs SPSync.
  • Rights to register an app in Microsoft Entra ID and to add an application user in the environment (the System Administrator role there).
  • A decision on tables: SPSync creates custom tables in the environment’s default solution. It does not create them inside a solution of your own.

Create the database and a least-privilege user

Section titled “Create the database and a least-privilege user”

Dataverse has no password logins at all. SPSync signs in as an application user, which is an Entra app registration added to the environment with a security role.

  1. In Microsoft Entra ID, register an app. Note the Application (client) id and the Directory (tenant) id, and create a client secret. Do not grant any API permission on the app. Dataverse authorises through the application user’s security role, not through Entra consent.
  2. In the Power Platform admin centre, open the environment, then Settings, Users + permissions, Application users, New app user. Pick the app registration and give it the System Customizer role. System Administrator also works, but is broader than SPSync needs. A custom role works if it can create tables and read and write rows.

These steps are from the Microsoft documentation and the SPSync design notes, and have not been tested against a live environment by SPSync.

SPSync calls the environment’s own URL over HTTPS and gets its token from Microsoft Entra ID. Allow outbound HTTPS to both. If the environment is limited with IP firewall settings, add the address SPSync connects from. Dataverse allows each user a number of requests per five-minute window. When it answers 429 or 503, SPSync waits for the time Dataverse gives and retries, so a very large first load or reconcile can take longer than the same list on a SQL destination.

Dataverse is reached over HTTPS only, with no setting to change.

An Entra app registration with a client secret, signed in as an application user. That is the only mode. A certificate, a managed identity and signing in as a person are not supported for Dataverse today.

The secret expires on the date you chose when you created it. Put the expiry in a calendar.

Five values make up the connection: the environment URL, the tenant id, the client id, the client secret, and an optional publisher prefix. The prefix is 2 to 8 lowercase letters or digits starting with a letter, and defaults to sps. Every table and column SPSync creates carries it, so ks_tasks becomes sps_ks_tasks. Use your solution publisher’s prefix if you want the tables to match it, then add them to your solution by hand afterwards.

  • Desktop app: open the Destination screen, choose Dataverse (Power Apps), fill in the environment URL, tenant id, client id, client secret and, if wanted, the publisher prefix. There is no connection string. Choose Test connection.

  • CLI: connection_string_env names an environment variable holding the path of the local DuckDB state file, not a network string. The secret is passed by variable name.

    Terminal window
    export SPSYNC_DATAVERSE_STATE_PATH=/var/lib/spsync/dataverse-state.duckdb
    export SPSYNC_DATAVERSE_CLIENT_SECRET='<client-secret>'
    spsync export-config --output replication.yaml \
    --site-url https://contoso.sharepoint.com/sites/x --list Projects \
    --pipeline-name spsync_dev --prefix dev \
    --destination-kind dataverse --connection-string-env SPSYNC_DATAVERSE_STATE_PATH \
    --dataset-name main \
    --dataverse-url https://org.crm.dynamics.com \
    --dataverse-tenant-id <tenant-id> --dataverse-client-id <app-client-id> \
    --dataverse-client-secret-env SPSYNC_DATAVERSE_CLIENT_SECRET \
    --dataverse-publisher-prefix sps \
    --client-id <entra-app-client-id>

    The last --client-id is the SharePoint app. The --dataverse-client-id is the Dataverse app, which can be the same registration or a different one.

  • AI assistant: with the admin MCP server connected, ask for the destination requirements, then let the assistant create the destination with the URL, tenant id, client id and prefix. You enter the client secret on the secure entry page.

Soft deletes stay in the table with sp_deleted_at filled in, so filter on that column being empty in a Power App to show only live rows. Hard deletes are refused for this destination. Changing a column’s type is not supported yet. SPSync may create a new versioned table instead, which has not been verified, so do not change a column’s type on a list that replicates to Dataverse.

Both get a token for the environment and call WhoAmI. A pass proves the environment URL, the tenant id, the client id and secret, and that the application user exists in that environment. It does not prove the security role can create tables. A role problem shows up on the first load.

What you seeWhat it means and the fix
AADSTS7000215 invalid client secretThe secret value is wrong, or you copied the secret id rather than its value. Create a new one.
AADSTS7000222 client secret expiredCreate a new secret and update SPSync.
AADSTS700016 application not foundThe client id or the tenant id is wrong.
401 or 403 from the environment after a good tokenThe app has no application user in this environment, or its role is too narrow. Add it, with System Customizer.
429 or 503 with a wait timeDataverse is limiting requests. SPSync waits and retries. For a very large list, raise the reconcile interval.
A column named name is refusedSPSync adds its own <prefix>_name column to every table, and a SharePoint column called name would collide with it. Rename the SharePoint column.
A text value is rejected as longer than its columnDataverse cannot widen a column in place and SPSync does not issue the change. Widen the column by hand in the maker portal.