{"id":44569,"date":"2026-05-12T15:39:29","date_gmt":"2026-05-12T10:09:29","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=44569"},"modified":"2026-05-12T15:39:29","modified_gmt":"2026-05-12T10:09:29","slug":"how-to-perform-crud-operations-in-microsoft-dataverse-with-python","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2026\/05\/how-to-perform-crud-operations-in-microsoft-dataverse-with-python\/","title":{"rendered":"How to Perform CRUD Operations in Microsoft Dataverse with Python"},"content":{"rendered":"<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44579\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python.png\" alt=\"CRUD Operations \" width=\"2100\" height=\"1200\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python.png 2100w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-300x171.png 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-1024x585.png 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-768x439.png 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-1536x878.png 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-2048x1170.png 2048w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/How-to-Perform-CRUD-Operations-in-Microsoft-Dataverse-with-Python-660x377.png 660w\" sizes=\"(max-width: 2100px) 100vw, 2100px\" \/>Microsoft Dataverse is widely used for storing and managing business data in Power Platform applications. In many real-world scenarios, developers need to integrate external applications, automate processes, or perform bulk data operations using Python.<\/p>\n<p>In this blog, we will learn how to connect Python with Microsoft Dataverse using Azure App Registration and perform CRUD (Create, Retrieve, Update, Delete) operations through the Dataverse Web API using Python libraries like msal and requests.<\/p>\n<h3><strong>Please find below steps to perform CRUD operation:<br \/>\n<\/strong><\/h3>\n<p><strong>Step 1: <\/strong>Create App Registration on Azure Portal<\/p>\n<p>Please find the <a href=\"https:\/\/learn.microsoft.com\/en-us\/entra\/identity-platform\/quickstart-register-app\" target=\"_blank\" rel=\"noopener\">link<\/a> to create Azure app from Azure Portal.<\/p>\n<p><strong>Step 2:<\/strong> Configure API Permissions to created Azure app<\/p>\n<ul>\n<li>Navigate to API Permissions &gt; Add Permission &gt; Apis my organization uses tab<\/li>\n<li>Add permission: Dynamics CRM<\/li>\n<li>Select: user impersonation<\/li>\n<li>Grant admin consent<\/li>\n<\/ul>\n<p>This allows the application to securely access Dataverse data.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44575\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1.jpg\" alt=\"CRUD Operations 1\" width=\"1919\" height=\"884\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1.jpg 1919w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1-300x138.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1-1024x472.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1-768x354.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1-1536x708.jpg 1536w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-1-660x304.jpg 660w\" sizes=\"(max-width: 1919px) 100vw, 1919px\" \/><\/p>\n<p><strong>Step 3:<\/strong> Install Necessary Libraries and Connect CRM to Local Python<\/p>\n<p>Install required libraries: pip install requests msal certifi<\/p>\n<p>Python Code:<\/p>\n<pre class=\"lang:css gutter:true start:1\">import os\r\n<em>import certifi<\/em>\r\n\r\n<em>import requests<\/em>\r\n\r\n<em>import msal<\/em>\r\n\r\n<em># SSL Fix<\/em>\r\n\r\n<em>os.environ[\"SSL_CERT_FILE\"] = certifi.where()<\/em>\r\n\r\n<em># Azure App Details<\/em>\r\n\r\n<em>CLIENT_ID = \"YOUR_CLIENT_ID\"<\/em>\r\n\r\n<em>TENANT_ID = \"YOUR_TENANT_ID\"<\/em>\r\n\r\n<em># Dataverse URL<\/em>\r\n\r\n<em>BASE_URL = \"https:\/\/yourorg.crm.dynamics.com\"<\/em>\r\n\r\n<em># Dataverse Table<\/em>\r\n\r\n<em>EMPLOYEE_TABLE = \"ale_employeerecordses\"<\/em>\r\n\r\n<em># Authentication<\/em>\r\n\r\n<em>AUTHORITY = f\"https:\/\/login.microsoftonline.com\/{TENANT_ID}\"<\/em>\r\n\r\n<em>SCOPE = [f\"{BASE_URL}\/.default\"]<\/em>\r\n\r\n<em>app = msal.PublicClientApplication(<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 CLIENT_ID,<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 authority=AUTHORITY<\/em>\r\n\r\n<em>)<\/em>\r\n\r\n<em>result = app.acquire_token_interactive(scopes=SCOPE)<\/em>\r\n\r\n<em>access_token = result[\"access_token\"]<\/em>\r\n\r\n<em>headers = {<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 \"Authorization\": f\"Bearer {access_token}\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 \"Accept\": \"application\/json\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 \"Content-Type\": \"application\/json\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 \"OData-MaxVersion\": \"4.0\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 \"OData-Version\": \"4.0\"<\/em>\r\n\r\n<em>}<\/em>\r\n\r\n<em>print(\"Connection Successful\")<\/em><\/pre>\n<p><strong>Step 4: <\/strong>Perform Record Create Operation<\/p>\n<p>Code for record creation:<\/p>\n<pre class=\"lang:css gutter:true start:1\">def create_employee():\r\n\r\n<em>\u00a0\u00a0\u00a0 url = f\"{BASE_URL}\/api\/data\/v9.2\/{EMPLOYEE_TABLE}\"<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 payload = {<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ale_name\": \"Alex Baker\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ale_email\": \"alex@company.com\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ale_department\": \"IT\",<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \"ale_salary\": 75000<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 }<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 response = requests.post(url, headers=headers, json=payload)<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 if response.status_code in [200, 201, 204]:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Employee Created Successfully\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 else:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Employee Creation Failed\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response.text)<\/em>\r\n\r\n<em>create_employee()<\/em><\/pre>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44576\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2.jpg\" alt=\"CRUD Operations \" width=\"1440\" height=\"821\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2.jpg 1440w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2-300x171.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2-1024x584.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2-768x438.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-2-660x376.jpg 660w\" sizes=\"(max-width: 1440px) 100vw, 1440px\" \/><\/p>\n<p><strong>Step 5:<\/strong> Perform Record Update Operation and Output<\/p>\n<p>Below Code to Update Record:<\/p>\n<pre class=\"lang:css gutter:true start:1\">def update_employee(employee_guid):\r\n\r\nurl = f\"{BASE_URL}\/api\/data\/v9.2\/{EMPLOYEE_TABLE}({employee_guid})\"\r\n\r\npayload = {\r\n\r\n\"ale_salary\": 90000,\r\n\r\n\"ale_department\": \"Engineering\"\r\n\r\n}\r\n\r\nresponse = requests.patch(url, headers=headers, json=payload)\r\n\r\nif response.status_code in [200, 204]:\r\n\r\nprint(\"Employee Updated Successfully\")\r\n\r\nelse:\r\n\r\nprint(\"Employee Update Failed\")\r\n\r\nprint(response.text)<\/pre>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-44574\" style=\"border: 1px solid #000000; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3.jpg\" alt=\"CRUD Operations \" width=\"1243\" height=\"730\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3.jpg 1243w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3-300x176.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3-1024x601.jpg 1024w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3-768x451.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2026\/05\/CRUD-Operations-3-660x388.jpg 660w\" sizes=\"(max-width: 1243px) 100vw, 1243px\" \/><\/p>\n<p>Record Department field updated Engineering from IT<\/p>\n<p><strong>Step 6:<\/strong> Perform record retrieve operation<\/p>\n<pre class=\"lang:css gutter:true start:1\">def get_employees():\r\n\r\n<em>\u00a0\u00a0\u00a0 print(\"\\n Fetching Employees...\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 url = f\"{BASE_URL}\/api\/data\/v9.2\/{EMPLOYEE_TABLE}\"<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 response = requests.get(url, headers=headers)<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 if response.status_code != 200:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0print(\" Failed to Fetch Employees\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response.text)<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 data = response.json()<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 print(\"\\n Employees Retrieved\\n\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 for emp in data[\"value\"]:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Name\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 :\", emp.get(\"ale_name\"))<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Email\u00a0\u00a0\u00a0\u00a0\u00a0 :\", emp.get(\"ale_email\"))<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Department :\", emp.get(\"ale_department\"))<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"Salary\u00a0\u00a0\u00a0\u00a0 :\", emp.get(\"ale_salary\"))<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"GUID\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 :\", emp.get(\"ale_employeerecordsid\"))<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\"-----------------------------------\")<\/em><em>\u00a0<\/em><\/pre>\n<p><strong>Step 7:<\/strong> Perform delete operation<\/p>\n<pre class=\"lang:css gutter:true start:1\">def delete_employee(employee_guid):\r\n\r\n<em>\u00a0\u00a0\u00a0 print(\"\\n Deleting Employee...\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 url = f\"{BASE_URL}\/api\/data\/v9.2\/{EMPLOYEE_TABLE}({employee_guid})\"<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 response = requests.delete(url, headers=headers)<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 if response.status_code in [200, 204]:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\" Employee Deleted Successfully\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0 else:<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(\" Employee Delete Failed\")<\/em>\r\n\r\n<em>\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 print(response.text)<\/em><\/pre>\n<h3><strong>Conclusion:<\/strong><\/h3>\n<p>Python provides a simple and powerful way to integrate with Microsoft Dataverse using Web API. By using Azure App Registration and MSAL authentication, we can securely connect external applications with Dataverse and perform CRUD operations.<\/p>\n<h3><strong>FAQs<\/strong><\/h3>\n<p><strong>1. What is Microsoft Dataverse in Python integration?<\/strong><\/p>\n<p>Microsoft Dataverse integration with Python allows developers to connect external Python applications with Dataverse using the Dataverse Web API. It helps automate CRUD operations, data migration, reporting, AI processing, and backend integrations.<\/p>\n<p><strong>2. How do I connect Python to Microsoft Dataverse?<\/strong><\/p>\n<p>You can connect Python to Microsoft Dataverse by:<\/p>\n<ul>\n<li>Creating an Azure App Registration<\/li>\n<li>Granting Dynamics CRM API permissions<\/li>\n<li>Using MSAL authentication<\/li>\n<li>Calling Dataverse Web API endpoints with Python requests library<\/li>\n<\/ul>\n<p><strong>3. Which Python libraries are required for Dataverse integration?<\/strong><\/p>\n<p>The commonly used Python libraries for Dataverse integration are:<\/p>\n<ul>\n<li>requests<\/li>\n<li>msal<\/li>\n<li>certifi<\/li>\n<\/ul>\n<p>Install them using:<\/p>\n<p>pip install requests msal certifi<\/p>\n<p><strong>4. How does authentication work in Dataverse Python integration?<\/strong><\/p>\n<p>Authentication is performed using Azure Active Directory (Azure AD) with MSAL (Microsoft Authentication Library). The application acquires an OAuth access token, which is used to securely access Dataverse APIs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Microsoft Dataverse is widely used for storing and managing business data in Power Platform applications. In many real-world scenarios, developers need to integrate external applications, automate processes, or perform bulk data operations using Python. In this blog, we will learn how to connect Python with Microsoft Dataverse using Azure App Registration and perform CRUD (Create,\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2026\/05\/how-to-perform-crud-operations-in-microsoft-dataverse-with-python\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":15,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2354,2848,2361],"tags":[3351],"class_list":["post-44569","post","type-post","status-publish","format-standard","hentry","category-dataverse","category-power-platform","category-technical","tag-perform-crud-operations"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/44569","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=44569"}],"version-history":[{"count":5,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/44569\/revisions"}],"predecessor-version":[{"id":44581,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/44569\/revisions\/44581"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=44569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=44569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=44569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}