API Documentation
ChibiGeo is a geocoding and reverse geocoding API based on OpenStreetMap data, built on top of Photon. It converts addresses into geographic coordinates (latitude and longitude) and vice versa, and is Photon-compatible — most Photon clients work by simply pointing them at ChibiGeo.
Looking for maps? See the vector tile API documentation. Tiles have their own allowance and use a separate endpoint.
- Base URL:
https://app.chibigeo.com/v1/photon - Format: every endpoint returns GeoJSON (
FeatureCollection).
Features
- Geocoding — convert an address or place name into geographic coordinates.
- Reverse geocoding — convert geographic coordinates into a human-readable place.
Authentication
Every geocoding request must include your API key. You can pass it in either of two headers:
X-Api-Key: YOUR_API_KEY
Authorization: Bearer YOUR_API_KEY
If both are present, X-Api-Key takes precedence. The /status endpoint is public and needs no key.
Rate limits and parallel requests
Geocoding has a per-second limit as well as a daily or monthly request allowance:
| Plan | Sustained geocoding requests/second | Full burst capacity | Geocoding allowance |
|---|---|---|---|
| Hobby | 1 | 3 requests | 2,500 requests per day |
| Builder | 10 | 20 requests | 500,000 requests per month |
| Scale | 25 | 50 requests | 2,500,000 requests per month |
| Self-Hoster | 5 | 10 requests | 500,000 requests per month |
Self-Hoster is for requests from Dawarich, reitti and GeoPulse only. Use Builder or Scale for general-purpose commercial API access. See plans and pricing.
Rates and burst capacities apply per API key. Forward and reverse geocoding share the same token bucket, as do all clients using that key. A new bucket starts full. Each request consumes one token; tokens replenish continuously at the sustained rate, up to the plan's burst capacity. There is no separate configured limit on concurrent geocoding requests.
Unused capacity accumulates up to that ceiling. A full Hobby bucket accepts three requests together, including two parallel search requests, then restores one token per second. A full Builder bucket accepts twenty requests together, then restores one token every 100 ms. Burst capacity is the total number of saved requests, not an extra allowance added to the sustained rate.
For example, a search that sends two requests in parallel is accepted when the key has at least two tokens available. Keep sustained traffic within the refill rate so repeated bursts do not exhaust the bucket. At 3,000 requests every day, monthly usage is at most 93,000 requests, within Builder's 500,000-request allowance.
Retrying rate-limited requests
An empty token bucket returns HTTP 429, the body below, and a Retry-After
response header containing the number of seconds until the next token,
rounded up. This header is readable by browser clients through CORS:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 1
{"error":"rate_limited"}
Wait for the delay in Retry-After before retrying. Debounce interactive search
and cancel outdated queries to avoid sending requests for text the user has
already changed. Exhausting the daily or monthly allowance returns
limit_exceeded; retrying after a second does not reset that quota.
These rates apply to geocoding. Map tiles have separate limits and allowances.
Geocoding
Convert a human-readable address or place name into geographic coordinates.
GET https://app.chibigeo.com/v1/photon/api
| Parameter | Required | Description |
|---|---|---|
q | yes | The search query (address or place name). |
limit | no | Maximum number of results. |
lang | no | Language for the results (e.g. en, de). |
lat, lon | no | Bias results toward this location. |
zoom, location_bias_scale | no | Tune how strongly the location bias is applied. |
bbox | no | Restrict results to a bounding box (minLon,minLat,maxLon,maxLat). |
countrycode | no | Restrict results to ISO 3166-1 alpha-2 country codes (e.g. DE). Repeat the parameter for multiple countries. |
layer | no | Restrict to feature layers (e.g. house, street, city). Repeat the parameter for multiple layers. |
osm_tag | no | Filter by OSM tag (e.g. tourism:attraction). Supports repeated filters. |
dedupe | no | Deduplicate results. |
Example Request
curl 'https://app.chibigeo.com/v1/photon/api?q=Brandenburger+Tor,+Berlin&limit=1' \
--header 'X-Api-Key: YOUR_API_KEY'
Example Response
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"osm_type": "W",
"osm_id": 518071791,
"osm_key": "tourism",
"osm_value": "attraction",
"type": "house",
"housenumber": "1",
"name": "Brandenburger Tor",
"street": "Pariser Platz",
"locality": "Friedrich-Wilhelm-Stadt",
"district": "Mitte",
"city": "Berlin",
"country": "Deutschland",
"postcode": "10117",
"countrycode": "DE",
"extent": [13.3775798, 52.5164328, 13.3778251, 52.516117]
},
"geometry": {
"type": "Point",
"coordinates": [13.3777034, 52.5162699]
}
}
]
}
Reverse Geocoding
Convert geographic coordinates into a human-readable place.
GET https://app.chibigeo.com/v1/photon/reverse
| Parameter | Required | Description |
|---|---|---|
lat | yes | Latitude. |
lon | yes | Longitude. |
limit | no | Maximum number of results. |
lang | no | Language for the results (e.g. en, de). |
radius | no | Search radius. |
layer | no | Restrict to feature layers (e.g. house, street, city). Repeat the parameter for multiple layers. |
osm_tag | no | Filter by OSM tag. Supports repeated filters. |
dedupe | no | Deduplicate results. |
Example Request
curl 'https://app.chibigeo.com/v1/photon/reverse?lat=52.5162&lon=13.3778' \
--header 'X-Api-Key: YOUR_API_KEY'
Example Response
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"osm_type": "W",
"osm_id": 518071791,
"osm_key": "tourism",
"osm_value": "attraction",
"name": "Brandenburger Tor",
"housenumber": "1",
"street": "Pariser Platz",
"district": "Mitte",
"city": "Berlin",
"postcode": "10117",
"country": "Deutschland",
"countrycode": "DE"
},
"geometry": {
"type": "Point",
"coordinates": [13.3777034, 52.5162699]
}
}
]
}
Repeated Photon filters
Send multiple filters by repeating the parameter name. ChibiGeo preserves every
allowed value and its order when forwarding the request to Photon. Use plain
repeated names such as osm_tag; square-bracket names such as osm_tag[] are
not supported.
Forward search with two OSM tag filters:
curl 'https://app.chibigeo.com/v1/photon/api?q=rainier&osm_tag=natural&osm_tag=boundary:national_park' \
--header 'X-Api-Key: YOUR_API_KEY'
Reverse geocoding with city, town and municipality filters:
curl 'https://app.chibigeo.com/v1/photon/reverse?lat=35.1983&lon=-111.6513&osm_tag=place:city&osm_tag=place:town&osm_tag=place:municipality' \
--header 'X-Api-Key: YOUR_API_KEY'
The key:value form includes a tag, a bare key includes that tag key, and
!key:value excludes a tag. Tag filters follow
Photon's filtering rules
and work on the principal OSM tags present in the geocoding index. A supported
filter can still return no results when the index has no matching places.
You can also repeat layer on either endpoint and countrycode on forward
search, for example layer=city&layer=locality or
countrycode=US&countrycode=CA. A request with multiple filters counts as one
request toward both the rate limit and the usage allowance.
Status
A public health check — no API key required.
curl 'https://app.chibigeo.com/v1/photon/status'
{ "import_date": "2025-11-02T00:01:55Z", "status": "Ok" }
Errors
Errors are returned as JSON with an error field and the matching HTTP status code.
| Status | error | Meaning |
|---|---|---|
401 | missing_api_key | No API key was provided in the request headers. |
401 | invalid_api_key | The API key was not recognized. |
429 | rate_limited | The key's geocoding token bucket is empty. Wait for the delay in Retry-After before retrying. |
429 | limit_exceeded | You've hit your plan's request cap. The free plan resets daily at 00:00 UTC; paid plans reset on the subscription's monthly billing anniversary. |
503 | service_unavailable | The geocoding backend is temporarily unavailable. |
504 | gateway_timeout | The geocoding backend took too long to respond. |