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.
No calculation units consumed
This endpoint only resolves the location — it does not run Swiss Ephemeris or consume a calculation unit from your quota. Use it to catch bad input before calling a chart endpoint.
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
| Parameter | Type | Required | Description |
|---|---|---|---|
birthLocation | string | No | City name to validate (e.g. "Manila", "London, UK", "New York, NY"). Required if latitude/longitude not provided. |
latitude | number | No | Override latitude. Bypasses city lookup when provided with longitude. |
longitude | number | No | Override longitude. Bypasses city lookup when provided with latitude. |
birthDate | string | No | Date (YYYY-MM-DD) for DST-aware offset calculation. Defaults to 2000-01-01. |
birthTime | string | No | Time (HH:MM) for DST-aware offset calculation. Defaults to 12:00. |
Either birthLocation or both latitude + longitude must be provided.
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"
}| Field | Description |
|---|---|
valid | true — city resolved successfully |
resolved.city | Canonical city name from the database |
resolved.timezone | IANA timezone identifier |
resolved.coordinates | { lat, lon } — exact coordinates used |
resolved.offset | DST-aware UTC offset in fractional hours (e.g. 8, -4, 5.5) |
resolved.source | "offline-city-lookup" or "offline-coordinates" |
input | The 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"
}
]
}| Field | Description |
|---|---|
valid | false — input could not be resolved |
error | Human-readable explanation |
suggestions | Array 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:
- Exact match on the full input
- First space-token —
"Austin TX"→ searches"Austin"✓ - 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
| Field | Present when |
|---|---|
resolved | valid: true only |
error | valid: false only |
suggestions | valid: false only |
hint | valid: 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) returnsvalid: falsebut suggestions will include Austin, Texas — use thevaluefrom suggestions as the corrected input- Towns under 1,000 population are not in the dataset — collect
latitude/longitudedirectly for very remote birthplaces
Notes
- Location resolution is fully offline — no external geocoding APIs are called
birthDateandbirthTimeonly affect the UTCoffsetcalculation (historical DST rules), not which city is matched- Pass
latitude+longitudeinstead ofbirthLocationto bypass city lookup entirely — useful for coordinates from a map picker
