How to fetch leads from Microsoft Dynamics 365 Sales using Python

Microsoft Dynamics 365 Sales offers a robust customer relationship management (CRM) system, enabling businesses to understand their customers' needs more accurately, engage accounts more intelligently, and secure more deals.

While there's a variety of data worth pulling from Microsoft Dynamics 365 Sales, leads are likely at or near the top of your list.

To help you get leads from the CRM in Python, we'll breakdown each step you need to follow.

Related: Marketing automation integration examples

Authentication

Before you can pull leads from the Microsoft Dynamics 365 Sales API, you need to authenticate with the service. You can this through an OAuth 2.0 Authorization Code grant type.

First, set up an OAuth flow with Microsoft Dynamics 365 Sales. Users should navigate to the authorization URL, https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize, to authorize. Once the user completes the authorization flow, Microsoft Dynamics 365 Sales will navigate the user to your provided <code class="blog_inline-code">redirect_url</code> and include the authorization code as a query parameter, <code class="blog_inline-code">code</code>. This code can be exchanged for an access token.

Include the scopes <code class="blog_inline-code">https://{DOMAIN}.dynamics.com/.default offline_access</code> in the scope parameter in the authorization URL. For the token URL, use the <code class="blog_inline-code">client ID</code> and secret provided by Microsoft Dynamics 365 Sales.

To request the access token, hit the token URL, <code class="blog_inline-code">https://login.microsoftonline.com/organizations/oauth2/v2.0/token</code>. Pass <code class="blog_inline-code">client_id</code>, <code class="blog_inline-code">client_secret</code>, and other parameters into the URL as body parameters. The header format should be <code class="blog_inline-code">Content-Type: application/x-www-form-urlencoded</code> for the token URL.

The access token can be found in the <code class="blog_inline-code">access_token</code> key in the response of the token URL. Use the <code class="blog_inline-code">expires_in</code> value in the response body of the token URL to determine the lifespan of the token. The refresh token can be found in the <code class="blog_inline-code">refresh_token key</code> in the response. Use the token URL to refresh the access token when it expires.

How to pull leads from Microsoft Dynamics 365


First, define your Microsoft Dynamics 365 Sales domain:

DOMAIN = 'YOUR_DOMAIN'

Then define your Microsoft Dynamics 365 Sales client id and secret:

CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'

Establish your redirect url:

REDIRECT_URL = 'YOUR_REDIRECT_URL'

Designate your authorization url and scopes:

AUTH_URL = 'https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize'
SCOPES = f'https://{DOMAIN}.dynamics.com/.default offline_access'

Specify your token url:

TOKEN_URL = 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token'

Exchange the authorization code for an access token:

def get_access_token(code):
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}
    data = {
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'code': code,
        'redirect_uri': REDIRECT_URL,
        'grant_type': 'authorization_code',
        'scope': SCOPES
    }
    response = requests.post(TOKEN_URL, headers=headers, data=data)
    if response.status_code == 200:
        return response.json().get('access_token')
    else:
        return None

Retrieve the Leads from Microsoft Dynamics 365 Sales

def get_leads(access_token):
    headers = {'Authorization': 'Bearer ' + access_token}
    response = requests.get(f'https://{DOMAIN}.dynamics.com/api/data/v9.0/leads', headers=headers)
    if response.status_code == 200:
        return response.json()
    else:
        return None

Get the authorization code:

Note: In a real world scenario, this would be the result of a user action to authorize the application.

code = 'YOUR_AUTHORIZATION_CODE'

Get the access token using the authorization code:

access_token = get_access_token(code)

Fetch the leads using the access token:

leads = get_leads(access_token)
print(leads)

Replace <code class="blog_inline-code">'YOUR_DOMAIN'</code>, <code class="blog_inline-code">'YOUR_CLIENT_ID'</code>, <code class="blog_inline-code">'YOUR_CLIENT_SECRET'</code>, <code class="blog_inline-code">'YOUR_REDIRECT_URL'</code> and <code class="blog_inline-code">'YOUR_AUTHORIZATION_CODE'</code> with your actual values.

This script first exchanges an authorization code for an access token. It then uses that access token to authenticate a request to the Microsoft Dynamics 365 Sales leads endpoint and retrieve leads data. The results are then printed to the console.

You should see the list of Leads from Microsoft Dynamics 365 Sales as the output.

