diff --git a/src/api/urls.py b/src/api/urls.py
index 134284a302458cd31184e8db3835cfe7ccc0827d..52c110c8e372dc43740ec9b4575be67e1ed5c5d0 100644
--- a/src/api/urls.py
+++ b/src/api/urls.py
@@ -3,7 +3,7 @@ from rest_framework.urlpatterns import format_suffix_patterns
 from rest_framework.authtoken import views as authtoken_views
 
 from .views import api_root
-from .views import assemblies, badges, bbb, conferencemember, conferences, events, rooms, schedule, users, workadventure
+from .views import assemblies, badges, bbb, conferencemember, conferences, events, maps, rooms, schedule, users, workadventure
 
 
 app_name = 'api'
@@ -29,6 +29,8 @@ urlpatterns = [
     path('c/<slug:conference>/assembly/<slug:assembly>/rooms', assemblies.ConferenceAssemblyRoomList.as_view(), name='assembly-rooms'),
     path('c/<slug:conference>/assembly/<slug:assembly>/schedule', schedule.AssemblySchedule.as_view(), name='assembly-schedule'),
     path('c/<slug:conference>/assembly/<slug:assembly>/badges/new_redeem_token', badges.create_redeem_token, name='create-badge-redeem'),
+    path('c/<slug:conference>/map/assemblies/poi.json', maps.AssembliesPoiExportView.as_view(),  name='map-assemblies-poi'),
+    path('c/<slug:conference>/map/assemblies/areas.json', maps.AssembliesAreasExportView.as_view(), name='map-assemblies-areas'),
     path('c/<slug:conference>/badges/redeem_token', badges.redeem_badge_token, name='badge-redeem'),
     path('c/<slug:conference>/badges/redeem_map_token', badges.RedeemBadgeMapTokenView.as_view(), name='badge-map-redeem'),
     path('c/<slug:conference>/rooms', rooms.ConferenceRoomList.as_view(), name='room-list'),
diff --git a/src/api/views/maps.py b/src/api/views/maps.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ec3153cffce8a79039ba392097e87ef71edb410
--- /dev/null
+++ b/src/api/views/maps.py
@@ -0,0 +1,81 @@
+import abc
+import json
+
+from django.contrib.gis.gdal import SpatialReference, CoordTransform
+from rest_framework.views import APIView
+
+from core.models.assemblies import Assembly
+from core.models.conference import ConferenceExportCache
+from .mixins import ConferenceSlugMixin
+
+
+class AssembliesExportView(ConferenceSlugMixin, APIView, metaclass=abc.ABCMeta):
+    geometry_field = None
+    _cts = {}  # cache of CoordTransforms (if needed)
+
+    def get_queryset(self):
+        return Assembly.objects.filter(conference=self.conference, state_assembly__in=Assembly.PLACED_STATES)
+
+    @staticmethod
+    def get_field_geojson(value, srid: int, ct_cache: dict = None):
+        if value.srid != srid:
+            if ct_cache is None:
+                ct_cache = {}
+            if value.srid not in ct_cache:
+                srs = SpatialReference(srid)
+                ct_cache[value.srid] = CoordTransform(value.srs, srs)
+            value.transform(ct_cache[value.srid])
+        return json.loads(value.geojson)
+
+    def get_geometry_field(self, obj):
+        return getattr(obj, self.geometry_field)
+
+    def get_geojson(self):
+        srid = 4326  # RFC7946 mandates WGS84
+        ct_cache = {}
+        features = []
+        result = {
+            'type': 'FeatureCollection',
+            # 'crs': {'type': 'name', 'properties': {'name': f'EPSG:{srid}'}},  # deprecated, not in RFC7946
+            'features': features,
+        }
+
+        for assembly in self.get_queryset().prefetch_related('parent').all():
+            geometry = self.get_geometry_field(assembly)
+            if geometry is None:
+                continue
+
+            feature = {
+                'type': 'Feature',
+                'id': assembly.slug,
+                'geometry': self.get_field_geojson(geometry, srid=srid, ct_cache=ct_cache),
+                'properties': {
+                    'name': assembly.name,
+                    'official': assembly.is_official,
+                    'cluster': assembly.is_cluster,
+                    'parent': assembly.parent.slug if assembly.parent else None,
+                },
+            }
+            features.append(feature)
+
+        return result
+
+    def get(self, request, *args, **kwargs):
+        cache_id = 'geojson-' + self.geometry_field
+
+        return ConferenceExportCache.handle_http_request(
+            request=request,
+            conference=self.conference,
+            type=ConferenceExportCache.Type.MAP,
+            ident=cache_id,
+            content_type='application/geo+json',
+            result_func=lambda: json.dumps(self.get_geojson()),
+        )
+
+
+class AssembliesPoiExportView(AssembliesExportView):
+    geometry_field = 'location_point'
+
+
+class AssembliesAreasExportView(AssembliesExportView):
+    geometry_field = 'location_boundaries'