Protocol Spec

OGP Specification

Formal data model, JSON schemas, and validation rules.

Derived from the reference implementation. For conceptual explanations, see the docs.

Data Model

Country

Root entity. Primary key is the ISO 3166-1 alpha-3 code.

field type constraint description
alpha_3 string(3) PK ISO 3166-1 alpha-3 — e.g. bra, usa, deu
alpha_2 string(2) ISO 3166-1 alpha-2 — e.g. br, us, de
numeric string(3) ISO 3166-1 numeric — e.g. 076
flag string(2) Emoji flag string — e.g. 🇧🇷
short_name string Common name — e.g. Brazil
official_name string? Official name — e.g. Federative Republic of Brazil
id_for_osm string unique OpenStreetMap relation ID
i18n object Internationalized names keyed by BCP 47 locale
tags object Free-form metadata tags
centroid Point? SRID 4326 Geographic centroid
geom MultiPolygon? SRID 4326 Country boundary polygon

SubdivisionContext

Defines a geographic hierarchy scheme for a country. Multiple contexts per country are allowed; exactly one must be the default.

field type constraint description
id string(64) PK Context ID — format: {COUNTRY}-{scheme} e.g. BRA-administrative
country FK Country The country this context belongs to
name string(64) Human-readable name
description string(128) Short description of the hierarchy scheme
is_default boolean unique per country True for exactly one context per country
i18n object Internationalized names

SubdivisionType

Defines a level in the geographic hierarchy. The local_level field is the ordinal position — higher = more granular.

field type constraint description
id string(8) PK Slug — format: {country}-{type} e.g. bra-state, bra-neighborhood
country FK Country generated Derived from first 3 chars of id
context FK SubdivisionContext The context this type belongs to
slug string(64) Singular slug — e.g. estado, municipio, bairro
slug_plural string(64) Plural slug — e.g. estados, municipios, bairros
name string(64) Singular name — e.g. Estado, Município, Bairro
name_plural string(64) Plural name
local_level integer Ordinal position in hierarchy. 1 = country root. Higher = more granular.
id_for_iso integer? ISO 3166-2 numeric type code
osm_admin_level integer? Corresponding OSM admin_level tag value
types_for_gmaps object Mapping from Google Maps address_component types to this SubdivisionType
i18n object Internationalized names

Subdivision

A single geographic subdivision — a neighborhood, municipality, state, or country. Geometry is stored separately in SubdivisionShape.

field type constraint description
id bigint PK Internal auto-increment identifier
country FK Country generated Derived from type.country
type FK SubdivisionType The type/level of this subdivision
source FK SubdivisionSource Data source — e.g. IBGE, OSM, Brasil Aberto
id_for_source string(32)? Source-specific identifier
id_for_iso string(6)? ISO 3166-2 code — e.g. BR-SP
id_for_osm bigint? OpenStreetMap relation ID
id_for_gmaps string(94)? Google Maps place_id
name string(96) Full name — e.g. São Paulo
short_name string(32)? Short name — e.g. SP
slug string(96) URL slug — e.g. sao-paulo
short_slug string(32)? Short slug — e.g. sp
parents M2M Subdivision through SubdivisionHierarchy Parent subdivisions in the active context
children M2M Subdivision through SubdivisionHierarchy Child subdivisions in the active context
i18n object Internationalized names
tags object Free-form tags
updated_at datetime auto Last modified timestamp
Computed properties
path Denormalized SubdivisionPath — e.g. bra/sp/sao-paulo/tatuape
short_path Short path without country prefix — e.g. sp/sao-paulo/tatuape
recursive_title Full human title — e.g. Tatuapé, bairro em São Paulo, SP, Brasil
ancestry_title Context title — e.g. bairro em São Paulo, SP
is_root True if this subdivision is the root of its context (no real parent)

SubdivisionHierarchy

Many-to-many through table that stores parent-child relationships between subdivisions, scoped by context. A subdivision can have multiple parents (e.g., a neighborhood straddling a district boundary). Root nodes are identified by parent_id == child_id.

field type constraint description
id bigint PK Auto-increment
country FK Country generated Derived from context.country
context FK SubdivisionContext The hierarchy context this relationship belongs to
parent FK Subdivision Parent subdivision
child FK Subdivision Child subdivision
is_root boolean generated True when parent_id == child_id (self-reference = root node)

Unique constraint: (parent, child, context)

SubdivisionShape

Geographic geometry for a subdivision. Stored separately to keep the Subdivision table lean. Used for point-in-polygon reverse geocoding via PostGIS ST_Contains().

field type constraint description
subdivision OneToOne Subdivision PK/FK The subdivision this shape belongs to
centroid Point SRID 4326 Geographic centroid of the shape
geom MultiPolygon SRID 4326 Full boundary polygon(s)
source FK SubdivisionSource Data source — e.g. IBGE Malhas, OSM Geofabrik

SubdivisionPath

Denormalized path cache. Stores the canonical path string for a (subdivision, context) pair. This is the fast lookup key for all path-based API queries — path generation via hierarchy traversal is expensive, so it's computed once and cached here.

field type constraint description
id bigint PK Auto-increment
country FK Country generated Derived from context.country
context FK SubdivisionContext The context this path belongs to
subdivision OneToOne Subdivision? unique, db_constraint=False The subdivision this path identifies
path string(256) unique Full path — e.g. bra/sp/sao-paulo/tatuape
short_path string(256)? unique Path without country prefix — e.g. sp/sao-paulo/tatuape
updated_at datetime auto Last update timestamp

