Pipedrive API wrapper for Pypedrive written in Python.
NOTE : This fork is an Object Oriented extention of the original library allowing automatic navigation and attribute access between entity classes and handling custom fields and a lot more.
It lets you do stuff like
for p in person.org.persons:
p.deals
And access custom fields (p.admin) including setting and saving them (p.admin = 'Yes' , client.save_changes(p))
Expose all fields (inc custom) as attributes (both get and set) without having to use the hex API keys.
Custom fields :-
load all custom fields using API on first API hit
caches custom fields in local per entity json files (remove to update)
converts the custom field keys to the field value
When modifiying custom fields with set values, validates the new value
Links related objects automatically (person.org.deals)
Creates stubs for them until the they get fully loaded then refreshes them
Handles modifying objects using attributes (including custom fields)
Keeps a list of modified fields
Added client.save_changes(entity)
Added automatic pagination
client.get_persons(limit=5000) will make up to 10 hits of 500 returning all and refreshing any stubs
Retains access to raw json data (with .data)
Allows empty Client constructor if pipedrive_settings.json exists
Added examples folder
To use the original, non OO version, use either :-
from pipedrive.ooclient import *
# OR
from pipedrive.client import *
# and
client = Client()
To use the new OO version, use
from pipedrive.ooclient import *
client = OOClient()
It's extended to automatically and transparently create a OO Entity cache with all returned API data available, including the sometimes stripped down relationship stubs that get returned. This allows
persons = client.get_persons(limit=5000) # Load up to 5000 people with auto API pagination, and return Person objects
person=Person.get_by_id(728) # Now get a specific one, which has stubs for org and owner (from the persons json)
print(f"{person.name} belongs to {person.org.name} and is owned by {person.owner.name}") # Field access, using the owner "stub" from loading the persons
print(f"{person} belongs to {person.org} and is owned by {person.owner}") # A useful __str__
Which outputs the following
John Johnson belongs to JJ Works and is owned by Craig
Person(728,John Johnson) belongs to Organization(713,JJ Works) and is owned by User(61100,Craig)
See the examples folder for some basic examples of what it can do. https://github.com/shanness/pipedrive-python/tree/master/examples For example this will load up to 5000 person objects with stubs (partial objects) for their organizations.
>>> from pipedrive.ooclient import *
>>> client = OOClient()
>>> persons = client.get_persons(limit=5000)
>>> person=Person.get_by_id(728) # Let's get a specific one from the loaded set
>>> # Navigation, caching, stub to full entity etc between entity relationships is completely automatic.
>>> # As most API endpoints return decent partial relationship data, loading the people above will set their orgs
>>> org currently a stub. Also the entity's hide some unpleasant inconsistencies in Pipedrive API data
>>> print(person,"has",person.org)
Person(728,James Randi) has Organization(712,Randi Foundation)
>>> person.org.stub # check if it's a stub
True
>>> # Shows which fields are available on these stubs
>>> print("Org field names (from person stubs): ",person.org.get_field_names())
Org field names (from person stubs): ['name', 'people_count', 'owner_id', 'address', 'active_flag', 'cc_email', 'id']
>>> # The stubs (included in the PD API returned person json data in this case) mean that you can access basic org stuff without needing to hit the org API endpoint
>>> print(f"{person} is from {person.org.name} - which have {person.org.people_count} {[p for p in person.org.]}")
Person(728,James Randi) is from C Eather Photography - org is stub = False
Now for the magic. Relationships and custom fields handled.
>>> # This loads up the orgs, replacing the stubs. Works for Person, Organization, Deal, Pipeline, Stage, User, Product, Note, Activity, linking all relationships between them together on load.
>>> orgs = client.get_organizations(limit=5000)
>>> # Now we have access to all the org data
>>> print(person.org.closed_deals_count)
2
>>> # And it automatically handles custom fields. Custom fields are cached.
>>> # If you add a new custom field or drop down value, just delete the .json cache files and it'll refresh them
>>> print(person.org.member_type)
Supplier
It also handles changing and saving data
>>> # Modify entities
>>> person.name = "New Name"
>>> # Including custom fields
>>> person.admin = 'True' # This is validated as valid value for this custom field.
>>> # You can check what fields are modified if any
>>> print(person," has these fields modified",person.modified_fields)
Person(728,New Name) has these fields modified ['4a43547838bfac29f9ea7895efdf43d39d0d9336', 'name']
>>> # Check if a entity is modified and what fields (currently the only place that custom fields aren't resolved)
>>> print(person,"has these fields modified after reload",person.modified_fields)
Person(728,New Name) has these fields modified after reload ['4a43547838bfac29f9ea7895efdf43d39d0d9336', 'name']
>>> # Save : This is used to save any entity type's changes. i.e. client.save_changes(my_deal)
>>> # client.save_changes(person) # (commented out to avoid stuffing your data)
>>> # And if you want to revert changes just re fetch it.
>>> # Note, no need to catch the return value, person is now updated (there is only ever at most one instance per id)
>>> client.get_persons(person_id=person.id)
To create new deals, this example
from pipedrive.ooclient import *
client = OOClient()
# First find the target pipeline and stage to add them too
pipelines = client.get_pipelines()
stages = client.get_stages()
pipeline = Pipeline.get_by_name("Your Pipeline Name")[0]
stage = [ stage for stage in pipeline.stages if stage.name == "Ready to send"][0]
print(pipeline,stage)
# Get everyone if your DB isn't huge
persons = client.get_persons(limit=5000)
# Filter to the segment however you like, for example a custom field called campaign with no open deals
target_people = [p for p in persons if p.campaign == 'Your campaign target' and p.open_deals_count == 0]
# Contine filtering if needed. (preset a target_country list before hand)
print("Filtering to countries : ",target_countries)
target_people = [p for p in target_people if p.country in target_countries]
# Create the deals
deal_count = 0
print("{0:<40} {1:<50} {2:<40} {3:20} {4:20}".format('Name','Company','Email Address','Country','Deal'))
print("{0:<40} {1:<50} {2:<40} {3:20} {4:20}".format('====','=======','=============','=======','======='))
blocking = {}
print("Creating a max of ",target_count," deals, and sleeping ",sleep_count," seconds between each one")
for p in target_people:
if p.lost_deals_count > 0:
blocking[p] = "Skipping because they have lost deals : " + str(p.lost_deals_count)
else:
deal_count += 1
deal = client.create_deal(title=p.name + " - your deal name",person_id=p.id,stage_id=stage.id,visible_to=3) # 3 = shared, removed org_id=p.org.id, as new LI imports don't have an org.
print("{0:<40.40} {1:<50.50} {2:<40.40} {3:20} {4:20}".format(p.name,p.companyname,p.email_address,p.country,str(deal)))
time.sleep(sleep_count)
if deal_count >= target_count:
print("Reached maximum deal count, stopping creating")
break
print("Created",deal_count,"deals")
## Installing
git clone
## Usage
- If you are not going to use the authentication flow, just send the "pipedrive company domain" and instance the library like this:
from pipedrive.client import Client client = Client(api_base_url='https://companydomain.pipedrive.com/')
- If on the contrary you will use it, send the "pipedrive company domain", the "client_id", the "client secret" and the parameter "oauth=True" in the main instance like this:
from pipedrive.client import Client client = Client(api_base_url='https://companydomain.pipedrive.com/', 'CLIENT_ID', 'CLIENT_SECRET', oauth=True)
#### Set token
And to make requests send the access token
client.set_token(access_token)
#### Get authorization url
url = client.get_oauth_uri("REDIRECT_URL", "OPTIONAL - state")
#### Exchange the code for an access token
token = client.exchange_code('REDIRECT_URL', 'CODE')
#### Refresh token
token = client.refresh_token('REFRESH TOKEN')
#### Get recent changes
token = client.get_recent_changes(since_timestamp="YYYY-MM-DD HH:MM:SS")
### Deals section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Deals
#### Get deals
If you need a specific deal send the deal id, if you don't just call the method
get_specific_deal = client.get_deals(deal_id="")
get_deals = client.get_deals()
#### Create deal
create_deal = client.create_deal(title="")
#### Update deal
update_deal = client.update_deal(deal_id="")
#### Delete deal
delete_deal = client.delete_deal(deal_id="")
#### Duplicate deal
duplicate_deal = client.duplicate_deal(deal_id="")
#### Get details of a deal
details_deal = client.get_deal_details(deal_id="")
#### Find deals by name
find_deal = client.get_deals_by_name(term="")
#### Get followers of a deal
followers_deal = client.get_deal_followers(deal_id="")
#### Add a follower to a deal
add_follower_deal = client.add_follower_to_deal(deal_id="", user_id="")
#### Delete a follower from a deal
delete_followers_deal = client.delete_follower_to_deal(deal_id="", follower_id="")
#### Get participants of a deal
get_participants_deal = client.get_deal_participants(deal_id="")
#### Add a participant to a deal
add_participants_deal = client.add_participants_to_deal(deal_id="", person_id="")
#### Delete a participant from a deal
delete_participants_deal = client.delete_participant_to_deal(deal_id="", participant_id="")
#### Get activities associated with a deal
get_activities_deal = client.get_deal_activities(deal_id="")
#### Get mail messages associated with a deal
get_messages_deal = client.get_deal_mail_messages(deal_id="")
#### Get products attached to a deal
get_products_deal = client.get_deal_products(deal_id="")
### Notes section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Notes
#### Get notes
If you need a specific note send the note id, if you don't just call the method
get_specific_note = client.get_notes(note_id="")
get_notes = client.get_notes()
#### Add a note
add_note = client.create_note(content="", org_id="")
#### Update a note
update_note = client.update_note(note_id="", content="")
#### Delete a note
delete_note = client.delete_note(note_id="")
### Organizations section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Organizations
#### Get organizations
If you need a specific organization send the organization id, if you don't just call the method
get_specific_organization = client.get_organizations(org_id="")
get_organizations = client.get_organizations()
#### Add organization
add_organization = client.create_organization(name="")
#### Update organization
update_organization = client.update_organization(data_id="", name="")
#### Delete an organization
delete_organization = client.delete_organization(data_id="")
### Persons section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Persons
#### Get persons
If you need the details of a person send the person id, if you don't just call the method
get_details_person = client.get_persons(person_id="")
get_persons = client.get_persons()
#### Get persons by name
find_persons = client.get_persons_by_name(term="")
#### Create person
add_persons = client.create_person(name="")
#### Update person
update_persons = client.update_person(data_id="", name="")
#### Delete person
delete_persons = client.delete_person(data_id="")
#### Get deals associated with a person
get_persons_deals = client.get_person_deals(person_id="")
### Products section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Products
#### Get products
If you need a specific product send the product id, if you don't just call the method
get_specific_product = client.get_products(product_id="")
get_products = client.get_products()
#### Get products by name
find_product = client.get_product_by_name(term="")
#### Create a product
add_product = client.create_product(name="")
#### Update a product
update_product = client.update_product(product_id="", name="")
#### Delete a product
delete_product = client.delete_product(product_id="")
#### Get deals where a product is attached to
get_product_deal = client.get_product_deal(product_id="")
### Activities section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Activities
#### Get activities
If you need the activity details send the activity id, if you don't just call the method
get_details_activity = client.get_activities(activity_id="")
get_activities = client.get_activities()
#### Create an activity
add_activity = client.create_activity(subject="", type="")
#### Update an activity
edit_activity = client.update_activity(activity_id="")
#### Delete an activity
delete_activity = client.delete_activity(activity_id="")
### Webhook section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Webhooks
#### Get webhooks
get_hooks = client.get_hooks_subscription()
#### Add webhook
add_hook = client.create_hook_subscription(subscription_url="", event_action="", event_object="")
#### Delete webhook
delete_hooks = client.delete_hook_subscription(hook_id="")
### Users section, see the api documentation: https://developers.pipedrive.com/docs/api/v1/#!/Users
#### Get users
users = client.get_users(user_id="")
## Requirements
- requests
## Contributing
Fork it ( https://github.com/GearPlug/pipedrive-python/fork ) Create your feature branch (git checkout -b my-new-feature) Commit your changes (git commit -am 'Add some feature') Push to the branch (git push origin my-new-feature) Create a new Pull Request