{
    "schemes": [
        "https",
        "http"
    ],
    "swagger": "2.0",
    "info": {
        "description": "Vietnam-focused geocoding, reverse geocoding, autocomplete, and POI search.\nAuthenticate every /v1 request with the X-API-Key header.",
        "title": "gogoduk Geocoding API",
        "termsOfService": "https://gogoduk.com/terms",
        "contact": {
            "name": "gogoduk support",
            "url": "https://gogoduk.com",
            "email": "support@gogoduk.com"
        },
        "license": {
            "name": "Proprietary"
        },
        "version": "1.0"
    },
    "host": "api.gogoduk.com",
    "basePath": "/",
    "paths": {
        "/health": {
            "get": {
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "system"
                ],
                "summary": "Health check",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "503": {
                        "description": "Service Unavailable",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/admin-boundaries": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns province/district polygons in GeoJSON or WKT.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "boundaries"
                ],
                "summary": "Admin boundary polygons",
                "parameters": [
                    {
                        "type": "string",
                        "default": "geojson",
                        "description": "Output format: geojson or wkt",
                        "name": "format",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "default": "4,8",
                        "description": "Comma-separated admin levels",
                        "name": "levels",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "default": "VN",
                        "description": "ISO-3166-1 alpha-2",
                        "name": "country_code",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Douglas-Peucker tolerance in degrees",
                        "name": "tolerance",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/batch/geocode": {
            "post": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Resolves up to 100 free-form addresses in one request. Results are\nreturned in the same order as the input array. Each item resolves\nindependently — an address that fails to match does not fail the\nbatch; it returns null in `result` with an `error` field.",
                "consumes": [
                    "application/json"
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Batch forward geocode",
                "parameters": [
                    {
                        "description": "addresses (≤100)",
                        "name": "body",
                        "in": "body",
                        "required": true,
                        "schema": {
                            "$ref": "#/definitions/internal_handler.batchGeocodeRequest"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/categories": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns the curated taxonomy of values accepted by\n/v1/pois?category=. Each row carries display labels in English\nand Vietnamese plus a Lucide icon hint for UIs.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "pois"
                ],
                "summary": "List supported POI categories",
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/geocode": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Resolves a free-form address string to a single best coordinate.\nBacked by the same fallback chain as /v1/suggest (ES → PG → Google),\nbut returns one normalized result with a confidence score rather\nthan a list of predictions.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Forward geocode an address",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Free-form address",
                        "name": "address",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "string",
                        "default": "VN",
                        "description": "ISO-3166-1 alpha-2 country bias",
                        "name": "country",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "default": "vi",
                        "description": "Language code",
                        "name": "lang",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Bias point latitude",
                        "name": "focus.lat",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Bias point longitude",
                        "name": "focus.lon",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/place/resolve": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Resolve a placeId into full place details",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Place identifier",
                        "name": "id",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "string",
                        "default": "vi",
                        "description": "Language code",
                        "name": "lang",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Autocomplete session token (close billing session)",
                        "name": "sessionToken",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/geocode-service_internal_model.PlaceResolveResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "503": {
                        "description": "Service Unavailable",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/pois": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns a GeoJSON FeatureCollection of POIs ordered by distance to `near` (or bbox centre).",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "pois"
                ],
                "summary": "Search POIs in a bounding box",
                "parameters": [
                    {
                        "type": "string",
                        "description": "minLng,minLat,maxLng,maxLat",
                        "name": "bbox",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "string",
                        "description": "lng,lat — distance ranking centre",
                        "name": "near",
                        "in": "query"
                    },
                    {
                        "type": "integer",
                        "default": 500,
                        "description": "Max results (1-2000)",
                        "name": "limit",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Comma-separated Google Places types (any-of)",
                        "name": "category",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Filter by rating ≥ value",
                        "name": "min_rating",
                        "in": "query"
                    },
                    {
                        "type": "boolean",
                        "description": "Only POIs marked open now",
                        "name": "open_now",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/pois/{placeId}": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Requires a valid X-POI-Token (issued in MVT tile responses).",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "pois"
                ],
                "summary": "Get a POI by placeId",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Place identifier",
                        "name": "placeId",
                        "in": "path",
                        "required": true
                    },
                    {
                        "type": "string",
                        "description": "Per-feature HMAC token",
                        "name": "X-POI-Token",
                        "in": "header",
                        "required": true
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "404": {
                        "description": "Not Found",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/reverse": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns the nearest known address(es) to point.lat/point.lon.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Reverse geocode a coordinate",
                "parameters": [
                    {
                        "type": "number",
                        "description": "Latitude (WGS84)",
                        "name": "point.lat",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "number",
                        "description": "Longitude (WGS84)",
                        "name": "point.lon",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "integer",
                        "default": 1,
                        "description": "Max results (1-5)",
                        "name": "size",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "default": 0.05,
                        "description": "Search radius in km, max 0.1",
                        "name": "boundary.circle.radius",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "default": "vi",
                        "description": "Language code",
                        "name": "lang",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Comma-separated ISO-3166-1 alpha-2 codes",
                        "name": "boundary.country",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/geocode-service_internal_model.ReverseResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "503": {
                        "description": "Service Unavailable",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/reverse-geocode": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns the province/district that contains the given lat/lng (PostGIS ST_Contains).",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Admin-boundary reverse geocode",
                "parameters": [
                    {
                        "type": "number",
                        "description": "Latitude",
                        "name": "lat",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "number",
                        "description": "Longitude",
                        "name": "lng",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "string",
                        "default": "4,8",
                        "description": "Comma-separated admin levels",
                        "name": "levels",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/suggest": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns predictions for a partial address. Input must be ≥ 2 characters.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "geocoding"
                ],
                "summary": "Autocomplete address suggestions",
                "parameters": [
                    {
                        "type": "string",
                        "description": "User input (min 2 chars)",
                        "name": "input",
                        "in": "query",
                        "required": true
                    },
                    {
                        "type": "string",
                        "default": "vi",
                        "description": "Language code",
                        "name": "lang",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "ISO-3166-1 country filter (alpha-2 or alpha-3)",
                        "name": "country",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "Autocomplete session token",
                        "name": "sessionToken",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Bias point latitude",
                        "name": "focus.lat",
                        "in": "query"
                    },
                    {
                        "type": "number",
                        "description": "Bias point longitude",
                        "name": "focus.lon",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "$ref": "#/definitions/geocode-service_internal_model.SuggestResponse"
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        },
        "/v1/usage": {
            "get": {
                "security": [
                    {
                        "ApiKeyAuth": []
                    }
                ],
                "description": "Returns request counts attributed to the authenticated key's\nowning user, plus today's quota state. Quota is summed across\nALL of this user's API keys (regardless of org). Use it to\npre-empt 429s in your client. Defaults to the last 30 days;\npass `from` and `to` (YYYY-MM-DD) to override.",
                "produces": [
                    "application/json"
                ],
                "tags": [
                    "usage"
                ],
                "summary": "Get this user's API usage and quota",
                "parameters": [
                    {
                        "type": "string",
                        "description": "Start date (YYYY-MM-DD)",
                        "name": "from",
                        "in": "query"
                    },
                    {
                        "type": "string",
                        "description": "End date (YYYY-MM-DD, inclusive)",
                        "name": "to",
                        "in": "query"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "400": {
                        "description": "Bad Request",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    },
                    "503": {
                        "description": "Service Unavailable",
                        "schema": {
                            "type": "object",
                            "additionalProperties": true
                        }
                    }
                }
            }
        }
    },
    "definitions": {
        "geocode-service_internal_model.PlaceResolveResponse": {
            "type": "object",
            "properties": {
                "result": {
                    "$ref": "#/definitions/geocode-service_internal_model.ResolveResult"
                }
            }
        },
        "geocode-service_internal_model.Prediction": {
            "type": "object",
            "properties": {
                "mainText": {
                    "type": "string"
                },
                "placeId": {
                    "type": "string"
                },
                "secondaryText": {
                    "type": "string"
                },
                "text": {
                    "type": "string"
                },
                "types": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            }
        },
        "geocode-service_internal_model.ResolveResult": {
            "type": "object",
            "properties": {
                "address": {
                    "type": "string"
                },
                "city": {
                    "type": "string"
                },
                "country": {
                    "type": "string"
                },
                "district": {
                    "type": "string"
                },
                "lat": {
                    "type": "number"
                },
                "lon": {
                    "type": "number"
                },
                "name": {
                    "type": "string"
                },
                "placeId": {
                    "type": "string"
                },
                "types": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                }
            }
        },
        "geocode-service_internal_model.ReverseResponse": {
            "type": "object",
            "properties": {
                "results": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/geocode-service_internal_model.ReverseResult"
                    }
                }
            }
        },
        "geocode-service_internal_model.ReverseResult": {
            "type": "object",
            "properties": {
                "address": {
                    "type": "string"
                },
                "city": {
                    "type": "string"
                },
                "confidence": {
                    "type": "number"
                },
                "country": {
                    "type": "string"
                },
                "distance_km": {
                    "type": "number"
                },
                "district": {
                    "type": "string"
                },
                "lat": {
                    "type": "number"
                },
                "lon": {
                    "type": "number"
                },
                "place_id": {
                    "type": "string"
                }
            }
        },
        "geocode-service_internal_model.SuggestResponse": {
            "type": "object",
            "properties": {
                "predictions": {
                    "type": "array",
                    "items": {
                        "$ref": "#/definitions/geocode-service_internal_model.Prediction"
                    }
                }
            }
        },
        "internal_handler.batchGeocodeRequest": {
            "type": "object",
            "properties": {
                "addresses": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    }
                },
                "country": {
                    "type": "string"
                },
                "lang": {
                    "type": "string"
                }
            }
        }
    },
    "securityDefinitions": {
        "ApiKeyAuth": {
            "type": "apiKey",
            "name": "X-API-Key",
            "in": "header"
        }
    }
}