Unique constraint: (subdivision, context)

API Schemas

GeoPath Response

Returned by all reverse geocoding endpoints and the main /{geopath} registry lookup.

Example — internal result (found in registry)
{
  "path": "bra/sp/sao-paulo/tatuape",
  "hint": "internal",
  "slug": "tatuape",
  "name": "Tatuapé",
  "recursive_title": "Tatuapé, bairro em São Paulo, SP, Brasil",
  "ancestry_title": "bairro em São Paulo, SP",
  "subdivision": {
    "id": 42819,
    "local_feed": null
  },
  "servers": [
    {
      "url": "https://findera.app/geo/bra/sp/sao-paulo/tatuape",
      "type": "feed",
      "operator": "findera.com.br"
    }
  ],
  "geoshape": {
    "type": "MultiPolygon",
    "coordinates": [...]
  }
}
Example — external result (from Google Maps, not yet in registry)
{
  "path": "bra/sp/sao-paulo/vila-prudente",
  "hint": "external",
  "slug": "vila-prudente",
  "name": "Vila Prudente",
  "recursive_title": "Vila Prudente, bairro em São Paulo, SP, Brasil",
  "ancestry_title": "bairro em São Paulo, SP",
  "subdivision": null
}
field type constraint description
path string always Canonical SubdivisionPath
hint "internal" | "external" always Where the result originated. internal = found in registry DB.
slug string always Last segment slug — e.g. tatuape
name string always Human-readable name of the subdivision
recursive_title string? optional Full hierarchical title — e.g. Tatuapé, bairro em São Paulo, SP, Brasil
ancestry_title string? optional Ancestry description — e.g. bairro em São Paulo, SP
subdivision object? internal only Present only when hint=internal. Contains subdivision id.
servers array? registry lookup only List of registered content servers for this geopath.
geoshape GeoJSON? registry lookup only Boundary geometry as GeoJSON MultiPolygon.

Children Response

Returned by GET api.geofeed.ai/{geopath}/children. Lists direct children within the active context.

{
  "path": "bra/sp/sao-paulo",
  "context": "BRA-administrative",
  "count": 96,
  "children": [
    {
      "path": "bra/sp/sao-paulo/tatuape",
      "slug": "tatuape",
      "name": "Tatuapé",
      "type": "bra-neighborhood",
      "local_level": 6
    },
    ...
  ]
}

Autocomplete Response

Returned by GET api.geofeed.ai/autocomplete. Suggestions carry signed tokens — passing a token back resolves the selection without re-querying Google Maps.

{
  "session": "a1b2c3d4e5f6",
  "query": "tatuapé",
  "count": 3,
  "suggestions": [
    {
      "token": "eyJ...",
      "text": "Tatuapé",
      "secondary": "São Paulo, SP, Brasil",
      "matches": [{ "offset": 0, "length": 7 }]
    }
  ]
}

Tokens are TimestampSigned base64-encoded Google Maps place IDs. They expire after GEO_AUTOCOMPLETE_MAX_AGE seconds. Pass an expired token to get a fresh autocomplete flow.

Errors

All errors return a JSON body with an error_type field.

HTTP 404 not_found

No subdivision found for the given path, point, or address.

HTTP 400 invalid_path

Path string does not match the required format or country code is unknown.

HTTP 400 invalid_point

Point string cannot be parsed as lat,lng coordinates.

HTTP 400 invalid_context

The provided context does not match the country inferred from the path.

HTTP 400 unknown_context

No default context exists for the country and none was provided.

HTTP 400 invalid_country

Country code (alpha-2 or alpha-3) not found in pycountry.

HTTP 501 not_implemented

Endpoint exists but is not yet implemented (e.g. /search).

Validation

Path Validation

Rules applied to every SubdivisionPath string before any lookup.

Regex
^[a-z]{2,3}(?:/[a-z0-9-_]+)*$
Lowercase only

All path segments must be lowercase.

Alpha-3 required

First segment must be 2–3 letters. Alpha-2 codes are normalized to alpha-3 before storage.

Valid country

First segment must resolve to a known ISO 3166-1 country (pycountry lookup).

Slug characters

Segments after the country may contain lowercase letters, digits, hyphens, and underscores.

No trailing slash

Paths must not end with a slash.

No empty segments

Double slashes (bra//sp) are invalid.

Valid
bra
bra/sp
bra/sp/sao-paulo
bra/sp/sao-paulo/tatuape
br/sp/sao-paulo → normalized to bra/sp/sao-paulo
Invalid
BRA/SP → uppercase
bra/São Paulo → non-ASCII
bra/sp/ → trailing slash
bra//sp → empty segment
xx/sp → unknown country code

Context Rules

Rules for the context parameter.

Format

Context IDs follow the pattern {COUNTRY}-{scheme}, e.g. BRA-administrative. The country segment is uppercase alpha-3.

Default

If omitted, the default context for the country inferred from the path is used. Each country has exactly one default context.

Country match

The country inferred from the path's first segment must match the country in the context ID. Mismatch → invalid_context error.

Deducibility

If no default context exists for the inferred country, the context parameter becomes required. Omitting it → unknown_context error.