K nearest neighbor points
Find the nearest geographic points to any query coordinate without setting up a spatial database.
Run — free
Provide a latitude and longitude, a list of candidate coordinates, and the number of matches you need. The capability calculates spherical great-circle distance to every candidate, sorts the results from nearest to farthest, and returns the requested top k with source indexes and optional labels. Its deterministic ordering makes the result suitable for location search, routing preparation, proximity checks, and repeatable data-processing pipelines.
Prepare a clear query and candidate set
Start with one query coordinate in decimal degrees and a candidate list containing between one and ten thousand points. Latitude must fall between -90 and 90, while longitude must fall between -180 and 180. Each candidate uses the same coordinate rules and may include a label, such as a store name, depot code, sensor identifier, or city. Labels are copied into results but never influence ranking. Choose k as a positive integer no larger than the candidate count. This explicit contract prevents ambiguous partial searches and makes malformed records fail early with a useful input error. Keep all coordinates in the WGS84-style decimal-degree convention normally used by web maps and GPS exports. If your source uses degrees, minutes, and seconds or a projected coordinate system, convert it before calling the capability. Candidate order matters only when distances tie: equally distant points retain their original list order, giving repeatable output across calls and runtimes.
Understand the great-circle ranking
The calculation treats Earth as a sphere with a mean radius of 6,371.0088 kilometers. For each candidate, it applies the haversine relationship and an atan2 central-angle calculation, which remains stable for both very short paths and nearly opposite points. The returned distance_km value is rounded to six decimal places, then candidates are sorted in ascending order. This is surface distance along the globe, not a straight line through Earth, a driving route, or distance measured in a local map projection. It naturally handles longitude wraparound near the international date line and works at either pole without special cases. The spherical model is appropriate for global lookup, discovery, rough dispatch, and shortlist generation. If a workflow requires survey-grade ellipsoidal measurements, road travel time, elevation, borders, or obstacles, use this result as a first-stage shortlist and apply a specialized calculation afterward. The source index lets you join every returned neighbor back to its original record without relying on a label being present or unique.
Use the ranked shortlist in a larger workflow
A nearest-neighbor result is often the beginning of a decision rather than its end. A store locator can request the five closest branches, then filter them by opening hours or inventory. A logistics service can shortlist nearby depots before sending those few candidates to a road-routing engine. An environmental dashboard can associate an observation with its closest sensors while preserving the computed distance for quality checks. Because the function has no network calls, randomness, stored state, or current-time dependency, identical input produces identical output. That makes it straightforward to cache results, test integrations with golden fixtures, or reproduce an earlier ranking during an audit. The declared upper bound also keeps execution predictable: the implementation measures every candidate once and sorts the bounded result set. For frequently changing or very large collections, a spatial index or database will be more efficient. For compact lists supplied with each request, this capability avoids index setup and returns a transparent JSON structure that can be passed directly to another task.
What you can do with it
Build a branch shortlist
Return the nearest stores or service centers before applying business filters such as stock, opening hours, or appointment capacity.
Match readings to sensors
Find the closest monitoring stations to an observation and retain distances and source indexes for later validation.
Prepare route candidates
Reduce a modest depot or waypoint list to the nearest few points before requesting more expensive road-network routes.
FAQ
What does a request cost?
Each API request costs $0.002. The same deterministic calculation can also run in the browser.
Which distance formula is used?
It uses a haversine-based great-circle calculation with the mean Earth radius of 6,371.0088 kilometers.
How are equal distances ordered?
Ties preserve the candidates' original input order, using their zero-based source indexes as the deterministic tie-breaker.
Can k be larger than the candidate list?
No. k must be a positive integer and cannot exceed the number of supplied points.
Does it calculate driving distance?
No. It calculates spherical surface distance. Roads, travel time, elevation, borders, and other route constraints are not considered.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/geo/k-nearest-neighbors \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"lat":40.4168,"lon":-3.7038,"points":[{"label":"Toledo","lat":39.8628,"lon":-4.0273},{"label":"Segovia","lat":40.9429,"lon":-4.1088},{"label":"Guadalajara","lat":40.6337,"lon":-3.1674}],"k":2}'const res = await fetch("https://api.kit.forhosting.com/geo/k-nearest-neighbors", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"lat": 40.4168,
"lon": -3.7038,
"points": [
{
"label": "Toledo",
"lat": 39.8628,
"lon": -4.0273
},
{
"label": "Segovia",
"lat": 40.9429,
"lon": -4.1088
},
{
"label": "Guadalajara",
"lat": 40.6337,
"lon": -3.1674
}
],
"k": 2
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/geo/k-nearest-neighbors",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"lat": 40.4168,
"lon": -3.7038,
"points": [
{
"label": "Toledo",
"lat": 39.8628,
"lon": -4.0273
},
{
"label": "Segovia",
"lat": 40.9429,
"lon": -4.1088
},
{
"label": "Guadalajara",
"lat": 40.6337,
"lon": -3.1674
}
],
"k": 2
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/geo/k-nearest-neighbors", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"lat":40.4168,"lon":-3.7038,"points":[{"label":"Toledo","lat":39.8628,"lon":-4.0273},{"label":"Segovia","lat":40.9429,"lon":-4.1088},{"label":"Guadalajara","lat":40.6337,"lon":-3.1674}],"k":2}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"lat":40.4168,"lon":-3.7038,"points":[{"label":"Toledo","lat":39.8628,"lon":-4.0273},{"label":"Segovia","lat":40.9429,"lon":-4.1088},{"label":"Guadalajara","lat":40.6337,"lon":-3.1674}],"k":2}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/geo/k-nearest-neighbors", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"lat": 40.4168,
"lon": -3.7038,
"points": [
{
"label": "Toledo",
"lat": 39.8628,
"lon": -4.0273
},
{
"label": "Segovia",
"lat": 40.9429,
"lon": -4.1088
},
{
"label": "Guadalajara",
"lat": 40.6337,
"lon": -3.1674
}
],
"k": 2
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "geo.k_nearest_neighbors",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_items | 10000 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |