Your own places are searched together with the planet index, by your account's keys only. They are stored beside the planet file, never inside it, and no other account can see them.
Write places
Writes take a secret key (gc_sk_…). Publishable keys and OAuth tokens get 403 secret_key_required. Writes count against the key's rate limit, not your geocoding allowance.
curl -X PUT https://api.geolith.app/v1/places/custom/depot-1 \
-H "Authorization: Bearer $GEOLITH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Pune depot","names":{"mr":"पुणे डेपो"},"lat":18.5204,"lon":73.8567,"address":{"street":"FC Road","locality":"Pune","country":"IN"},"category":"depot"}'
| Method and path | Does |
|---|---|
POST /v1/places/custom | Write { "places": [...] }, insert or replace by externalId |
POST /v1/places/custom/bulk | Write NDJSON, one place per line |
PUT /v1/places/custom/{externalId} | Write one place |
GET /v1/places/custom?after=&limit= | List by external id, up to 1,000 a page |
GET /v1/places/custom/{externalId} | Read one |
DELETE /v1/places/custom/{externalId} | Delete one |
DELETE /v1/places/custom | Delete all |
Writing an externalId you deleted earlier brings that place back with the new data.
The OpenAPI 3.1 description is at https:/. You can also upload an NDJSON file and delete places in the dashboard at console.geolith.app.
A place
| Field | Required | Notes |
|---|---|---|
externalId | yes | Your id: 1–128 of A-Z a-z 0-9 . _ ~ -, unique in your account |
name | yes | Up to 200 characters |
names | no | Names by language tag (hi, mr, ta, …); lang= picks one |
lat, lon | yes¹ | WGS 84 degrees; with an outline, the label point (optional, must lie inside) |
geometry | no¹ | GeoJSON Point, Polygon or MultiPolygon (RFC 7946, WGS 84) |
address | no | housenumber, street, postalcode, locality, region, country (ISO alpha-2) |
category | no | Returned as category: [..] |
expiresAt | no | ISO 8601; after it the place is no longer returned, then deleted |
¹ Give lat and lon, or a geometry. createdAt, createdBy, updatedAt, updatedBy, deletedAt and deletedBy are set by the server; a request that sends one gets 400.
Outlines: Polygon and MultiPolygon
A place can be an area: a yard, a campus, a delivery zone. Send a GeoJSON Polygon (an outer ring, then holes) or MultiPolygon (several polygons). Positions are [longitude, latitude].
curl -X PUT https://api.geolith.app/v1/places/custom/hadapsar-yard \
-H "Authorization: Bearer $GEOLITH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Hadapsar yard",
"category": "depot",
"geometry": {
"type": "Polygon",
"coordinates": [
[[73.920, 18.500], [73.930, 18.500], [73.930, 18.510], [73.920, 18.510], [73.920, 18.500]],
[[73.924, 18.504], [73.924, 18.506], [73.926, 18.506], [73.926, 18.504], [73.924, 18.504]]
]
}
}'
curl -X PUT https://api.geolith.app/v1/places/custom/twin-depots \
-H "Authorization: Bearer $GEOLITH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Twin depots",
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[[[73.84, 18.52], [73.85, 18.52], [73.85, 18.53], [73.84, 18.53], [73.84, 18.52]]],
[[[73.88, 18.55], [73.89, 18.55], [73.89, 18.56], [73.88, 18.56], [73.88, 18.55]]]
]
}
}'
Checked on write; a shape that fails gets 400 invalid_place with the reason:
- Every ring is closed (first and last positions equal), with at least 3 distinct positions and some area.
- Rings do not cross or touch each other or themselves; holes lie inside their outer ring; polygons of a MultiPolygon do not overlap.
- Longitudes in -180, 180, latitudes in -90, 90. A shape across the antimeridian is cut there into a MultiPolygon (RFC 7946 §3.1.9); an edge across more than 180° of longitude is refused.
- At most 10,000 positions per place and 100,000 per request.
Rings are rewound to the right-hand rule (outer rings counter-clockwise, holes clockwise). The place's point is its label point: the centroid of its largest polygon, or a point inside when the centroid falls outside (in a hole or a bend), unless you send lat/lon inside the shape.
In answers an outline place is returned the way planet places with outlines are:
/v1/search,/v1/autocomplete,/v1/reverse,/v1/nearby: aPointat the label point, with the outline'sbbox([west, south, east, north];west > eastacross the antimeridian)./: the outline as the geometry (v1/ place? ids= custom:venue:<externalId>& geometry= true Polygonfor one polygon, elseMultiPolygon), the label point inproperties.center, and thebbox./v1/reverse: a point inside the outline (not in a hole) returns the place whatever the radius; distances are to the label point.
addendum. says which kind a place is. GET /v1/places/custom/{externalId} returns the full geometry; the list returns geometryType, bbox and a small preview of each outer ring.
Limits
| Plan | Custom places |
|---|---|
| Free | 100 |
| Starter | 1,000 |
| Growth | 10,000 |
| Scale | 100,000 |
One request writes at most 500 places in at most 5 MiB (413 payload_too_large). A write that would pass your plan's limit is refused whole, with nothing written (413 custom_places_limit).
In answers
/v1/searchand/v1/autocomplete: a place of yours that holds every word of the query (the last word as a prefix in autocomplete) comes before the planet's places.boundary.country,layers(custom places arevenue) andsizeapply./v1/reverseand/v1/nearby: your places within the radius, merged with the planet's by distance./v1/place: ask forcustom:venue:<externalId>together with planet gids; answers keep the asked order.
Features have source: "custom", gid: "custom:venue:<externalId>", and addendum.custom with the names and expiry. A change made with the API shows in answers at once from the same location and everywhere within a minute. Structured search matches the address and locality words, and the MCP tools and A2A operations return your places the same way as the matching REST route.
Privacy
Places are visible only to your account's keys. They stop being returned when you delete them, when they expire, and when you close your account. Deleted places are kept, hidden, so we can restore them if you ask; to have them erased for good, write to contact@geolith.app.