Hello! I am working on a project for a client leveraging Custom Objects / Serverless Functions in HubSpot. My goal is to clean up a lot of the pre-existing logic/object workarounds on my client's HubSpot account for a cleaner, more sane process utilizing Custom Objects.
Quick general outline of this project:
My client has HubSpot lead forms on their site for 'Get in touch with our Network of Dealers'. When a contact submits this qualifying form--
Form data is then POSTed to my client's Dealer API and then a list of dealers for this contact is returned (in a specific order) in the response.
These dealers are then associated with the contact record in HubSpot.
Emails then go out:
Contact receives an email with a list of the associated 'Dealers', in the exact order that was given by their Dealer API (this is important).
Every 'Dealer' that was associated with the contact each receives an email containing details of the contact (Lead Notification)
HubSpot is able to report on all of the above... ex. seeing which dealers opened their lead emails, which contacts opened the email, etc.
Given the outline above, we have generally had this working without using Custom Objects in our existing workflow process:
Instead of objects, we emulated this effect by using custom Contact properties, prefixed with an index number... like so: 01_dealer_name, 01_dealer_address. etc.
We have a PHP middleware setup to ingest the native HubSpot workflow Webhook action. PHP Middleware takes the webhook payload, parses out the needed properties and then hits the external API and maps that data back into the custom contact properties.
Limitations: As you can imagine, this is messy and does not scale well... we can only have 20 of the Dealer 'object' placeholders due to the amount of custom Contact properties it requires for each object. Since our external API can return more than 20 dealers and is also attributing the contact event into other databases, this is creating discrepancies in my client's reporting... there system will show that 26 dealers received this lead, however it was only really 20 lead emails sent.
New/Desired Workflow Process-- Rather than constantly appending data to contact records (data that might change!), I replicated the object schema for their Dealer API as Custom Objects in HubSpot and will be doing batch imports to sync it up with their systems each night... whatever is returned by the Dealer API will now already exist in HubSpot in the form of a Customer Dealer object. Given that, here's the flow I'm looking at:
Contact submits lead form to 'Connect with Dealers'.
HubSpot workflow triggers by form submission, then fires off our new Custom Workflow Action.
Custom Workflow Action sends the payload to our HubSpot Serverless Function (workflow action is configured to send the exact properties needed for the external API to our serverless function as the actionUrl).
Serverless function begins
Serverless function transforms the data and creates a request for the external API and sends out the request.
Serverless function receives list of dealers from external API and maps a list of ID's to use as search criteria.
Serverless function hits Search API with the list of IDs (these are matching a custom property on the search, not the actual object ID).
Serverless function receives the matched dealers from the Search API response. I map over these results to get the actual ObjectID's for the Custom Objects.
Serverless function then takes the dealer's Object ID's and associates them with the contact.
Serverless function ends (finally)
Current progress: All of these bullet points above on my 'New Workflow' are working with what I have developed so far... yay 🎉! Here's a quick screenshot of this, utilizing the nice new shiny labels from HubSpot:
What I now need to solve for:
Order/priority of associated objects So, believe it or not, this is where our current method of using custom Contact properties was actually helping us... we kept a prefix on the properties to act as an index for our objects. I need to find a way to replicate this effect with custom objects ... but at a contact level.
Example: I need to send the enrolled contact an email containing a list of the custom objects that were just associated with their contact record... this list must be in the exact order initially returned by the external API.
Brainstorm idea: Possibly saving the initial list of ID's from the external API as a contact property value... something like ['dealer231', dealer266', 'dealer555']. I would then use this value in a Hubl module and iterate the list variable to return a CRM_object() for each instance... however, since I need to use Object ID's for that Hubl function, I'm having trouble ensuring that the objectID's I have are actually 'in order'. This is because of the need to use the Search API to retrieve the actual Object ID's... I don't know of a way to ensure the Search API returns a list in the exact order it was given, when using something like:
I would essentially need a way to read these custom objects in the CRM by their custom property, but ensure the Search API returns them in the exact order of the values array that was given to it... Then I can save the list of HubSpot ObjectIDs in the proper order, to use in my CRM_object loop function.
Side note: Being able to set a 'priority' of association labels would be killer. See my screenshot above... Grand should take precedence over Select and be shown first, etc.
Batch Unassociate(?) Custom Objects from Contact by only ContactID and Object Type I need to account for contacts who re-enroll in this workflow. Let's say the contact already has associated dealers with their contact record and submits the form again... I need to completely 'wipe' any pre-existing associated Dealer objects with from the contact's record, so the contact can proceed in the workflow again and get in touch with other Dealers.
Issues faced: I don't see any documentation for dropping all associations from one object to another object type. It seems that I need to have all of the associated Object ID's first, then can use the /batch/archive v4 endpoint to create objects for each association I want to remove.
Given that, Is it possible to unassociate all objects of a Custom Object from a contact, only using the Contact ID? ...Rather than needing every custom object's ID, it would be helpful to just drop all associations of a custom object type from a contact.
Happy to hear anyone's thoughts on this... I practically live within HubSpots documentation pages nowadays, but these are some of the issues I can't seem to iron out. Any help/insight/advice would be super appreciated! And big shoutout to HubSpot for the awesome development taking place lately... thanks for making HubSpot such a great place for developing solutions for our clients. 😎
First, congrats on making the switch to custom objects, they really are a game changer when it comes to organizing your content within Hubspot !
Regarding your need to sort out dealers keeping the order given by the dealer API, I would have gone the custom property route on the contact too. Now to get the list of CO IDs in the same order as the result of your previous call, I see no other way than looping on your list and make a single search for each CO.
You can even run it using a serverless Hubspot function, this way you avoid putting too much pressure on your php middleware.
The function would :
- get the custom property storing the results of your dealer API
- loop on these values (in order) and use the search API for each one
- output the resulting list in another custom property
You can then follow-up with a hubl module and loop on that list to include them in the email.
Regarding the batch unassociate, I read the same documentation as you do and I don't see any way to batch delete associations between one contact and the many custom objects it's associated with.
To me the only solution to that problem lies (again) in iterating on the list of ID's you get from the batch read call :
First, congrats on making the switch to custom objects, they really are a game changer when it comes to organizing your content within Hubspot !
Regarding your need to sort out dealers keeping the order given by the dealer API, I would have gone the custom property route on the contact too. Now to get the list of CO IDs in the same order as the result of your previous call, I see no other way than looping on your list and make a single search for each CO.
You can even run it using a serverless Hubspot function, this way you avoid putting too much pressure on your php middleware.
The function would :
- get the custom property storing the results of your dealer API
- loop on these values (in order) and use the search API for each one
- output the resulting list in another custom property
You can then follow-up with a hubl module and loop on that list to include them in the email.
Regarding the batch unassociate, I read the same documentation as you do and I don't see any way to batch delete associations between one contact and the many custom objects it's associated with.
To me the only solution to that problem lies (again) in iterating on the list of ID's you get from the batch read call :
Thank you so much for your detailed response, @LMeert !
I am planning on completely replacing the existing PHP middleware for Serverless Functions, that's my hopes, at least.
With that in mind, should I be worried about overloading the serverless function itself? Currently, it's performing rather quickly... but I'm worried about iterating every dealer object individually into that Search API calls... it feels like it might be too many calls (conceptually) for a single Serverless Function.
Do you feel like this would be too much stress on a single function, or am I overthinking it? I suppose I could chain multiple functions together, but I'm trying to keep things as simple as possible initially.
Thanks again! Looking forward to hearing your thoughts.
Great idea to get rid of the middleware altogether, a great use of your operations professionnal subscription 🙂
To be honest, so far I have experimented with medium complexity custom code and have not gone over the limits, so I don't really have an answer to that question.
You could at least split the first call to the dealer API from the repeated calls to the search API and run these in two different workflow nodes.
There's no way to know for sure unless you try the more complex function (the second function), which I reckon you can quickly set up !
I think it all depends on the number of dealers returned by the API, but the limits mention a max of 128MB of memory as well as 10s of max execution time, it should be doable within those limits.
If you're too close to the limits, you could split the list in two and run the same function twice for security and have a third function to concatenate both resulting lists.
Hope this helps, I'd really appreciate if you could keep me updated with the results of your testing 🙂
Good luck,
Ludwig
CTO @ Mi4 Hubspot Platinum Partner and Integration Expert
Passionate human, very curious about everything data and automation.