Migrate Accounts, Contacts, Deals & Attachments from Freshsales to Zoho CRM Using Python
Below is a Python-based solution to migrate Accounts, Contacts, Deals, and their associated files from Freshsales to Zoho CRM using the Zoho CRM Bulk APIs. This script can be run directly from your local machine — just ensure that Python and all required dependencies are installed.
Data Structure and Approach
We’ve structured the migration process by treating the Accounts module as the parent object. For each account, the script:
- Fetches related Contacts, Deals, and Attachments
- Identifies Deals associated with Contacts
- Collects file IDs for Accounts, Contacts, and Deals
Instead of directly transferring files, we collect file IDs and include them as JSON key-value pairs within the parent record data sent to Zoho CRM.
In Zoho CRM, you can use Deluge’s invokeURL
function to download and attach files based on the file ID provided. This makes the migration process more streamlined and avoids file handling issues in Python.
Zoho CRM Setup
- Create a standalone Deluge function in Zoho CRM.
- Inside this function, use custom logic and the
zoho.crm.bulkCreate("Module", {data});
API. - Trigger this function from the Python script using an HTTP request, as shown in the code.
This modular setup ensures flexibility and scalability for large datasets.
import json
import requests
from decimal import Decimal
API_Key = '1234567'
def getFiles(parentRecId):
endPointUrl = f'https://yourDomain.myfreshworks.com/crm/sales/api/sales_accounts/{parentRecId}/document_associations'
headerMap = {
'Authorization': f'Token token={API_Key}',
'Content-Type': 'application/json'
}
getAttachments = requests.get(endPointUrl, headers=headerMap)
file_Id_List = []
if getAttachments.status_code == 200:
for file in getAttachments.json().get('documents', []):
file_Id_List.append(file.get('id'))
return file_Id_List
def getContacts(parentAccountId):
endPointUrlCustomers = f'https://yourDomain.com/crm/sales/api/sales_accounts/{parentAccountId}?include=contacts'
headerMap1 = {
'Authorization': f'Token token={API_Key}',
'Content-Type': 'application/json'
}
getContacts = requests.get(endPointUrlCustomers, headers=headerMap1)
if getContacts.status_code == 200:
# print("All Contacts (JSON):", json.dumps(getContacts.json(), indent=2))
contact_Return_List = []
for contact in getContacts.json().get('contacts', []):
related_Deals = getDeals(contact.get('id'),'contacts')
related_Files = getFiles(contact.get('id')) or []
cf_fields = contact.get('custom_field') or {}
payload = {
'FreshSales_Rec_ID': contact.get('id'),
'First_Name': contact.get('first_name'),
'Last_Name': contact.get('last_name'),
'Mailing_City': contact.get('city'),
'Mailing_State': contact.get('state'),
'Mailing_Zip': contact.get('zipcode'),
'Country': contact.get('country'),
'Email': contact.get('email'),
'Employer_contact_number': contact.get('work_number'),
'Mobile': contact.get('mobile_number'),
'Mailing_Street': contact.get('address'),
###### Custom Fields ######
'Employment_Category': cf_fields.get('cf_employment_category'),
'Employment_Status': cf_fields.get('cf_employer_status'),
'Occupation_Position': cf_fields.get('cf_occupation'),
'Employer_Name': cf_fields.get('cf_employer_name'),
###########
'related_Deals': related_Deals,
'related_Files': related_Files
}
contact_Return_List.append(payload)
#print("contact_List: ", contact_List)
print("**************************")
return contact_Return_List
def getDeals(parentRecId,ParentRecType):
endPointUrlDeals = f'https://yourDomain.myfreshworks.com/crm/sales/api/{ParentRecType}/{parentRecId}?include=deals'
headerMap1 = {
'Authorization': f'Token token={API_Key}',
'Content-Type': 'application/json'
}
getDeals = requests.get(endPointUrlDeals, headers=headerMap1)
deal_Return_List = []
if getDeals.status_code == 200:
#print("All Contacts (JSON):", json.dumps(getDeals.json(), indent=2))
for deal in getDeals.json().get('deals', []):
######## Get The Attchements #############
related_Files = getFiles(deal.get("id")) or []
#################
payload={
"FreshSales_Rec_ID":deal.get("id"),
"Deal_Name" : deal.get("name"),
"Amount" : deal.get("amount"),
"Closing_Date" : deal.get("closed_date"),
"related_Files": related_Files
}
deal_Return_List.append(payload)
#print("deal_List: ", deal_Return_List)
print("**************************")
return deal_Return_List
def getAccounts():
viewId = '111111111'### USE ACTUAL VIEW ID From FreshSales
endPointUrl = f'https://yourDomain.myfreshworks.com/crm/sales/api/sales_accounts/view/{viewId}'
headerMap = {
'Authorization': f'Token token={API_Key}',
'Content-Type': 'application/json'
}
response = requests.get(endPointUrl, headers=headerMap)
if response.status_code == 200:
# print("All Accounts (JSON):", json.dumps(response.json(), indent=2))
acccount_Return_List = []
for account in response.json().get('sales_accounts', []):
################### Get The Child Recs Of The Account ##################
print("Account ID: ", account.get('id'))
related_Contacts = getContacts(account.get('id'))
related_Deals = getDeals(account.get('id'),'sales_accounts')
related_Files = getFiles(account.get('id')) or []
######################################################################
payload = {
'FreshSales_Rec_ID' : account.get('id'), ### unique Field in Zoho CRM
'Account_Name' : account.get('name'),
'Billing_Street' : account.get('address'),
'Billing_City' : account.get('city'),
'Billing_State' : account.get('state'),
'Billing_Code' : account.get('zipcode'),
'Billing_Country' : account.get('country'),
'Number_of_Employees' : account.get('number_of_employees'),
'Annual_Revenue' : account.get('annual_revenue'),
'Website' : account.get('website'),
'Phone' : account.get('phone'),
'related_contacts':related_Contacts,
'related_deals':related_Deals,
'related_files':related_Files
}
acccount_Return_List.append(payload)
########################### Invoke Zoho CRM Function #####################################
else:
print("Failed to fetch accounts. Status code:", response.status_code)
print("Response:", response.text)
return acccount_Return_List
############ Invoke The Primary Function - getAccounts ##############
data_List = getAccounts()
clean_data = json.dumps(data_List, indent=2)
##### Invoking Zoho CRM REST API Function ############
# crmUrl = 'https://sandbox.zohoapis.com/crm/v7/functions/datamigration/actions/execute?auth_type=apikey&zapikey=1123'
# hitCRM = requests.post(crmUrl, json=clean_data)
# print('CRM Response Code: ', hitCRM.status_code)
print('Return_List: ',data_List)