Geographic decision engine

Put your business logic on the map.

Know whether you serve an address, who owns it, and what should happen next. One versioned ruleset answers the same way for your website, your CRM, your call centre and your API.

The problem

One address. Three different answers.

Geographic logic ends up split across a spreadsheet, a CRM automation, your website and the knowledge of whoever has been there longest. Nothing reconciles them, so the disagreement only surfaces as a misrouted lead or a franchise dispute.

HVAC service requested at 123 Main Street, Richmond, VA 23219

  • The territory spreadsheet

    Richmond South

    Last edited 7 months ago by someone who has left.

  • Your CRM assignment rule

    Richmond Central

    A ZIP list pasted into a workflow, never reviewed since.

  • The website form

    Tri-County

    Hard-coded in a page nobody on the ops team can edit.

Three systems, three owners, one customer. Somebody on your team is the tiebreaker, every time.

The answer

Give every address an answer.

One published ruleset, asked the same way by every system you run, returning the same decision with the reasoning attached.

  1. Serviceable

    Do we serve this address?

    Coverage and eligibility are different answers. A territory can cover a point and still be unable to do the job, and saying so is not the same as saying no.

  2. Ownership

    Who owns it?

    One assignee, chosen by explicit precedence rather than whichever row the database returned first. When two claims genuinely tie, you hear about it instead of getting a coin flip.

  3. Action

    What should happen next?

    Route the lead, quote the pricing zone, pick the queue, hand off to the right branch, carried out by whichever system asked.

How it fits

One ruleset. Every system that asks.

MapLogics does not replace your website or your CRM. It becomes the thing they all ask, so the answer stops depending on which one a customer happened to reach.

One ruleset serving every system Your website, your CRM, the call centre, API integrations and AI agents all send an address to a single published MapLogics ruleset, which returns one decision and the trace explaining it. Your website Your CRM Call centre API integrations AI agents MapLogics published ruleset cfg_00042 one answer

Change a territory once. Every one of them is already using the new version, and the old version still explains every decision it made.

How it works

From spreadsheet to published ruleset.

Setup is a sequence, not a project. Most teams get to a first published version the same day.

  1. Add your locations

    Branches, franchisees, dealers or reps, with the services each one can actually perform. Import a spreadsheet if that is where they live today.

  2. Draw your territories

    Draw polygons, group postal areas, or set a radius. Overlaps are surfaced while you work rather than discovered later by a customer.

  3. Write the rules

    Eligibility, ownership, priority, fallback and business hours, built from typed conditions. No code, and nothing that can silently mean two things.

  4. Test before anyone sees it

    Run real addresses through a draft and read the full trace. Save the ones that matter and re-run them before every publish.

  5. Publish a version

    Publishing is atomic. Every system asking gets the new answer at the same moment, and every past decision still names the version that produced it.

Why it decided that

Every answer shows its work.

Anyone can draw a territory on a map. When a franchisee asks why a lead went to the branch across town, you need the reasoning: which territories were in play, which were ruled out and why, which rule won, and which version of your configuration produced it.

The trace

  1. Geocode

    123 Main St, Richmond VA normalised to 37.5407, -77.4360 at high confidence

  2. Candidate query

    Territories trr_017 and trr_021 both cover the point

  3. Exclusions

    No exclusion rule matched

  4. Eligibility

    trr_021 eliminated: its assigned location does not provide the requested HVAC service

  5. Assignment

    trr_017 matched rule_primary_owner at priority 100

  6. Fallback

    Not evaluated: a primary eligible candidate exists

  7. Decision

    Resolved to Richmond Central

reason_code PRIMARY_ELIGIBLE_TERRITORY

What the API returns

{
  "request_id": "res_01J8ZQ...",
  "status": "resolved",
  "ruleset_version": "cfg_00042",
  "location":  { "id": "loc_004", "name": "Richmond Central" },
  "territory": { "id": "trr_017", "name": "Richmond Central" },
  "serviceable": true,
  "outputs": {
    "pricing_zone": "B",
    "lead_queue": "richmond-central"
  },
  "trace": {
    "candidates": 2,
    "matched_rules": [
      "rule_hvac_required",
      "rule_primary_owner"
    ],
    "reason_code": "PRIMARY_ELIGIBLE_TERRITORY"
  }
}

The same trace is available in the app, in a batch export and over the API. The reason code is stable, so your own systems can branch on it instead of parsing prose.

What you get

Built for decisions people will argue about.

