Sharing groups API
Groups are created and filled by admins, then datasets and maps are shared with them. The behavior behind these routes is described in Sharing with groups. Request and response schemas are in the API reference.
Replace https://geolens.example.com, $TOKEN and the ids below with your
own values. Send the token as a bearer token or API key, as described in
API authentication.
Admin routes
Section titled “Admin routes”These need the manage_users permission. Names are unique, and a duplicate
answers 409.
| Method and path | Purpose |
|---|---|
GET /admin/groups/ | List groups by name, with member_count. Takes skip and limit. |
POST /admin/groups/ | Create a group from {"name": "Planning"}. Answers 201. |
GET /admin/groups/{group_id} | Read one group. |
PATCH /admin/groups/{group_id} | Rename it with {"name": "..."}. |
DELETE /admin/groups/{group_id} | Delete it and its memberships. Answers 204. |
GET /admin/groups/{group_id}/members/ | List members by username. |
POST /admin/groups/{group_id}/members/ | Add users with {"user_ids": [...]}, up to 500. Users already in the group are skipped. An unknown id answers 404 and adds nobody. |
DELETE /admin/groups/{group_id}/members/{user_id} | Remove one member. Answers 204. |
curl -X POST https://geolens.example.com/api/admin/groups/ \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Planning"}'Deleting a group removes its grants at once. A restricted map shared only with it becomes private. Adding a member answers 422 when a virtual raster dataset shared with the group would then reach someone who can’t read one of its sources.
List the groups you can share with
Section titled “List the groups you can share with”curl "https://geolens.example.com/api/groups/mine/" \ -H "Authorization: Bearer $TOKEN"Returns {"groups": [{"id": "...", "name": "..."}], "total": 1}. The groups
are the ones the caller belongs to, or every group for an admin. skip and
limit (default 50, at most 200) page the list.
Share a dataset
Section titled “Share a dataset”curl -X PUT "https://geolens.example.com/api/datasets/$DATASET_ID/groups/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"group_ids": ["'"$GROUP_ID"'"]}'group_ids is the full list, up to 100, and replaces what the dataset had. An
empty list removes every group. The caller needs the edit_metadata permission
and must own the dataset or be an admin.
- A private dataset with a group becomes
restricted. A restricted dataset left with no group becomesprivate. Internal and public datasets keep their visibility. - An owner who adds a group they don’t belong to gets 403. An unknown group answers 404.
- A change that would strand a layer in one of the owner’s shared maps, or expose a source through a virtual raster dataset, answers 422.
Dataset detail returns groups to the owner and admins only.
Share a map
Section titled “Share a map”curl -X PUT "https://geolens.example.com/api/maps/$MAP_ID/groups/" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"group_ids": ["'"$GROUP_ID"'"]}'The body and the visibility rules match the dataset route, with the map’s own
owner-or-admin check. The response carries visibility, groups,
shared_dataset_ids and hidden_layers. Becoming restricted revokes the
map’s share link and embed tokens.
Confirm sharing layers the groups can’t read
Section titled “Confirm sharing layers the groups can’t read”When a member of a new group can’t read a layer’s dataset, nothing is written and the route answers 409:
{ "detail": { "code": "layers_hidden_from_groups", "message": "...", "layers": [ { "layer_id": "...", "layer_title": "Parcels", "dataset_id": "...", "dataset_title": "Parcels 2026", "group_ids": ["..."], "can_share": true } ] }}Repeat the request with confirm:
"share_datasets"also shares each dataset withcan_share: truewith the groups that lack it. A refusal on any of those shares rolls back the whole request, the map’s groups included."map_only"shares the map alone. The response’shidden_layerslists the layers still out of reach.
Branch on detail.code. A 409 without it means another change holds the map’s
lock, and the request can be retried.
GET /maps/{id}/visibility-check/ also returns hidden_from_groups: on a
restricted map, the layers some of its groups can’t read, among those the
caller can read.
Read restricted maps
Section titled “Read restricted maps”A map can now be restricted. Older generated clients reject a visibility
value they don’t know, so a map response names restricted only to clients
that send this request header:
X-GeoLens-Map-Visibility: restrictedEvery map-returning endpoint answers with Vary: X-GeoLens-Map-Visibility.
Without the header a restricted map reads as private, and the
visibility=private list filter also finds restricted maps. Writing private
to a map that has groups keeps it restricted, so a client that can’t see the
groups doesn’t remove them by accident. Remove them with
PUT /maps/{id}/groups/ and an empty list. PUT /maps/{id} with
visibility: restricted and no group answers 422.
The web app, the CLI, the MCP server and both SDKs send the header. A later
release will name restricted to every client, header or not, so a client that
sends it now sees no change then.
404 instead of 403 on maps
Section titled “404 instead of 403 on maps”Map write and management routes answer 404, not 403, for a map the caller can’t read, so they no longer reveal that it exists. A caller who can read the map but doesn’t own it still gets 403.