{"openapi":"3.1.0","info":{"title":"explorer-api","description":"\n## Explorer API\n\nPublic read-only API for the CivicWall Explorer Platform.\n\n### Architecture\n\nExplorer API is a **read-only aggregation API**.\n- **CivicPerson** (port 8040) provides territory hierarchy (public endpoint, no auth).\n- **ClickHouse GDAM** provides human-readable territory names.\n- **Explorer API** (port 8090) combines both sources for the Explorer frontend.\n\n### No authentication required\n\nAll endpoints are public. No Bearer token needed.\n","version":"0.1.0"},"paths":{"/api/v1/territories/countries":{"get":{"tags":["territories"],"summary":"List active ecosystem countries","description":"List countries from Identity Backend (active + public only).\n\nFor each country, population comes from CivicPerson territory/tree.\nRegion/department/city counts come from CivicPerson (populated zones only).","operationId":"list_countries_api_v1_territories_countries_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/CountryInfo"},"type":"array","title":"Response List Countries Api V1 Territories Countries Get"}}}}}}},"/api/v1/territories/summary":{"get":{"tags":["territories"],"summary":"Country summary stats","description":"Get summary statistics for a country using CivicPerson populated counts.","operationId":"country_summary_api_v1_territories_summary_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountrySummary"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/children":{"get":{"tags":["territories"],"summary":"List children of a territory zone","description":"Get child zones from CivicPerson territory/tree, enriched with GDAM names.\n\n- level=region → list regions\n- level=department&parent=FR_Grand_Est → list departments in Grand Est\n- level=city&parent=FR_Grand_Est_Marne → list cities in Marne","operationId":"list_children_api_v1_territories_children_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"level","in":"query","required":true,"schema":{"type":"string","description":"Territory level: region, department, city","title":"Level"},"description":"Territory level: region, department, city"},{"name":"parent","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Parent zone GDAM code","title":"Parent"},"description":"Parent zone GDAM code"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChildrenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/zone-metrics":{"get":{"tags":["territories"],"summary":"Dynamic metrics for a territorial zone","description":"Get dynamic metrics for any territorial zone from CivicWall_Explorer_DWH.\n\nReturns a variable number of metrics depending on what's stored in ClickHouse.\nThe frontend renders them dynamically — no hardcoded metric types.\nA future JOB will populate metrics from multiple data platforms.","operationId":"zone_metrics_api_v1_territories_zone_metrics_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"zone_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Zone GDAM code (empty = country level)","title":"Zone Code"},"description":"Zone GDAM code (empty = country level)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneMetricsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/geo-layer":{"get":{"tags":["territories"],"summary":"GeoJSON boundaries for a territorial level","description":"Get GeoJSON FeatureCollection with territory boundaries from GDAM ClickHouse.\n\n- level=region → all regions of the country\n- level=department&parent_code=FR_Bretagne → departments in Bretagne\n- level=city&parent_code=FR_Bretagne_Finistere → cities in Finistere\n- level=city&zone_code=FR_Bretagne_Finistere_Kernoues → single city boundary","operationId":"get_geo_layer_api_v1_territories_geo_layer_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"level","in":"query","required":true,"schema":{"type":"string","description":"Territory level: region, department, city","title":"Level"},"description":"Territory level: region, department, city"},{"name":"parent_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Parent zone GDAM code","title":"Parent Code"},"description":"Parent zone GDAM code"},{"name":"zone_code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Specific zone code (single boundary)","title":"Zone Code"},"description":"Specific zone code (single boundary)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Geo Layer Api V1 Territories Geo Layer Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/search":{"get":{"tags":["territories"],"summary":"Search territories by name","description":"Full-text search across GDAM territory names (region + department + city).\n\nReturns results with pre-built breadcrumb paths for instant navigation.","operationId":"search_territories_api_v1_territories_search_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":2,"description":"Search term (min 2 chars)","title":"Q"},"description":"Search term (min 2 chars)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20,"minimum":1,"description":"Max results","default":8,"title":"Limit"},"description":"Max results"},{"name":"level","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by level: region, department, city","title":"Level"},"description":"Filter by level: region, department, city"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/resolve-path":{"get":{"tags":["territories"],"summary":"Resolve territory path to human names","description":"Resolve a territorial path into human-readable names using GDAM.\n\nEach segment is a CivicPerson territory code (GDAM format).\nReturns: segment codes + names + current zone info + children count.","operationId":"resolve_path_api_v1_territories_resolve_path_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"path","in":"query","required":false,"schema":{"type":"string","description":"Slash-separated path segments (e.g. FR_Grand_Est/FR_Grand_Est_Marne)","default":"","title":"Path"},"description":"Slash-separated path segments (e.g. FR_Grand_Est/FR_Grand_Est_Marne)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvedPathResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/population":{"get":{"tags":["territories"],"summary":"Population directory listing","description":"Netflix-style population listing for a territorial zone.\n\nUses CivicPerson /entities with zone_prefix for territorial filtering.\nOnly returns persons where is_published=True.","operationId":"list_population_api_v1_territories_population_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"item_selector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Zone GDAM code (empty = country level)","title":"Item Selector"},"description":"Zone GDAM code (empty = country level)"},{"name":"entity_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"HUMAN, MORAL, GROUP","title":"Entity Type"},"description":"HUMAN, MORAL, GROUP"},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Cursor for pagination (person_code)","title":"Cursor"},"description":"Cursor for pagination (person_code)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Items per page","default":24,"title":"Limit"},"description":"Items per page"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PopulationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/population/counts":{"get":{"tags":["territories"],"summary":"Population counts by type","description":"Get population counts for each person type (HUMAN/MORAL/GROUP).\n\nMakes 3 parallel calls to CivicPerson /entities with limit=1 to get totals.","operationId":"population_counts_api_v1_territories_population_counts_get","parameters":[{"name":"country_code","in":"query","required":true,"schema":{"type":"string","description":"ISO-2 country code","title":"Country Code"},"description":"ISO-2 country code"},{"name":"item_selector","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Zone GDAM code","title":"Item Selector"},"description":"Zone GDAM code"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PopulationCounts"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/territories/person/{person_code}":{"get":{"tags":["territories"],"summary":"Person detail for mini-site","description":"Get full person detail from CivicPerson for the Person Space mini-site.\n\nPublic endpoint — no auth required.","operationId":"get_person_detail_api_v1_territories_person__person_code__get","parameters":[{"name":"person_code","in":"path","required":true,"schema":{"type":"string","title":"Person Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonDetail"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/version":{"get":{"tags":["meta"],"summary":"Get Version","operationId":"get_version_version_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"tags":["meta"],"summary":"API home","operationId":"home__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/health":{"get":{"tags":["meta"],"summary":"Health Check","operationId":"health_check_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ChildrenResponse":{"properties":{"country_code":{"type":"string","title":"Country Code"},"level":{"type":"string","title":"Level"},"parent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent"},"nodes":{"items":{"$ref":"#/components/schemas/HierarchyNode"},"type":"array","title":"Nodes"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["country_code","level","nodes","total"],"title":"ChildrenResponse","description":"Response for the children endpoint."},"CountryInfo":{"properties":{"country_code":{"type":"string","title":"Country Code"},"country_name":{"type":"string","title":"Country Name"},"flag_emoji":{"type":"string","title":"Flag Emoji","default":""},"region_count":{"type":"integer","title":"Region Count","default":0},"department_count":{"type":"integer","title":"Department Count","default":0},"city_count":{"type":"integer","title":"City Count","default":0},"population":{"type":"integer","title":"Population","default":0}},"type":"object","required":["country_code","country_name"],"title":"CountryInfo","description":"A country entry for the countries list."},"CountrySummary":{"properties":{"country_code":{"type":"string","title":"Country Code"},"country_name":{"type":"string","title":"Country Name"},"population":{"type":"integer","title":"Population","default":0},"region_count":{"type":"integer","title":"Region Count","default":0},"department_count":{"type":"integer","title":"Department Count","default":0},"city_count":{"type":"integer","title":"City Count","default":0}},"type":"object","required":["country_code","country_name"],"title":"CountrySummary","description":"Summary stats for a single country."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HierarchyNode":{"properties":{"node_id":{"type":"string","title":"Node Id"},"node_name":{"type":"string","title":"Node Name"},"level":{"type":"string","title":"Level"},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id"},"item_selector":{"type":"string","title":"Item Selector","default":""},"total_entities":{"type":"integer","title":"Total Entities","default":0},"has_children":{"type":"boolean","title":"Has Children","default":false}},"type":"object","required":["node_id","node_name","level"],"title":"HierarchyNode","description":"A node in the territorial hierarchy tree."},"PathSegment":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"level":{"type":"string","title":"Level"},"is_clickable":{"type":"boolean","title":"Is Clickable","default":true}},"type":"object","required":["code","name","level"],"title":"PathSegment","description":"A single segment in a resolved territorial path."},"PersonCard":{"properties":{"person_code":{"type":"string","title":"Person Code"},"person_type":{"type":"string","title":"Person Type"},"display_name":{"type":"string","title":"Display Name"},"city_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City Code"},"city_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City Name"},"verification_level":{"type":"integer","title":"Verification Level","default":0},"is_verified":{"type":"boolean","title":"Is Verified","default":false}},"type":"object","required":["person_code","person_type","display_name"],"title":"PersonCard","description":"A person card for the Netflix-style population directory."},"PersonDetail":{"properties":{"person_code":{"type":"string","title":"Person Code"},"person_type":{"type":"string","title":"Person Type"},"country_code":{"type":"string","title":"Country Code","default":""},"display_name":{"type":"string","title":"Display Name","default":""},"human_first_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Human First Name"},"human_last_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Human Last Name"},"human_public_bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Human Public Bio"},"human_gender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Human Gender"},"human_birth_year":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Human Birth Year"},"human_nationality_codes":{"items":{"type":"string"},"type":"array","title":"Human Nationality Codes","default":[]},"moral_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Name"},"moral_legal_form":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Legal Form"},"moral_industry":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Industry"},"moral_subcategory":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Subcategory"},"moral_employees_range":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Employees Range"},"moral_website":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Website"},"moral_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Description"},"moral_registration_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Moral Registration Date"},"group_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Name"},"group_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Type"},"group_purpose":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Purpose"},"group_members_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Group Members Count"},"group_is_official":{"type":"boolean","title":"Group Is Official","default":false},"group_founded_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Group Founded Date"},"hierarchical_city_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hierarchical City Code"},"city_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"City Name"},"public_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Email"},"public_phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Public Phone"},"public_address":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Public Address"},"social_links":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Social Links"},"verification_level":{"type":"integer","title":"Verification Level","default":0},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"is_published":{"type":"boolean","title":"Is Published","default":false},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"}},"type":"object","required":["person_code","person_type"],"title":"PersonDetail","description":"Full person detail for the Person Space mini-site."},"PopulationCounts":{"properties":{"zone_code":{"type":"string","title":"Zone Code"},"total":{"type":"integer","title":"Total","default":0},"human_count":{"type":"integer","title":"Human Count","default":0},"moral_count":{"type":"integer","title":"Moral Count","default":0},"group_count":{"type":"integer","title":"Group Count","default":0}},"type":"object","required":["zone_code"],"title":"PopulationCounts","description":"Population counts by person type for a territorial zone."},"PopulationResponse":{"properties":{"zone_code":{"type":"string","title":"Zone Code"},"entity_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Entity Type"},"persons":{"items":{"$ref":"#/components/schemas/PersonCard"},"type":"array","title":"Persons"},"total":{"type":"integer","title":"Total"},"cursor":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"},"has_more":{"type":"boolean","title":"Has More","default":false}},"type":"object","required":["zone_code","persons","total"],"title":"PopulationResponse","description":"Paginated population listing for a territorial zone."},"ResolvedPathResponse":{"properties":{"country_code":{"type":"string","title":"Country Code"},"country_name":{"type":"string","title":"Country Name"},"segments":{"items":{"$ref":"#/components/schemas/PathSegment"},"type":"array","title":"Segments"},"current_zone_name":{"type":"string","title":"Current Zone Name"},"current_zone_level":{"type":"string","title":"Current Zone Level"},"children_count":{"type":"integer","title":"Children Count"}},"type":"object","required":["country_code","country_name","segments","current_zone_name","current_zone_level","children_count"],"title":"ResolvedPathResponse","description":"Response for resolve-path endpoint."},"SearchResponse":{"properties":{"country_code":{"type":"string","title":"Country Code"},"query":{"type":"string","title":"Query"},"results":{"items":{"$ref":"#/components/schemas/SearchResult"},"type":"array","title":"Results"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["country_code","query","results","total"],"title":"SearchResponse","description":"Response for the territory search endpoint."},"SearchResult":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"level":{"type":"string","title":"Level"},"path":{"items":{"$ref":"#/components/schemas/SearchResultPath"},"type":"array","title":"Path","default":[]},"url_path":{"type":"string","title":"Url Path"}},"type":"object","required":["code","name","level","url_path"],"title":"SearchResult","description":"A single territory search result."},"SearchResultPath":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"level":{"type":"string","title":"Level"}},"type":"object","required":["code","name","level"],"title":"SearchResultPath","description":"A single ancestor in a search result breadcrumb."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ZoneMetric":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"value":{"type":"integer","title":"Value"},"icon":{"type":"string","title":"Icon"},"color":{"type":"string","title":"Color"}},"type":"object","required":["key","label","value","icon","color"],"title":"ZoneMetric","description":"A single dynamic metric for a zone."},"ZoneMetricsResponse":{"properties":{"zone_code":{"type":"string","title":"Zone Code"},"metrics":{"items":{"$ref":"#/components/schemas/ZoneMetric"},"type":"array","title":"Metrics"}},"type":"object","required":["zone_code","metrics"],"title":"ZoneMetricsResponse","description":"Dynamic metrics for a territorial zone."}}},"tags":[{"name":"meta","description":"Health check, home page, and API metadata."},{"name":"territories","description":"Territory navigation: countries, hierarchy, and path resolution."}]}