Route new HubSpot leads to a sales territory and ping Slack

When a HubSpot contact lands with a street address, figure out the sales territory, write it back to HubSpot, and post the lead to the right Slack channel.

Agentic Task
HubSpotOpenStreetMap NominatimSlackSalesOperationsLead EnrichmentNotifications & Alerts

Build an agent workflow that auto-routes new HubSpot contacts to a sales territory and posts a heads-up in Slack the moment they land.

Trigger: a HubSpot webhook on the contact.creation event. The webhook should hand the agent the new contact's ID so it can fetch the full record.

Integrations:

1. HubSpot (Get Contact, Update Contact).

2. OpenStreetMap Nominatim (Search / Forward Geocode).

3. Slack (Send a Message).

What the agent should do, in order:

Step 1. Read the contact. Pull the contact from HubSpot by ID and read firstname, lastname, email, company, address, city, state, zip, and country.

Step 2. Bail early if there is no usable street address. If only a country is present, or every address field is empty, do not geocode. Clear the territory property by writing an empty string and exit without posting to Slack.

Step 3. Geocode with Nominatim. Build a one-line address string from the available fields and call Search (Forward Geocode) with format=jsonv2 and limit=1. Send a descriptive User-Agent identifying this workflow (Nominatim rejects generic library defaults). Make exactly one Nominatim call per contact, never in parallel: the public instance is capped at one request per second. If you get HTTP 429 or 403, sleep at least 1500ms and retry once before giving up.

Step 4. Decide the territory from the geocoded country_code and state. Use this default matrix (edit to fit the team):

- West Coast: country=us AND state in California, Oregon, Washington. Slack channel #sales-west.

- East Coast: country=us AND state in New York, Massachusetts, New Jersey, Connecticut, Pennsylvania. Slack channel #sales-east.

- US Central: country=us AND everything else. Slack channel #sales-central.

- Canada: country=ca. Slack channel #sales-canada.

- EMEA: country in gb, ie, fr, de, nl, es, it, se, dk, no, fi, pl, pt, be, at, ch. Slack channel #sales-emea.

- APAC: country in jp, au, nz, sg, hk, in, kr, tw, my, th, id, ph, vn. Slack channel #sales-apac.

- LATAM: country in br, mx, ar, cl, co, pe, uy. Slack channel #sales-latam.

- Anything that doesn't match (or geocode returned no country) is treated as unmatched.

Step 5. Write the territory back to HubSpot. Use Update Contact to set a custom single-line-text contact property (default name: territory). On a match, set it to the territory name (e.g. West Coast). On unmatched or skipped-geocode cases, set it to an empty string so reporting cleanly surfaces 'no territory yet'.

Step 6. Post to Slack (only on a confident match). Use Send a Message to post into the territory's channel. Keep it short and scannable:

πŸ†• New {territory} lead: {first} {last} ({company if present})

πŸ“ {full address}

πŸ—ΊοΈ <https://www.google.com/maps/search/?api=1&query={lat},{lon}|View on Google Maps>

πŸ”— <https://app.hubspot.com/contacts/{portal_id}/contact/{contact_id}|Open in HubSpot>

Build the Google Maps link from the geocoded lat,lon. Format the message in Slack's mrkdwn (single asterisks for bold, <url|text> for links).

Step 7. On unmatched results, do not post to the territory channels. Either skip the post entirely or post a single-line note to a fallback channel like #sales-unrouted naming the country and state we did get, so a human can route it by hand. Make the fallback channel configurable.

Failure modes the agent should handle:

- HubSpot returns 404 (contact already deleted): log and exit cleanly.

- Nominatim returns an empty array or a result with no country: treat as unmatched.

- Slack returns channel_not_found for the territory's channel: fall back to the unrouted channel and mention the expected territory.

- HubSpot Update Contact fails because the territory property doesn't exist: surface a clear setup message ('Create a single-line text contact property named territory in HubSpot, then re-run') and exit.

Configuration knobs the user should be able to edit without touching code:

- The territory matrix (country/state β†’ territory name + Slack channel).

- The HubSpot property name to write back to (default: territory).

- The fallback Slack channel for unrouted leads.

- Whether to include the contact's email and HubSpot owner mention in the Slack post.

Additional information

What does this prompt do?
  • The moment a new contact with a street address lands in HubSpot, look up where they are in the world using free OpenStreetMap data.
  • Use that location to decide which sales territory or region the lead belongs to, based on a matrix you control.
  • Write the matched territory back onto the HubSpot contact so reporting and routing stay in sync.
  • Post a short heads-up in the right territory's Slack channel with the lead's name, address, and a clickable map link.
What do I need to use this?
  • A HubSpot account with permission to read and update contact properties.
  • A single-line text contact property in HubSpot (the workflow will write the territory name here).
  • A Slack workspace with one channel per sales territory, plus a fallback channel for unrouted leads.
  • Your team's territory rules (which countries and states map to which channel).
How can I customize it?
  • Edit the territory rules: which countries, states, or regions map to which Slack channel.
  • Choose what to include in the Slack post (contact name, company, email, owner mention, map link).
  • Decide what happens on a vague or international address that doesn't match any rule (clear the field, post to a fallback channel, or both).
  • Swap to your own Slack channel naming so it matches your existing #sales workspace setup.

Frequently asked questions

Does this work if the contact has no street address?
Yes. The workflow checks for an address first and skips both the lookup and the Slack post if one is missing or too vague, so empty contacts don't spam your channels.
Does the geocoding cost anything?
No. The lookup uses OpenStreetMap's free Nominatim service, which is why the workflow runs one address at a time and waits a second between calls to respect their fair-use policy.
Will this work for international leads?
Yes. The default territory matrix includes North America, EMEA, APAC, and LATAM regions, and you can split or merge them however you like.
What happens if the address is too vague to place on a map?
The workflow clears the territory field so the lead is easy to spot in HubSpot reports as 'no territory yet', and it skips the Slack post so no one gets pinged with a half-routed lead.
Can I run this on contacts that already exist in HubSpot?
Yes. You can either re-trigger the workflow on existing contacts by hand from HubSpot, or ask Geni to add a one-time backfill step that loops through contacts missing a territory.

Stop manually routing inbound leads.

Connect HubSpot and Slack once, and Geni geocodes every new contact, tags the territory, and posts the lead to the right channel automatically.