HubSpot is a system that simplifies the work of sales and marketing teams by automating routine tasks. You can configure your pipeline for deals and describe your workflow, or what will happen at each stage of the deal. It is not always possible to get by with the workflow functionality only. This may be because you are integrating with a custom company platform, or logic connected to an external database. For such cases, you can use the convenient and well-documented Hubspot API.
Our project (let's call it Portal) runs on Python 3 (Django Rest Framework), which stores a list of services sold by our client, the logic of calculating the cost of services, and more. In this article, I will describe some of the tasks that we have tackled using WebHooks and Hubspot’s API.
The pipeline of our Deal is as follows:
- Information Sent
- Deal won
When the Deal stage switches to the Approved value based on the data from Hubspot, we need to create a document of the ordered service (Order), to calculate the price of this service and to update the data in HubSpot. In this case, the first thing we have to do is to create a View and configure the router to receive and process the POST request.
We are using the versioning API and as a result, our uri will look like this:
As Hubspot expects to receive a response within 2 seconds, we won’t delay validating the signature and running the asynchronous Celery Tasks.
validate_signature will check the request data and if the data is not valid, an
Exception rest_framework.exceptions.ValidationError will be generated. Subsequently, the attacker will receive an HTTP Code 400 Bad Request. Here we finish the view setup.
We will not dwell on signature validation (
api.utils.hubspot.validate_signature), as it is described in the documentation with examples in Python. The main things to know are:
- Hubspot uses several versions of the signature
- Hubspot Webhooks uses the v1 version of the signature, with the validation method described here.
- The version can be determined by the header “X-HubSpot-Signature-Version”
- The signature itself is in “X-HubSpot-Signature” header
process_webhook task does the following:
- parses received json string
- creates an instance of the custom service class Hubspot Constructor of this class. Hubspot accepts two api_key parameters (needed for requests to the Hubspot API; we got it when creating the application in Hubspot) and portal_id (the Hubspot ID of the portal our client works with)
The main method of our service is a process, it takes a list of events and processes them in turns.
In event, we are interested in the following fields:
portalId- id of the portal from which we expect to receive updates, we process data only from the portal known to us
subscriptionType- type of subscription, for deal changes this value is: deal.propertyChange
propertyName- the name of the field that has been changed; with its help we determine what method we use to process this change
propertyValue- The new value of the field.
According to our logic, the method that handles the change of the Hubspot Deal Stage is deal_dealstage_changed. In compliance with our task, an Order should be created only when the dealstage changes to the Approved value; we ignore all other values.
To create an Order, we need additional fields from Hubspot, which we get through the API using the hubspot3 package, in particular, the DealsClient class.
After creating the Order, calculating its price, we update the data in the Hubspot Deal using the previously created instance of the DealsClient class. You can see the data structure for the update here, for the convenience of filling the array with updated fields, we created the add_property helper function:
We will be glad if the above described case is useful to the community =)
Hope it helps, and if you have any comments about the article, feel free to share them with us!