{
    "@odata.context": "https://services.odata.org/V4/(S(4h1gie24gh0cc1gv4wtobl1r))/TripPinServiceRW/",
    "value": [
        {
            "@odata.etag": "W/\"08D7D405123456789\"",
            "mobilephone": "+1 123 456 7890",
            "address1_country": "United States",
            "merged": false,
            "prioritycode": 1,
            "confirminterest": false,
            "exchangerate": 1.5,
            "_parentaccountid_value": "12345678-1234-1234-1234-1234567890",
            "decisionmaker": true,
            "modifiedon": "2021-09-18T20:30:00Z",
            "revenue_base": 50000.0,
            "_owninguser_value": "1234567a-1234-1234-1234-1234567890",
            "address1_shippingmethodcode": 1,
            "address1_composite": "123 Main St, City, State 12345",
            "lastname": "Doe",
            "donotpostalmail": false,
            "numberofemployees": 100,
            "donotphone": false,
            "preferredcontactmethodcode": 2,
            "_ownerid_value": "1234567b-1234-1234-1234-1234567890",
            "sic": "1234",
            "firstname": "John",
            "evaluatefit": false,
            "yomifullname": "John Doe",
            "address2_addresstypecode": 2,
            "donotemail": false,
            "address2_shippingmethodcode": 2,
            "fullname": "John Doe",
            "address1_addressid": "1234567c-1234-1234-1234-1234567890",
            "msdyn_gdproptout": false,
            "statuscode": 1,
            "createdon": "2021-09-18T20:30:00Z",
            "address1_stateorprovince": "State",
            "_msdyn_predictivescoreid_value": "1234567d-1234-1234-1234-1234567890",
            "companyname": "Company Name",
            "donotfax": false,
            "leadsourcecode": 1,
            "jobtitle": "Developer",
            "versionnumber": 123456789,
            "address1_line1": "123 Main St",
            "emailaddress1": "johndoe@example.com",
            "telephone1": "+1 123 456 7890",
            "donotsendmm": false,
            "leadqualitycode": 1,
            "_transactioncurrencyid_value": "1234567e-1234-1234-1234-1234567890",
            "subject": "Introduction",
            "address1_addresstypecode": 1,
            "donotbulkemail": false,
            "_modifiedby_value": "1234567f-1234-1234-1234-1234567890",
            "followemail": true,
            "leadid": "1234567g-1234-1234-1234-1234567890",
            "_createdby_value": "1234567h-1234-1234-1234-1234567890",
            "websiteurl": "https://www.example.com",
            "address1_city": "City",
            "salesstagecode": 1,
            "_msdyn_leadkpiid_value": "1234567i-1234-1234-1234-1234567890",
            "revenue": 50000.0,
            "purchasetimeframe": 1,
            "participatesinworkflow": true,
            "statecode": 1,
            "_owningbusinessunit_value": "1234567j-1234-1234-1234-1234567890",
            "address2_addressid": "1234567k-1234-1234-1234-1234567890",
            "address1_postalcode": "12345",
            "telephone3": "+1 123 456 7891",
            "businesscardattributes": null,
            "address1_upszone": "Zone 1",
            "address2_city": "City 2",
            "_slainvokedid_value": "1234567l-1234-1234-1234-1234567890",
            "address1_postofficebox": "PO Box 123",
            "importsequencenumber": 1,
            "utcconversiontimezonecode": 1,
            "schedulefollowup_qualify": null,
            "overriddencreatedon": null,
            "stageid": null,
            "msdyn_leadscore": null,
            "address1_latitude": 36.1699,
            "address1_utcoffset": -8,
            "yomifirstname": "John",
            "estimatedclosedate": null,
            "_masterid_value": null,
            "lastonholdtime": null,
            "address2_fax": null,
            "address2_line1": "456 Secondary St",
            "address1_telephone3": "+1 123 456 7892",
            "address1_telephone2": "+1 123 456 7891",
            "address1_telephone1": "+1 123 456 7890",
            "address2_postofficebox": "PO Box 456",
            "emailaddress2": "jdoe@example.com",
            "address2_latitude": 40.7128,
            "processid": null,
            "emailaddress3": "john.doe@example.com",
            "address2_composite": "456 Secondary St, City 2, State 2 67890",
            "salesstage": null,
            "traversedpath": null,
            "qualificationcomments": null,
            "address2_line2": "Apt 456",
            "teamsfollowed": null,
            "budgetamount": 10000.0,
            "address2_stateorprovince": "State 2",
            "address2_postalcode": "67890",
            "estimatedamount": null,
            "entityimage_url": null,
            "initialcommunication": null,
            "msdyn_scorehistory": null,
            "timezoneruleversionnumber": null,
            "estimatedamount_base": null,
            "address2_telephone3": "+1 123 456 7893",
            "need": null,
            "address2_telephone2": "+1 123 456 7892",
            "address2_telephone1": "+1 123 456 7891",
            "address2_upszone": "Zone 2",
            "_owningteam_value": null,
            "budgetstatus": null,
            "address2_line3": "Unit 456",
            "timespentbymeonemailandmeetings": null,
            "businesscard": null,
            "address2_longitude": 74.006,
            "_modifiedonbehalfby_value": null,
            "address1_line2": "Apt 123",
            "address1_county": "County",
            "schedulefollowup_prospect": null,
            "msdyn_leadscoretrend": null,
            "address1_fax": "+1 123 456 7893",
            "_createdonbehalfby_value": null,
            "_accountid_value": null,
            "address2_name": "Secondary Address",
            "msdyn_leadgrade": null,
            "msdyn_scorereasons": null,
            "address2_utcoffset": -5,
            "_campaignid_value": null,
            "_slaid_value": null,
            "fax": null,
            "address2_county": "County 2",
            "_qualifyingopportunityid_value": null,
            "msdyn_salesassignmentresult": null,
            "address1_line3": "Unit 123",
            "_parentcontactid_value": null,
            "industrycode": null,
            "purchaseprocess": 1,
            "onholdtime": null,
            "entityimage_timestamp": null,
            "_customerid_value": null,
            "entityimageid": null,
            "lastusedincampaign": null,
            "_msdyn_segmentid_value": null,
            "_originatingcaseid_value": null,
            "telephone2": "+1 123 456 7891",
            "yomilastname": "Doe",
            "description": null,
            "_relatedobjectid_value": null,
            "_contactid_value": null,
            "yomimiddlename": null,
            "budgetamount_base": 10000.0,
            "address1_name": "Main Address",
            "yomicompanyname": null,
            "address1_longitude": 115.1728,
            "entityimage": null,
            "middlename": null,
            "estimatedvalue": null,
            "salutation": null,
            "pager": null,
            "address2_country": "United States"
        }
    ]
}

Final thoughts

It's highly probable that your clients utilize a diverse range of CRM systems—not just Microsoft Dynamics 365 Sales.

To cater to this varied landscape of CRM tools, you can build to Merge's CRM Unified API. Once you’ve built to it, you can offer dozens of CRM integrations to clients, whether that’s Salesforce, HubSpot, ActiveCampaign, etc.

You can learn more about Merge by scheduling a demo with one of our integration experts.