Documentation

Quickstart

Base URL: https://api.geolabel.dev  ·  Auth: X-API-Key header on every request  ·  Get a free key →

The one endpoint you need

GET /label?lat={latitude}&lng={longitude}
ParameterTypeRequiredDescription
latfloatLatitude (-90 to 90)
lngfloatLongitude (-180 to 180)
radiusintSearch radius in metres (default 100, max 500)

Response

{
  "place":            "Planet Fitness - Chicago",
  "label":            "Planet Fitness",
  "category":         "gym",
  "distance_meters":  12.1,
  "coordinates":     { "lat": 41.8827, "lng": -87.6233 },
  "is_open":          true,
  "opens_at":         null,
  "closes_at":        "23:00",
  "opening_hours":    "Mo-Fr 05:00-23:00; Sa-Su 07:00-21:00",
  "cached":           false
}
FieldTypeDescription
placestring | nullRaw venue name from OpenStreetMap
labelstringClean, friendly name — use for display
categorystringStable type — use for automation logic
distance_metersfloat | nullDistance from your coordinates to the matched place
coordinatesobjectThe lat/lng you sent, echoed back
is_openbool | nulltrue if currently open, false if closed. null if the place has no hours data in OSM.
opens_atstring | nullNext opening time as HH:MM. Populated when the place is currently closed so you know when it reopens. null when open or unknown.
closes_atstring | nullToday's closing time as HH:MM. Populated when the place is open. null when closed or unknown.
opening_hoursstring | nullRaw OpenStreetMap opening_hours string (e.g. Mo-Fr 09:00-18:00; Sa 10:00-17:00). null if not set in OSM.
cachedbooltrue if served from 10-minute in-memory cache. Note: is_open, opens_at, and closes_at are always recalculated live against the current time, even on cache hits.

Code samples

curl -H "X-API-Key: your_key_here" \
  "https://api.geolabel.dev/label?lat=41.8827&lng=-87.6233"
import httpx

API_KEY = "your_key_here"

def get_location_label(lat: float, lng: float, radius: int = 100) -> dict:
    response = httpx.get(
        "https://api.geolabel.dev/label",
        headers={"X-API-Key": API_KEY},
        params={"lat": lat, "lng": lng, "radius": radius},
    )
    response.raise_for_status()
    return response.json()

result = get_location_label(41.8827, -87.6233)
print(result["category"])  # → "gym"
print(result["label"])     # → "Planet Fitness"
const API_KEY = "your_key_here";

async function getLocationLabel(lat, lng, radius = 100) {
  const url = new URL("https://api.geolabel.dev/label");
  url.searchParams.set("lat", lat);
  url.searchParams.set("lng", lng);
  url.searchParams.set("radius", radius);

  const res = await fetch(url, {
    headers: { "X-API-Key": API_KEY },
  });
  if (!res.ok) throw new Error(`GeoLabel error: ${res.status}`);
  return res.json();
}

const { category, label } = await getLocationLabel(41.8827, -87.6233);
console.log(category); // → "gym"
import fetch from "node-fetch"; // remove on Node 18+

const API_KEY = "your_key_here";

const res = await fetch(
  `https://api.geolabel.dev/label?lat=41.8827&lng=-87.6233`,
  { headers: { "X-API-Key": API_KEY } }
);
const data = await res.json();
console.log(data.label);    // → "Planet Fitness"
console.log(data.category); // → "gym"
struct LabelResponse: Decodable {
    let place: String?
    let label: String
    let category: String?
    let distanceMeters: Double?
    let isOpen: Bool?
    let opensAt: String?
    let closesAt: String?
    let openingHours: String?
    let cached: Bool

    enum CodingKeys: String, CodingKey {
        case place, label, category, cached
        case distanceMeters = "distance_meters"
        case isOpen        = "is_open"
        case opensAt       = "opens_at"
        case closesAt      = "closes_at"
        case openingHours  = "opening_hours"
    }
}

var components = URLComponents(string: "https://api.geolabel.dev/label")!
components.queryItems = [
    URLQueryItem(name: "lat", value: "41.8827"),
    URLQueryItem(name: "lng", value: "-87.6233"),
]
var request = URLRequest(url: components.url!)
request.setValue("your_key_here", forHTTPHeaderField: "X-API-Key")

let (data, _) = try await URLSession.shared.data(for: request)
let result = try JSONDecoder().decode(LabelResponse.self, from: data)
print(result.category ?? "")  // → "gym"
── Step 1 ──────────────────────────────────────
Action:  Get Current Location
Output:  Current Location (lat + lng)

── Step 2 ──────────────────────────────────────
Action:  Get Contents of URL
URL:     https://api.geolabel.dev/label
Method:  GET
Headers: X-API-Key → your_key_here
Params:  lat → Latitude (from step 1)
         lng → Longitude (from step 1)

── Step 3 — category (for logic) ───────────────
Action:  Get Dictionary Value
Key:     category
From:    Contents of URL (step 2)

── Step 4 — label (for display) ────────────────
Action:  Get Dictionary Value
Key:     label
From:    Contents of URL (step 2)

── Step 5 — hours ──────────────────────────────
Action:  Get Dictionary Value
Key:     is_open      ← "true", "false", or empty
From:    Contents of URL (step 2)

Action:  Get Dictionary Value
Key:     closes_at    ← "23:00" when open, empty when closed
From:    Contents of URL (step 2)

Action:  Get Dictionary Value
Key:     opens_at     ← "09:00" when closed, empty when open
From:    Contents of URL (step 2)

── Step 6 ──────────────────────────────────────
Action:  If [category] equals "gym"
         → your actions here
         End If

── Tip: use "Stop and Output" + Dictionary ─────
Build a Dictionary of all values, then
"Stop and Output" → Dictionary.
Calling shortcuts receive a clean object
with label, category, is_open, closes_at, etc.

Rate limit headers

Every response includes these headers so you always know where you stand.

HeaderDescription
X-RateLimit-TierYour plan (free / pro / enterprise)
X-RateLimit-Limit-MinuteRequests allowed per minute
X-RateLimit-Remaining-MinuteRequests left this minute
X-RateLimit-Limit-DayRequests allowed per day
X-RateLimit-Remaining-DayRequests left today
PlanPer MinutePer Day
Free10100
Pro10010,000
Enterprise5001,000,000

Error reference

StatusMeaning
200Success
401Missing or invalid X-API-Key
422Invalid parameters (e.g. lat out of range)
429Rate limit hit — check Retry-After header
502OpenStreetMap temporarily unavailable, retry shortly

Full interactive Swagger UI → api.geolabel.dev/docs