HUBSPOT
Connecting HubSpot to MapLogics
MapLogics reads the addresses on your HubSpot companies, works out which territory covers each one and who serves it, and can write that answer back onto the company record. This page is the setup, start to finish. If you are looking for the API instead, the API reference has the request and response shapes.
What it asks for, and what it does not
Three scopes at most, and the third is optional. Contacts, deals and tickets are never requested, because none of them is needed to decide anything.
| Scope | Requested | What it is for |
|---|---|---|
oauth | Always | Required by HubSpot of every app that uses OAuth. It is not permission over any of your data, and it cannot be declined. |
crm.objects.companies.read | Always | Reads company records so an address can be placed on the map. A company is the record that carries an address, which is the only thing a decision needs. |
crm.objects.companies.write | Only with write-back | Writes the decision back onto the company. Asked for on a second consent screen, and only if you turn write-back on while connecting. |
There is no schema scope on that list, which is deliberate and has one consequence you will meet in the next section: the app cannot create a property in your portal. Creating fields in somebody else's CRM is a larger permission than writing a value into a field they made themselves.
Before you connect
Only needed if you want the decision written back. If you are just reading addresses, skip to connecting.
- Decide which parts of the answer you want on the company. Most people start with the territory name and whether the address is serviceable, and add the rest later if they miss it.
- Create a property in HubSpot for each one. Settings, then Properties, then Company properties. Single-line text works for every source in the table below except
serviceable, which is happier as a checkbox. For the record owner, HubSpot already hashubspot_owner_idand you should use it rather than making a new one. - Note the internal names, not the labels. A property called Territory may have an internal name of
ml_territory, and the internal name is what MapLogics writes to. HubSpot shows it under the property's own settings.
A property that does not exist in the portal is not a failure of the sync. It comes back as an itemised refusal on the run, naming the property, so the rest of the records still get written while you go and create it.
Connecting
- In MapLogics, open Settings, then Integrations. Choose HubSpot.
- Decide write-back before you click connect. It changes which consent screen HubSpot shows you, so turning it on later means authorizing again.
- Authorize in HubSpot. Sign in as a user in the portal you want connected and approve the scopes. You come back to the integrations screen either way, and a refusal says what was refused.
- Check the portal on the connection card. It shows the portal domain, so if you are a member of several you can see at a glance that you connected the right one.
One HubSpot rule worth knowing in advance, because the error it produces says almost nothing: an app cannot be installed into the account that owns it. If you are testing with a developer account, connect a separate test portal.
Mapping your fields
A new connection starts with a mapping that works for a portal keeping addresses in the standard places. If yours are somewhere else, this is the screen that fixes it.
The properties read by default arename, address, address2, city, state, zip, country, phone, domain, and hs_lastmodifieddate. The record id is mapped separately, and it is the most important one on the list: it is what makes a second sync update a location instead of creating a duplicate. Two companies can genuinely share a name, so the name is never the key.
The field picker lists the properties your portal actually has, read from HubSpot when the screen loads, rather than a fixed list that would be wrong for most accounts. Properties HubSpot marks as hidden are left out, since those are its own bookkeeping and there are dozens of them.
Writing the decision back
Off by default. Each field pairs one part of the decision with one property in your portal.
| Source | What gets written |
|---|---|
territory_id | The id of the territory that won. |
territory_name | The name of the territory that won. |
location_id | The id of the assigned location. |
location_name | The name of the assigned location. |
status | resolved, no_coverage, unserviceable, ambiguous, invalid_input or error. |
serviceable | true or false. Absent when the outcome did not settle the question. |
reason_code | The machine-readable reason, the same one the API returns. |
owner | The record owner in HubSpot, looked up from the territory. |
A rule output can be written too, addressed as output: followed by the key you named it. Everything else on the list is closed, so what a connection writes is always a question with a short answer.
Three things that surprise people
- Only differences are sent. A sync over companies nobody has touched writes nothing at all. This is not tidiness. A write bumps the last-modified date on a HubSpot company, so writing unchanged values on a schedule would touch your whole company database and fire every workflow hanging off it.
- Nothing is cleared unless you ask. A decision with no value for a field leaves the property as it was. Emptying
hubspot_owner_idunassigns an account from a salesperson, and doing that automatically because a boundary moved is not a default worth having. Set the field to clear if you mean it. - The property has to exist first. Covered above, and it is the single most common reason a first write-back does nothing.
What a sync does
The first sync of a new connection reads your companies, creates a location for each one and queues them to be placed on the map. It writes nothing back, because at that moment nothing has a coordinate yet. It runs itself again about eight minutes later, by which time the geocoder has caught up, and that second pass is the one that writes.
The second pass queues nothing further. It is the other half of one sync rather than a retry, which is what stops an address that can never be placed from scheduling a pass forever.
After that, syncs run on a schedule. When a company's address changes in HubSpot, its coordinate is cleared and placed again, because a location whose street moved but whose old pin did not gives a confident answer about a place the record no longer describes.
When it stops working
- The connection says the credential was revoked
- Somebody removed the app from the HubSpot portal, or the portal was closed. Reconnect from the integrations screen. Nothing is lost: the locations stay as they are.
- The run reports rejections naming a property
- The property does not exist in the portal, or it is read-only or calculated. Create it, or point the write-back field at one that exists, and the next run picks it up.
- The run says it wrote nothing
- It says why in one word.
writeback_offmeans it is switched off,no_write_permissionmeans the connection was not granted the write scope,nothing_publishedmeans there is no published configuration to decide against, andconnector_cannot_writemeans write-back is not available here at all. A run that reads six hundred records and writes none is either correct or broken, and those look identical without the word. - Addresses resolve to the wrong territory
- That is a configuration question rather than an integration one. Every answer carries a reason code saying which step decided it. The help centre covers the common ones.
Disconnecting
Disconnecting from the integrations screen revokes the refresh token with HubSpot, so the grant is gone on their side and not just forgotten on ours. You can also remove the app from inside HubSpot, under connected apps, which has the same effect. Either way the locations MapLogics created stay where they are, and so does everything you built on top of them. Only the link to HubSpot goes.
Getting help
Email hello@maplogics.com. Include the sync run id from the integrations screen if the problem is a sync, or the request id from a response if the problem is an answer. Either one lets us see exactly what happened, which is usually a two-minute reply instead of a two-day one.