We want to query and call Web API actions on the Microsoft Dynamics CRM 2016 Odata endpoint in Python. We want to do it because we can. Also, Python has a rich set of modules for all sorts from machine learning to forecasting- We want to apply this to CRM data.

The options for integration include using an odata library like ODatapy-Client which generates proxy code or static types from the Web API metadata. Using ODatapy-Client takes a fair amount of work considering that the metadata generated by the CRM web api is a lot and complex.

Given however that all we’re doing is issuing http requests you could use something as simple as cURL. Using PowerShell on an on-premise deployment this would look like this: curl [Organization URI]/api/data/v8.1/accounts?$select=accountnumber,name -Credential domain\username to get the account number and name for all accounts in CRM. Try that to get a feel of the data.

In Python we used the requests and pycurl modules. For the requests module we also brought in the requests_ntlm module to provide NTLM authentication. Using pycurl our code would look like this:

from io import BytesIO
import json,pycurl

url='[Organization URI]/api/data/v8.1/accounts?$select=accountnumber,name'

request = pycurl.Curl()
response = BytesIO()

# Setup http request
request.setopt(pycurl.URL, url)
request.setopt(pycurl.WRITEDATA, response)
request.setopt(pycurl.HTTPAUTH,cURL.HTTPAUTH_NTLM)
request.setopt(pycurl.USERPWD,"{}:{}".format(<username>,<password>))

request.perform()
request.close()

# Retrieve response string and encode using the json module
response.getvalue()
json.loads(response.getvalue)

pycurl allows us to set a number options using the setopt method which covers most complex http requests that we may have. Using the requests module we have the following:

import json, requests
from requests_ntlm import HttpNtlmAuth

url='[Organization URI]/api/data/v8.1/accounts?$select=accountnumber,name'

# Issue http request
response = requests.get(url, auth=HttpNtlmAuth(<username>,<password>))

# Display response content in the console
response.content

# Use json module to encode the string content e.g. into a dictionary
accounts = json.loads(response.content)

We employ the json module to allow decoding and encoding of json strings returned from our http requests. The requests module allows you to call requests.json which can also encode the response output as json. requests also has a Session object which allows you to issue http request in the context of one session and leverage connection pooling.

In order to create a record you can setup the requests object with the appropriate headers. So given you want to create an account you would do something like this:

# Account to be created
target = {"name": "Sample Account",
          "creditonhold": true,
          "address1_latitude": 47.639483,
          "description": "Account description here.",
          "revenue": 5000000,
          "accountcategorycode": 1
         }
url='[Organization URI]/api/data/v8.1/accounts'
headers = {'Content-Type':'application/json; charset=utf-8' ;'Accept':'application/json'}
response = requests.post(url, auth=HttpNtlmAuth(<username>,<password>), data=target, headers=headers)

In the above example we are issuing a POST request hence the call to requests.post instead of get as was done previously.It is also possible to call Web-Api functions. In the below example we call the simple WhoAmI function.

requests.get('[Organization URI]/api/data/v8.1/WhoAmI', auth=HttpNtlmAuth(username,pwd))

You can pretty much do everything that is supported using the Dynamics CRM 2016 Web API. More on the CRM Web API is available on MSDN.