# Migrate from the Mapbox Geocoding API to geolith

> To move from the Mapbox Geocoding API v6, replace /search/geocode/v6/forward?q= with https://api.geolith.app/v1/search?text= and /reverse?longitude=&latitude= with /v1/reverse?point.lon=&point.lat=. Both APIs return a GeoJSON FeatureCollection, so map code that reads geometry.coordinates keeps working. geolith results may be stored permanently on every plan, from 100,000 free requests a month.

## Request mapping

| Mapbox Geocoding API | geolith | Note |
| --- | --- | --- |
| `GET /search/geocode/v6/forward?q=…` | `GET /v1/search?text=…` |  |
| `forward?q=…&autocomplete=true` | `GET /v1/autocomplete?text=…` |  |
| `GET /search/geocode/v6/reverse?longitude=…&latitude=…` | `GET /v1/reverse?point.lon=…&point.lat=…` |  |
| `access_token=…` | `api_key=… or Authorization: Bearer …` |  |
| `country=in` | `boundary.country=IN` |  |
| `proximity=lon,lat` | `focus.point.lon=…&focus.point.lat=…` |  |
| `types=address,place` | `layers=address,locality` |  |
| `language=hi` | `lang=hi` | Self-hosted server; hosted API planned. |
| `limit=5` | `size=5` | geolith allows up to 40. |
| `permanent=true` | `Not needed` | Every result may be stored. |

## Response mapping

| Mapbox Geocoding API | geolith | Note |
| --- | --- | --- |
| `features[].properties.full_address` | `features[].properties.label` |  |
| `features[].properties.name` | `features[].properties.name` |  |
| `features[].geometry.coordinates` | `features[].geometry.coordinates` | Same: [lon, lat]. |
| `features[].properties.mapbox_id` | `features[].properties.gid` |  |
| `properties.feature_type` | `properties.layer` |  |
| `properties.context.postcode.name` | `properties.postalcode` |  |
| `properties.context.place.name` | `properties.locality` |  |
| `properties.context.region.name` | `properties.region` |  |
| `properties.context.country.country_code` | `properties.country_code` |  |

## Before and after

Before: Mapbox:

```js
const url = new URL('https://api.mapbox.com/search/geocode/v6/forward');
url.searchParams.set('q', 'shaniwar wa');
url.searchParams.set('autocomplete', 'true');
url.searchParams.set('proximity', '73.8567,18.5204');
url.searchParams.set('access_token', MAPBOX_TOKEN);
const { features } = await (await fetch(url)).json();
return features.map((f) => f.properties.full_address);
```

After: geolith:

```js
const url = new URL('https://api.geolith.app/v1/autocomplete');
url.searchParams.set('text', 'shaniwar wa');
url.searchParams.set('focus.point.lon', '73.8567');
url.searchParams.set('focus.point.lat', '18.5204');
url.searchParams.set('api_key', GEOLITH_PUBLISHABLE_KEY);
const { features } = await (await fetch(url)).json();
return features.map((f) => f.properties.label);
```

## What changes

Mapbox public tokens and geolith publishable keys play the same role: both are safe in the browser when restricted to your origins. Use a secret key on servers.

- Autocomplete is its own endpoint, /v1/autocomplete, not a flag.
- The context object becomes flat properties: postalcode, locality, region, country, country_code.
- Show: © OpenStreetMap contributors (ODbL), Overture Maps Foundation.

## Questions

### Does my MapLibre or Mapbox GL code need to change?

Only the geocoding call. Both APIs return GeoJSON with [lon, lat] coordinates, so a result can go straight into a GeoJSON source.

### Do I need a permanent-storage flag?

No. Every geolith result may be stored permanently. Mapbox charges extra for that.

Get a free API key (100,000 requests a month): https://console.geolith.app/signup
