python-freshworks-crm

An API wrapper for the Freshsales CRM


License
BSD-3-Clause
Install
pip install python-freshworks-crm==1.1.2

Documentation

Python API Wrapper for Freshsales Suite CRM

PyPI Stars Forks

Build Status codecov Downloads License

This is a library for the Freshsales Suite CRM for Python 3.6+.

It includes the following features from the Freshsales Suite CRM API:

Installation

The easiest way to install is from PyPi inside a virtualenv:

  1. Create the virtualenv (Python 3.6+ supported) and activate it:

    virtualenv env
    source env/bin/activate
    
  2. Install from PyPi:

    pip install python-freshworks-crm
    
  3. 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.