π Project Overview
Global platforms like Google Maps or Yandex treat local administrative data as second-class citizens. When passing coordinates to their legacy APIs, they return unstable, hard-to-parse unstructured text strings such as "Pap District" or "ΠΠ°ΠΏΡΠΊΠΈΠΉ ΡΠ°ΠΉΠΎΠ½" depending on client locales. Processing these strings in your production backend leads to continuous regex parsing errors.
Kettu Geo-Data API solves this entirely. By matching client coordinates against precise spatial database MultiPolygon grids via PostGIS spatial indexes, it directly outputs a clean, immutable Universal Slug (e.g., pap, besharyk, sukh). This serves as a plug-and-play Natural Key for your database tables, completely bypassing expensive API pricing and vendor lock-in.
https://thekettu.com/api/geo-service
π°οΈ Geocoding API Specifications
Trigger a spatial intersection query from your mobile applications or server-side microservices instantly.
/reverse
1. Request Query Parameters
| Parameter Key | Type | Policy | Spatial Context & Sample |
|---|---|---|---|
| lat | Double | REQUIRED | Geographical Latitude coordinate point. Example: 41.182104 |
| long | Double | REQUIRED | Geographical Longitude coordinate point. Example: 70.709864 |
2. Global HTTP Request Headers
| Header Property | Supported Enums | Localization Logic |
|---|---|---|
| Accept-Language | uz | ru | en | Renders localization values using mapped resource bundles. Fallback Default: en |
π¦ JSON Response Payloads
The system enforces a rigid, predictable response block optimized for real-time relational parsing:
{
"message": "Success",
"data": {
"point": {
"latitude": 41.182104,
"longitude": 70.709864
},
"region": {
"id": 3,
"slug": "namangan",
"name": "Namangan viloyati"
},
"district": {
"id": 49,
"slug": "pap",
"name": "Pop"
}
}
}
{
"message": "Failed",
"data": "District not found"
}
π Developer Integration Flow
Understand how to integrate Kettu Geo-Data API into your infrastructure and completely automate data syncing. The entire pipeline consists of 4 direct phases:
Frontend: Capture Geographical Coordinates
When a user places a pin or clicks on the client map interface, the Map SDK (Google Maps, Mapbox, Leaflet) returns the exact geographical coordinate pair:
Request: Forward Coordinates to Kettu API
Your backend server targets Kettu's lightweight /reverse endpoint, appending the coordinate properties as safe query params:
Response: Ingest the Immutable Natural Key (Slug)
Kettu handles the complex PostGIS multi-polygon calculations and maps the point to an immutable natural text string within milliseconds. No fragile string parsing or regex filtering needed:
Database Match: Bind Relational Database Tables
Query your internal region and district tables matching the incoming slug string. Extract your local primary relational IDs, save the transaction entity, and execute your logic seamlessly.
ποΈ Database Architectural Integration
Kettu API does not return internal primary numerical IDs because every individual enterprise database enforces its own isolated sequencing and auto-increment strategies. Instead, the ozo-yengil **`slug`** property acts as our system contract. To integrate smoothly, your application's target tables must contain a dedicated `slug` column configured with a unique index:
-- Enforce a unique index on your slug string columns for instant record matches:
CREATE TABLE enterprise_districts (
id SERIAL PRIMARY KEY,
slug VARCHAR(50) UNIQUE NOT NULL, -- The unique natural key matching Kettu responses π
name_uz VARCHAR(100),
region_id INT
);
CREATE UNIQUE INDEX idx_districts_slug ON enterprise_districts(slug);
Mapping an incoming Kettu slug (e.g., `pap` or `chilanzar`) into your operational relational entity tables is achieved cleanly with a standard sub-query statement:
-- Direct relational foreign key linking without string manipulation or substring trimming
UPDATE app_users_profile
SET localized_district_id = (SELECT id FROM enterprise_districts WHERE slug = :kettu_returned_slug)
WHERE user_session_id = :active_user_id;
π Reference Data API
To seed your local databases or build dropdown menus in your UI, you can dynamically fetch all supported region and district slugs. These endpoints are heavily cached for ultra-fast response times.
/regions
Returns a list of all available region slugs. Use these values to query districts.
{
"message": "Success",
"data": [
"fergana",
"andijan",
"namangan",
"sirdaryo",
"jizzakh",
"samarkand",
"kashkadarya",
"surkhandarya",
"bukhara",
"navoi",
"khorezm",
"karakalpakstan",
"tashkent",
"tashkent-city"
]
}
/districts?region={region_slug}
Returns all district slugs associated with a specific region.
| region |
REQUIRED
Region slug to filter districts (e.g., tashkent-city)
|
{
"message": "Success",
"data": [
"yangi-hayat",
"yangi-tashkent",
"khamza",
"uchtepa",
"shaykhantahur",
"chilanzar",
"mirabad",
"yunusabad",
"mirzo-ulugbek",
"almazar",
"yakkasaray",
"sergeli",
"bektemyr"
]
}
π» Zero-Configuration Client Integration
Clean integration templates for multiple runtime applications.
β‘ Node.js (Axios Client Async)
const axios = require('axios');
async function resolveUserSpatialPoint() {
try {
const response = await axios.get('https://thekettu.com/api/geo-service/reverse', {
params: { lat: 41.182104, long: 70.709864 },
headers: { 'Accept-Language': 'uz' }
});
// Direct output: "pap"
console.log("Resolved Natural Key:", response.data.data.district.slug);
} catch (error) {
console.error("Spatial lookup failed:", error.message);
}
}
β Java (Spring RestTemplate)
import org.springframework.web.client.RestTemplate;
import org.springframework.http.*;
import java.util.Map;
public class SpatialResolver {
public Map<String, Object> getGeoData(double lat, double lon) {
String url = "https://thekettu.com/api/geo-service/reverse?lat={lat}&long={long}";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("Accept-Language", "uz");
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<Map> response = restTemplate.exchange(
url, HttpMethod.GET, entity, Map.class, lat, lon
);
// Returns the inner "data" object containing point, region, and district
return (Map<String, Object>) response.getBody().get("data");
}
}
π Support Kettu Platform
While the vast majority of funds contributed to support this project are directed straight toward maintaining high API (performance) and server (stability), a minor portion goes into keeping my (coffee and refreshments) stash stocked. Because absolute honesty is deeply important to me, I want to be entirely transparent: this directly helps (fuel the late-night coding) sessions required to keep building open-source platforms for the community. Let's grow impactful local developer utilities together! π
Custom Integration?
For large enterprise request setups or inquiries regarding direct PostGIS batch table downloads, feel free to contact me directly.
Discuss via Telegram