Territories & Geo
Territory rules tell Soryk which company locations an agent is allowed to see and serve. When territoryEnabled is on, the agent app filters companies and locations to those matching at least one of the agent's territory rules. Useful for sales orgs that split coverage geographically.
Five layers of matching
| Layer | Format | Matches |
|---|---|---|
| Country | ISO 3166-1 alpha-2 (e.g. IT) | Locations whose country code matches. |
| Region | Free-text region/state name | Locations whose region/province field matches (case-insensitive, whitespace-trimmed). |
| ZIP prefix | String (e.g. 20) | Locations whose postal code starts with the prefix. |
| Circle | {lat, lng, radiusKm} | Locations within a great-circle distance (Haversine). Requires lat/lng on the location. |
| Polygon | Array of {lat, lng} vertices | Locations inside the polygon (ray-casting). Requires lat/lng on the location. |
Layers combine with OR — a location matches the territory if any rule matches.
Set up a territory
- Make sure
territoryEnabledis on in Settings → Territory. - Open an agent profile (Agents → click row).
- Scroll to the Zone section.
- Use the structured editor for countries, regions, ZIP prefixes.
- Use the JSON editor for circles and polygons (power-user — see formats below).
- Save. The AI audit fires automatically (if
ANTHROPIC_API_KEYis configured).
Circle JSON
[
{ "lat": 45.4642, "lng": 9.1900, "radiusKm": 50 },
{ "lat": 41.9028, "lng": 12.4964, "radiusKm": 30 }
]
Polygon JSON
[
[
{ "lat": 45.40, "lng": 9.10 },
{ "lat": 45.55, "lng": 9.10 },
{ "lat": 45.55, "lng": 9.30 },
{ "lat": 45.40, "lng": 9.30 }
]
]
Each top-level array element is one polygon. Vertices in order (clockwise or counter-clockwise both work — ray-casting is winding-agnostic). The polygon auto-closes back to the first vertex.
AI conflict audit
On save, Soryk asks Claude (Opus 4.7, JSON-schema response) to analyse the full territory grid and report:
- Overlaps — two or more agents covering the same area.
- Gaps — areas with no coverage.
- Spelling drift — region names spelled inconsistently across agents (e.g. "Lombardia" vs "Lombardy").
- Manager hierarchy issues — sub-territories that don't roll up cleanly.
Findings appear as a banner above the editor with one-click "Apply fix" suggestions.
Without ANTHROPIC_API_KEY configured, the audit endpoint returns 500 with a clear message. Territory matching at runtime keeps working — the AI is purely advisory.
Polygons — ray-casting in plain English
To decide whether a point is inside a polygon, draw a horizontal ray from the point to the right and count how many polygon edges it crosses. Odd = inside, even = outside. Works for arbitrary shapes, including concave ones. We use the standard algorithm — fast (O(n) in vertex count) and dependency-free.
Circles — Haversine in plain English
Distance between two lat/lng points across the Earth's curvature. We use the standard Haversine formula with Earth radius 6,371 km. A "match" means the great-circle distance from circle center to location is ≤ radiusKm.
Known caveat — CompanyLocation lat/lng
Shopify CompanyLocation doesn't natively expose latitude/longitude. Country, region and ZIP-prefix rules work end-to-end. Geo shapes (circles + polygons) are wired through the data layer, AI audit, UI editor and matching engine — but they silently skip on real CompanyLocations until a coordinates field is provided. Two ways to unblock:
Option A: Add a per-location geocoding step (Nominatim or Mapbox) that writes lat/lng to a custom metafield on the CompanyLocation. We have an example script — ask support.
Option B: Wait for the planned Soryk geocoder (roadmap, mid-2026) that auto-runs at company create time.
Examples
Example A — Country + region split
Marco covers all of Italy except Lombardia. Sara covers Lombardia + Switzerland.
Marco
countries: ["IT"]
regions excluded: (none — handled by Sara's territory, see overlap audit)
Sara
countries: ["CH"]
regions: ["Lombardia"]
The AI audit will flag this as an overlap on Italian Lombardia locations. To fix: remove "IT" from Marco and add the remaining 19 Italian regions explicitly. Annoying — but explicit beats implicit.
Example B — Metropolitan area circle
Laura works the Milan metro area (50 km radius from Duomo) plus Monza.
circles: [
{ "lat": 45.4642, "lng": 9.1900, "radiusKm": 50 }
]
regions: ["Monza e Brianza"]
Example C — Custom polygon for a wine appellation
An agent covers a specific DOC wine area defined by a custom polygon (4 vertices for simplicity).
polygons: [[
{ "lat": 44.55, "lng": 11.20 },
{ "lat": 44.60, "lng": 11.40 },
{ "lat": 44.45, "lng": 11.50 },
{ "lat": 44.40, "lng": 11.30 }
]]