Total Human DesignDashboard|
Documentation

Validate Location

POST/api/validate-locationPro

Pre-validate a city name before making a chart calculation call. Returns resolved coordinates and timezone on success, or structured city suggestions on failure.

Not metered

This endpoint only resolves the location. It does not run Swiss Ephemeris and does not count against your Chart requests or SAGE responses. Use it to catch bad input before calling a chart endpoint. Location tools are free with any key.

Why use this?

All chart endpoints accept a birthLocation string that gets resolved to coordinates and timezone. If the city name is invalid, you waste a calculation call and get a 400 error.

This endpoint lets you:

  • Pre-validate city input before submitting a chart request
  • Show the resolved city to your user so they can confirm the match
  • Surface suggestions when the input is invalid — up to 5 similar cities returned so the user can correct without guessing

If you're building a full city picker UI, see City Search (GET /api/locations) instead.

Request

Parameters

ParameterTypeRequiredDescription
birthLocationstringNoCity name to validate (e.g. "Manila", "London, UK", "New York, NY"). Required if latitude/longitude not provided.
latitudenumberNoOverride latitude. Bypasses city lookup when provided with longitude.
longitudenumberNoOverride longitude. Bypasses city lookup when provided with latitude.
birthDatestringNoDate (YYYY-MM-DD) for DST-aware offset calculation. Defaults to 2000-01-01.
birthTimestringNoTime (HH:MM) for DST-aware offset calculation. Defaults to 12:00.

Either birthLocation or both latitude + longitude must be provided.

thd-api

Response — valid location

Response200

{
"success": true,
"valid": true,
"resolved": {
  "city": "Manila",
  "timezone": "Asia/Manila",
  "coordinates": { "lat": 14.6042, "lon": 120.9822 },
  "offset": 8,
  "source": "offline-city-lookup"
},
"input": "Manila, Philippines"
}
FieldDescription
validtrue — city resolved successfully
resolved.cityCanonical city name from the database
resolved.timezoneIANA timezone identifier
resolved.coordinates{ lat, lon } — exact coordinates used
resolved.offsetDST-aware UTC offset in fractional hours (e.g. 8, -4, 5.5)
resolved.source"offline-city-lookup" or "offline-coordinates"
inputThe original string you sent

Response — invalid location

When the city cannot be resolved, the endpoint returns 200 with valid: false and up to 5 structured suggestions:

Response200

{
"success": true,
"valid": false,
"error": "City 'Austin TX' not found. Please provide a valid city name or lat/lon coordinates.",
"input": "Austin TX",
"suggestions": [
  {
    "name": "Austin",
    "province": "Texas",
    "country": "United States",
    "timezone": "America/Chicago",
    "coordinates": { "lat": 30.2672, "lng": -97.7431 },
    "population": 961855,
    "value": "Austin, Texas, United States"
  }
]
}
FieldDescription
validfalse — input could not be resolved
errorHuman-readable explanation
suggestionsArray of up to 5 city objects sorted by population. Use value as the corrected birthLocation. Always present on failure — may be empty if no partial match found

How suggestions are generated

The fallback runs three attempts, stopping at the first that returns results:

  1. Exact match on the full input
  2. First space-token"Austin TX" → searches "Austin"
  3. 4-char prefix"Chemberlun" → searches "Chem" (best-effort for typos)

Response — ISO country code

If the input looks like a 2-letter country code, a hint field is added instead of suggestions:

Response200

{
"success": true,
"valid": false,
"error": "City 'BG' not found...",
"input": "BG",
"suggestions": [],
"hint": ""BG" looks like a country code. Try a city name instead: Sofia, Plovdiv, Varna"
}

Response fields at a glance

FieldPresent when
resolvedvalid: true only
errorvalid: false only
suggestionsvalid: false only
hintvalid: false + ISO country code detected

Integration pattern

// Pre-flight check before chart calculation async function resolveCity(userInput) { const res = await fetch('https://api.totalhumandesign.com/api/validate-location', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ birthLocation: userInput }) }); const result = await res.json(); if (!result.valid) { // Show suggestions so user can pick a corrected city if (result.suggestions.length > 0) { showSuggestions(result.suggestions); // each has .value, .timezone, .coordinates } else if (result.hint) { showHint(result.hint); } else { showError(result.error); } return null; } // Confirm with user, then calculate return result.resolved; // { city, timezone, coordinates, offset } }

Common pitfalls

  • ISO country codes like "US", "PH", "BG" will fail — use city names
  • Queries shorter than 3 characters are rejected
  • "Austin TX" format (no comma) returns valid: false but suggestions will include Austin, Texas — use the value from suggestions as the corrected input
  • Towns under 1,000 population are not in the dataset — collect latitude/longitude directly for very remote birthplaces

Notes

  • Location resolution is fully offline — no external geocoding APIs are called
  • birthDate and birthTime only affect the UTC offset calculation (historical DST rules), not which city is matched
  • Pass latitude + longitude instead of birthLocation to bypass city lookup entirely — useful for coordinates from a map picker