Territory changes are contentious. Every capability here exists so a decision can be defended afterwards, not just made.

  • Versioning

    Configuration is published as immutable versions. A decision from March is still explained by the ruleset that was live in March.

  • Overlap detection

    Territories that overlap are flagged while you edit, with the conflicting pair named, rather than resolved silently at request time.

  • Explicit precedence

    Exclusion, then eligibility, then ownership override, then priority. A fixed order, so the same inputs cannot produce a different winner tomorrow.

  • Fallback

    Say what happens when the primary owner cannot take the work. Fallback loops are rejected before they can be published.

  • Ambiguity you can see

    When two candidates genuinely tie and no rule breaks it, you get an ambiguous answer and the candidates. Not a coin flip presented as a decision.

  • Batch resolution

    Run an account list or a lead export through the same engine. Every row comes back with its decision and its reason, exceptions included.

  • Embeddable checker

    A service-area check on your own site that answers from the same published ruleset your CRM uses. No developer needed to install it.

  • Audit trail

    Who changed what, when, and what it did to the decisions. The record a franchise dispute actually turns on.

Who it is for

The question you came here with.

  • Franchise operations

    Which franchise owns this customer, and can I prove it?

    Territory ownership with an audit trail, so a dispute is settled by the record instead of by whoever argues hardest.

  • RevOps and CRM admin

    I need one source of geographic truth my integrations can call.

    Stop maintaining brittle ZIP-list automations in three systems. Keep ownership synchronised from one published ruleset.

  • Marketing and growth ops

    Am I wasting paid leads because a ZIP table is stale?

    Route inbound leads correctly on arrival, and see which addresses you are turning away so you know where demand is going unserved.

  • Operations manager

    Which branch can actually do this job, at this time?

    Serviceability is geography plus capability plus hours, not geography alone. A territory covering a point does not mean the work can be done.

  • Product and engineering

    Give me a stable API and deterministic behaviour.

    One documented endpoint, opaque IDs, stable reason codes and the same decision every time for the same inputs and version. No spatial infrastructure to build.

Jobs to be done

Find your situation.

A lead lands on my website…

It is routed to the correct owner immediately, and the assignment can be explained if anyone asks.

Territories change…

You stage the change, review it and publish it, without silently rewriting what past decisions were based on.

A customer asks whether we serve them…

They get an immediate, accurate answer based on where they are and what they are asking for.

Two territories overlap…

Explicit precedence decides, and genuine ties are surfaced as ambiguous rather than hidden behind a silent winner.

I import a list of accounts…

Every row is assigned in bulk, and the ones that could not be are handed back as an exception file rather than dropped.

Another system needs the answer…

The same decision is available through the API, a webhook, the embeddable widget or a CRM integration.

Somebody disputes a decision…

You show which rules, which geometry and which published version produced it.

We expand…

Model coverage gaps and proposed territories against a draft, without touching what is live.

Fits your stack

It slots in. It does not take over.

MapLogics decides; your systems keep doing what they already do. Nothing here asks you to migrate your CRM or rebuild your website.

  • REST API

    Available

    The contract everything else is built on.

  • Service-area widget

    Available

    A checker on your own site, no developer needed.

  • Webhooks

    Available

    Signed events when configuration is published.

  • HubSpot

    In build

    Route and update owners on contacts and deals.

  • Zapier and Make

    In build

    A resolve action for everything else.

  • Salesforce

    Planned

    For enterprise franchise and dealer networks.

  • ServiceTitan

    Planned

    Serviceability inside the field-service flow.

For developers

One endpoint. One decision. Same answer every time.

No spatial database to run, no geometry to maintain, no PostGIS to learn. Send an address or a coordinate and get back a decision you can branch on.

  • Deterministic: same inputs and same published version, same decision.
  • Opaque IDs and stable reason codes, so your code never parses prose.
  • Every response carries a request ID that matches your logs and ours.
  • Draft and published are separate endpoints, so you cannot test against production by accident.

Requestcurl

curl https://api.maplogics.com/v1/resolve \
  -H "Authorization: Bearer ml_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "address": {
      "line1": "123 Main Street",
      "city": "Richmond",
      "region": "VA",
      "postal_code": "23219",
      "country": "US"
    },
    "context": {
      "service": "hvac",
      "channel": "website"
    },
    "trace": "summary"
  }'

Response200 OK

{
  "status": "resolved",
  "territory": { "id": "trr_017", "name": "Richmond Central" },
  "serviceable": true,
  "trace": { "reason_code": "PRIMARY_ELIGIBLE_TERRITORY" }
}

Bring your territory spreadsheet.

The fastest way to see whether this is worth anything to you is to run your own addresses through it. Send us the spreadsheet you actually use and the locations you actually have, and we will show you what MapLogics decides, including the ones it gets wrong.