π 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
π°οΈ Geocoding API Specifications
Trigger a spatial intersection query from your mobile applications or server-side microservices instantly.
/geo-data
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"
}
ποΈ Database Architectural Integration
Because the API returns a predictable, immutable slug natural key instead of variable text blocks, updating relationship links within SQL engines like PostgreSQL or MySQL is safe and fast:
-- 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-data', {
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-data?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");
}
}