Python API Wrapper for Freshsales Suite CRM
This is a library for the Freshsales Suite CRM for Python 3.6+.
It includes the following features from the Freshsales Suite CRM API:
- Contacts
- Marketing Lists
- Accounts
- Deals
- Notes
- Tasks
- Appointments
- Sales Activities
- Products
- Documents
- Selectors
Installation
The easiest way to install is from PyPi inside a virtualenv:
-
Create the virtualenv (Python 3.6+ supported) and activate it:
virtualenv env source env/bin/activate
-
Install from PyPi:
pip install python-freshworks-crm
-
Optionally, run the test suite:
pip install python-freshworks-crm[test] pytest
Usage
Please note the domain and API key are not real and the example will not work without changing these.
>>> from freshsales.api import API
>>> a = API('company.myfreshworks.com/crm/sales', 'fsdajfl323kj423rj2')
To find your API key, follow Freshworks CRM step-by-step solution article How to find your API key.
The API
class provides access to all the methods exposed by the Freshsales Suite CRM API.
General
Attributes are automatically converted to native Python objects where appropriate:
>>> a.contacts.list_contacts()[0].created_at
datetime.datetime(2023, 12, 5, 14, 7, 44)
Contacts
The Contacts API is accessed by using the methods assigned to the a.contacts
instance. Contacts are loaded as instances of the freshsales.models.Contact
class.
Create
>>> a.contacts.create_contact(first_name='Jane',
last_name='Sampleton',
emails='janesampleton@gmail.com',
custom_field=custom_field)
<Contact 'Jane Sampleton'>
With custom fields:
>>> custom_field = {'custom_field_1': 'custom_value_1',
'custom_field_2': 'custom_value_2'}
>>> a.contacts.create_contact(first_name='Jane',
last_name='Sampleton',
emails='janesampleton@gmail.com',
custom_field=custom_field)
<Contact 'Jane Sampleton'>
To access any attribute of the contact, use the dot notation:
>>> contact.first_name
'Jane'
View
>>> a.contacts.view_contact(1)
<Contact 'John Doe'>
Views
>>> a.contacts.list_views()
[<View 'All Contacts'>, <View 'My Contacts'>]
List
>>> a.contacts.list_contacts()
[<Contact 'John Doe'>, <Contact 'Jane Sampleton'>]
Get specific page of contacts:
>>> a.contacts.list_contacts(page=2, per_page=5)
[<Contact 'John Doe'>, <Contact 'Jane Sampleton'>,...]
Update
>>> a.contacts.update_contact(1,
first_name='Jane',
last_name='Updated')
<Contact 'Jane Updated'>
Upsert
>>> a.contacts.upsert_contact(unique_identifier=('emails', 'janesampleton@gmail.com'),
first_name='Jane',
last_name='Upserted')
<Contact 'Jane Upserted'>
Delete
>>> a.contacts.delete_contact(1)
True
Forget
>>> a.contacts.forget_contact(1)
True
List Fields
>>> a.contacts.list_fields()
[<Field 'first_name'>, <Field 'last_name'>, <Field 'emails'>, ...]
List Activities
>>> a.contacts.list_activities(1)
[<Activity 'Call'>, <Activity 'Email'>, <Activity 'Meeting'>, ...]
Marketing Lists
The Marketing Lists API is accessed by using the methods assigned to the a.lists
instance. Marketing Lists are loaded as instances of the freshsales.models.List
class.
Create
>>> a.lists.create_list(name='My List')
<List 'My List'>
View
>>> a.lists.view_list(1)
<List 'My List'>
List
>>> a.lists.fetch_all_lists()
[<List 'My List'>, <List 'My Other List'>]
Update
>>> a.lists.update_list(1,
name='My Updated List')
<List 'My Updated List'>
Fetch Contacts
>>> a.lists.fetch_contacts_from_list(1)
[<Contact 'John Doe'>, <Contact 'Jane Sampleton'>]
Add Contacts
>>> a.lists.add_contacts_to_list(1, [1, 2])
'2 contacts updated.'
Remove Contacts
>>> a.lists.remove_contacts_from_list(1, [1, 2])
'2 contacts updated.'
Move Contacts
>>> a.lists.move_contacts_to_list(2, [1, 2])
'2 contacts updated.'
Accounts
The Accounts API is accessed by using the methods assigned to the a.accounts
instance. Accounts are loaded as instances of the freshsales.models.Account
class.
Create
>>> a.accounts.create_account(name='My Account')
<Account 'My Account'>
View
>>> a.accounts.view_account(1)
<Account 'My Account'>
Views
>>> a.accounts.list_views()
[<View 'My View'>, <View 'My Other View'>]
List
>>> a.accounts.list_accounts()
[<Account 'My Account'>, <Account 'My Other Account'>]
Note: supports pagination similar to contacts.
Update
>>> a.accounts.update_account(1,
name='My Updated Account')
<Account 'My Updated Account'>
Upsert
>>> a.accounts.upsert(unique_identifier=('name', 'My Account'),
name='My Upserted Account')
<Account 'My Upserted Account'>
Clone
>>> a.accounts.clone_account(1)
<Account 'My Cloned Account'>
Delete
>>> a.accounts.delete_account(1)
True
Forget
>>> a.accounts.forget_account(1)
True
List Fields
>>> a.accounts.list_fields()
[<Field 'name'>, <Field 'website'>, <Field 'industry'>, ...]
Deals
The Deals API is accessed by using the methods assigned to the a.deals
instance. Deals are loaded as instances of the freshsales.models.Deal
class.
Create
>>> a.deals.create_deal(name='My Deal')
<Deal 'My Deal'>
View
>>> a.deals.view_deal(1)
<Deal 'My Deal'>
Views
>>> a.deals.list_views()
[<View 'My View'>, <View 'My Other View'>]
List
>>> a.deals.list_deals()
[<Deal 'My Deal'>, <Deal 'My Other Deal'>]
Note: supports pagination similar to contacts.
Update
>>> a.deals.update_deal(1,
name='My Updated Deal')
<Deal 'My Updated Deal'>
Upsert
>>> a.deals.upsert(unique_identifier=('name', 'My Deal'),
name='My Upserted Deal')
<Deal 'My Upserted Deal'>
Clone
>>> a.deals.clone_deal(1)
<Deal 'My Cloned Deal'>
Delete
>>> a.deals.delete_deal(1)
True
Forget
>>> a.deals.forget_deal(1)
True
List Fields
>>> a.deals.list_fields()
[<Field 'name'>, <Field 'amount'>, <Field 'stage'>, ...]
Notes
The Notes API is accessed by using the methods assigned to the a.notes
instance. Notes are loaded as instances of the freshsales.models.Note
class.
Create
>>> a.notes.create_note(description='My Note',
targetable_type='Contact',
targetable_id=1)
<Note 'My Note'>
Update
>>> a.notes.update_note(1,
description='My Updated Note')
<Note 'My Updated Note'>
Delete
>>> a.notes.delete_note(1)
True
Tasks
The Tasks API is accessed by using the methods assigned to the a.tasks
instance. Tasks are loaded as instances of the freshsales.models.Task
class.
Create
>>> a.tasks.create_task(title='Sample Task',
description='This is just a sample task.',
due_date='Tue Jun 21 2099 11:00:00 GMT+0000',
owner_id=1,
targetable_id=1,
targetable_type='Contact')
<Task 'Sample Task'>`
View
>>> a.tasks.view_task(1)
<Task 'Sample Task'>
List
>>> a.tasks.list_tasks()
[<Task 'Sample Task'>, <Task 'My Other Task'>]
Note: supports pagination similar to contacts.
Update
>>> a.tasks.update_task(1,
title='Updated Task')
<sk 'Updated Task'>
Mark as Done
>>> a.tasks.mark_task_as_done(1)
<Task 'Updated Task'>
Delete
>>> a.tasks.delete_task(1)
True
Appointments
The Appointments API is accessed by using the methods assigned to the a.appointments
instance. Appointments are loaded as instances of the freshsales.models.Appointment
class.
Create
>>> a.appointments.appointments.create_appointment(
title='Sample Appointment',
description='This is just a sample Appointment.',
from_date='Mon Jun 20 2016 10:30:00 GMT+0530 (IST)',
end_date='Mon Jun 20 2016 11:30:00 GMT+0530 (IST)',
creater_id=1,
time_zone='Chennai',
location='Chennai, TN, India',
targetable_id=1,
targetable_type='Contact')
<Appointment 'Sample Appointment'>
View
>>> a.appointments.view_appointment(1)
<Appointment 'Sample Appointment'>
List
>>> a.appointments.list_appointments()
[<Appointment 'Sample Appointment'>, <Appointment 'My Other Appointment'>]
Note: supports pagination similar to contacts.
Update
>>> a.appointments.update_appointment(1,
title='Updated Appointment')
< 'Updated Appointment'>
Delete
>>> a.appointments.delete_appointment(1)
True
Sales Activities
The Sales Activities API is accessed by using the methods assigned to the a.sales_activities
instance. Sales Activities are loaded as instances of the freshsales.models.SalesActivity
class.
Create
>>> a.sales_activities.sales_activities.create_activity(
title='My Activity',
notes='sample',
targetable_id=1,
targetable_type='Contact',
start_date='2017-12-04T17:00:00+05:30',
end_date='2017-12-04T17:30:00+05:30',
owner_id=1,
sales_activity_type_id=1)
<SalesActivity 'My Activity'>
View
>>> a.sales_activities.view_activity(1)
<SalesActivity 'My Activity'>
List
>>> a.sales_activities.list_activities()
[<SalesActivity 'My Activity'>, <SalesActivity 'My Other Activity'>]
Note: supports pagination similar to contacts.
Activity Fields
>>> a.sales_activities.list_fields()
[<Field 'title'>, <Field 'notes'>, <Field 'start_date'>, ...]
Update
>>> a.sales_activities.update_activity(1,
title='Updated Activity')
<Activity 'Updated Activity'>
Delete
>>> a.sales_activities.delete_activity(1)
True
Products
The Products API is accessed by using the methods assigned to the a.products
instance. Products are loaded as instances of the freshsales.models.Product
class.
Create
>>> a.products.create_product(
name='My Product',
description='This is a sample product',
category='Software',
is_active=True,
product_code='sample_product',
sku_number='sample_sku',
)
<Product 'My Product'>
View
>>> a.products.view_product(1)
<Product 'My Product'>
Update
>>> a.products.update_product(1,
name='Updated Product')
<Product 'Updated Product'>
Delete
>>> a.products.delete_product(1)
True
Restore
>>> a.products.restore_product(1)
<Product 'Updated Product'>
Edit Product Prices
>>> product_pricings = [
{"currency_code": "USD", "unit_price": 2000}
]
product = api.products.edit_product_prices(
1,
product_pricings=product_pricings
)
<Product 'Updated Product'>
Delete Product Prices
>>> product = api.products.delete_product_prices(1,
[100, 101])
<Product 'Updated Product'>
Add Products to Deal
>>> products = [{"id": 100}]
deal = api.products.add_products_to_deal(
1,
products=products
)
<Deal 'Updated Deal'>
Edit Deal Products
>>> products = [{"id": 100, "quantity": 2}]
deal = api.products.edit_deal_products(
1,
products=products
)
<Deal 'Updated Deal'>
Delete All Deal Products
>>> deal = api.products.delete_all_deal_products(1)
<Deal 'Updated Deal'>
Documents
The Documents API is accessed by using the methods assigned to the a.documents
instance. Documents are loaded as instances of the freshsales.models.Document
class.
Create
>>> a.documents.create_document(
deal_id=1,
contact_id=1,
display_name='Sample Document',
document_type='Quote',
cpq_document_template_name='Sample Template',
currency_code='USD'
)
<Document 'Sample Document'>
View
>>> a.documents.view_document(1)
<Document 'Sample Document'>
Update
>>> a.documents.update_document(1,
display_name='Updated Document')
<Document 'Updated Document'>
Delete
>>> a.documents.delete_document(1)
True
Restore
>>> a.documents.restore_document(1)
<Document 'Updated Document'>
Forget
>>> a.documents.forget_document(1)
True
Add Products to Document
>>> products = [
{"id": 100, "quantity": 2}
]
document = api.documents.add_products_to_document(
1,
products=products
)
<Document 'Updated Document'>
Edit Products of Document
>>> products = [
{"id": 100, "quantity": 3}
]
document = api.documents.edit_products_of_document(
1,
products=products
)
<Document 'Updated Document'>
Delete All Products from Document
>>> document = api.documents.delete_products_from_document(1)
<Document 'Updated Document'>
Selectors
The Selectors API is accessed by using the methods assigned to the a.selectors
instance. Selectors are loaded as instances of the freshsales.models.Selector
class.
Users
>>> a.selectors.get_users()
[<User 'John Doe'>, <User 'Jane Doe'>]
Territories
>>> a.selectors.get_territories()
[<Territory 'North America'>, <Territory 'South America'>]
Deal Stages
>>> a.selectors.get_deal_stages()
[<DealStage 'Prospecting'>, <DealStage 'Qualification'>]
Currencies
>>> a.selectors.get_currencies()
[<Currency 'USD'>, <Currency 'EUR'>]
Deal Reasons
>>> a.selectors.get_deal_reasons()
[<DealReason 'New Business'>, <DealReason 'Renewal'>]
Deal Types
>>> a.selectors.get_deal_types()
[<DealType 'New Business'>, <DealType 'Renewal'>]
Lead Sources
>>> a.selectors.get_lead_sources()
[<LeadSource 'Website'>, <LeadSource 'Email'>]
Industry Types
>>> a.selectors.get_industry_types()
[<IndustryType 'Agriculture'>, <IndustryType 'Construction'>]
Business Types
>>> a.selectors.get_business_types()
[<BusinessType 'Customer'>, <BusinessType 'Competitor'>]
Deal Payment Statuses
>>> a.selectors.get_deal_payment_statuses()
[<DealPaymentStatus 'Paid'>, <DealPaymentStatus 'Unpaid'>]
Deal Products
>>> a.selectors.get_deal_products()
[<DealProduct 'Product 1'>, <DealProduct 'Product 2'>]
Deal Pipelines
>>> a.selectors.get_deal_pipelines()
[<DealPipeline 'Sales Pipeline'>, <DealPipeline 'Renewal Pipeline'>]
Contact Statuses
>>> a.selectors.get_contact_statuses()
[<ContactStatus 'Open'>, <ContactStatus 'Closed'>]
Sales Activity Types
>>> a.selectors.get_sales_activity_types()
[<SalesActivityType 'Call'>, <SalesActivityType 'Email'>]
Sales Activity Entity Types
>>> a.selectors.get_sales_activity_entity_types()
[<SalesActivityEntityType 'Contact'>, <SalesActivityEntityType 'Deal'>]
Sales Activity Outcomes
>>> a.selectors.get_sales_activity_outcomes()
[<SalesActivityOutcome 'Success'>, <SalesActivityOutcome 'Failure'>]
Lifecycle Stages
>>> a.selectors.get_lifecycle_stages()
[<LifecycleStage 'Lead'>, <LifecycleStage 'Customer'>]
Filtering Contacts
You can efficiently filter through your contacts using the dynamic Filter API. Here's a quick guide on how to utilize it:
Filter Data Format
The filter accepts a dictionary with a key named filter_rule
. This key holds a list of filtering criteria, and each criterion is a dictionary with the following keys:
-
attribute: Specifies the attribute of a contact you want to filter on.
-
operator: Describes the kind of operation you'd like to perform. Examples include:
is_in
is_not_in
is_before
is_after
is_in_the_range
- ... (more operators can be added as needed)
-
value: The value you want the attribute to be compared against.
Example
Here's a simple example that filters contacts based on their email address:
filter_data = [
{
"attribute": "contact_email.email",
"operator": "is_in",
"value": "jamessampleton@gmail.com"
}
]
results = a.search.filter_contacts(filter_data)
print(results) # [<Contact 'James Sampleton'>]
Testing
To run the tests, you'll need to install the development dependencies:
pip install python-freshworks-crm[test]
Then, you can run the tests with:
pytest
Travis CI will run the tests against Python 3.6, 3.7, 3.8, 3.9., 3.10, and 3.11
You can also use Tox to run the tests against all supported versions of Python:
tox
Contributing
Contributions are welcome! Bulk APIs as well as endpoints such as Files, Search (partially complete), Phone, .. are not implemented yet. Feel free to open a pull request.