Territories
Define named, jurisdiction-pinned partitions of a tenant's records and members, auto-assign records with rules, and transfer books of business.
Territories
A territory is Pact's unit of Salesforce-style sharing: a named partition of a
tenant's records and members. Each territory pins a single legal jurisdiction,
which lets the cross-territory consent evaluator (core.consent_multi_territory) pick the strictest requirement
across every territory a record is linked to. Territory CRUD is under
/v1/territories; auto-assignment rules are under /v1/territory-rules. Both are
gated by the admin module and enforce permission checks.
Live
Backed by core.territories (CRUD, membership, hierarchy, transfers) and
core.territory_rules (auto-assignment). Every helper requires an explicit
tenant_id derived from the auth context — never from a request body.
Jurisdictions
Each territory carries a jurisdiction from a fixed set: GDPR, UK_GDPR,
CCPA, CASL, PIPEDA, LGPD, PIPL, or OTHER (the default). This is not
cosmetic — territory membership feeds core.consent_multi_territory, which
resolves the strictest consent requirement when a record spans territories. An
unknown jurisdiction is rejected with a validation error.
Hierarchy and membership
Territories form a tree via parent_territory_id. Members are assigned with one
of three territory roles: owner, member, or viewer. The engine exposes
descendant resolution (descendants) and a full territory_tree so a manager's
scope can expand to a territory plus everything beneath it. The visibility filter
that turns membership into actual record-level filtering lives in
core.visibility.scope; territories own only the partition definition.
CRUD endpoints
| Method & path | Purpose |
|---|---|
GET /v1/territories | List territories |
POST /v1/territories | Create (name, jurisdiction, optional parent, slug) |
GET /v1/territories/{id} | Fetch one |
PATCH /v1/territories/{id} | Update |
DELETE /v1/territories/{id} | Soft-delete |
GET /v1/territories/{id}/members | List members |
POST /v1/territories/{id}/members | Assign a user |
DELETE /v1/territories/{id}/members/{user_id} | Unassign |
GET /v1/territories/me | Territories the caller belongs to |
Auto-assignment rules
/v1/territory-rules defines rules that link an incoming record to a territory
automatically. You can dry-run a record against the ruleset before committing:
| Method & path | Purpose |
|---|---|
GET /v1/territory-rules | List rules |
POST /v1/territory-rules | Create a rule |
PATCH /v1/territory-rules/{rule_id} | Update |
DELETE /v1/territory-rules/{rule_id} | Soft-delete |
POST /v1/territory-rules/preview | Dry-run a record against the rules |
POST /v1/territory-rules/{record_type}/{record_id}/apply | Link the record now |
Transferring a book of business
When a rep changes territory, core.territories provides preview_transfer to
show what would move and transfer_records to reassign records in bulk, plus
territory_performance for per-territory rollups. Transfers are tenant-scoped and
permission-gated like every other mutation here.