Maps API
List, create, edit, and delete venue maps and the markers placed on them.
Manage the venue maps shown on the Maps page of your event app: the floorplan images, and the markers placed on them for rooms, booths, entrances and anything else attendees need to find. It is the same data you edit under Maps in the console, so a map created here opens in the console’s map editor and the other way round. All endpoints require the standard authentication headers. Write endpoints require the maps:write scope; the read endpoint requires maps:read.
Every write supports ?dryRun=1 to validate without saving, and the authoritative field list is always available from /apiSchema, including the marker fields under formats.mapMarkers.
Maps are shown in the attendee app only, and only while the Maps page is on your event’s app menu (Menu Settings in the console). A write tells you in warnings when it is not, so you do not build maps nobody can open.
GET /getMaps
Returns an array of the event’s maps, each with its markers, in the order the app lists them (lowest sortNr first). No request body required. Requires maps:read.
Response body (JSON array)
[
{
"documentId": "map123",
"mapId": "map123",
"name": "Ground floor",
"imagePathLogo": "https://.../ground-floor.png",
"navigationLink": "https://maps.google.com/?q=...",
"sortNr": 1,
"iconScale": 900,
"markers": [
{ "markerId": "1759312800000", "label": "Hall A", "x": 0.42, "y": 0.61, "color": 4291176488, "iconId": "marker", "size": 24, "isPinned": true },
{ "markerId": "1759312800001", "label": "Registration", "x": 0.08, "y": 0.47, "color": 4280432963, "iconId": "flag", "size": 16, "isPinned": true }
]
}
]
Example request
curl "https://api.event-vault.com/getMaps" \
-H "x-api-key: <your-api-key>" \
-H "x-client-id: <your-client-id>" \
-H "x-event-id: <your-event-id>" \
-H "x-timestamp: $(date +%s%3N)"
POST /upsertMap
Creates a new map, or edits an existing one, markers included. Omit documentId to create (name required); include it to edit that map (only the fields you send are updated; fields you omit are left unchanged). Edits also return a changes map with the before and after value of every field the write actually changed, so you can confirm what happened. Requires maps:write.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
documentId |
string | The map you are editing. Omit to create, include to edit. /getMaps returns it, so a record you just fetched can be posted straight back. |
|
mapId |
string | Accepted as an alias for documentId on every endpoint. Send one or the other - two different values is a 400. |
|
name |
string | ✓ (create) | The map’s name, e.g. "Ground floor". Shown in the app’s map picker when the event has more than one map. |
imagePathLogo |
string | URL of the floorplan image. Host it with /uploadImage. Replacing it with an image of a different shape moves the markers - see Positioning markers. |
|
navigationLink |
string | Optional link, for instance to Google Maps, offered to attendees as a NAVIGATE button under the map. | |
sortNr |
number | Order among the event’s maps, lowest first. The lowest is the map the app opens on. | |
iconScale |
number | The reference width that marker sizes are measured against - see Marker sizes. | |
markers |
array | The map’s markers as a JSON array of objects - see Markers below. When sent, it replaces the whole list. |
Markers
Each entry in markers is an object:
| Key | Type | Description |
|---|---|---|
markerId |
string | Identifies the marker within its map. Omit it to add a new marker: an id is generated and returned by the write. Send the id a read gave you to keep editing the same marker. |
label |
string | The marker’s name, shown in the map legend and when the marker is tapped. A marker without a label is not drawn in the app. |
x |
number | Horizontal position from 0 (left edge) to 1 (right edge) - see Positioning markers. |
y |
number | Vertical position from 0 (top edge) to 1 (bottom edge). |
color |
color | Colour of the icon, as a hex string like "#C62828" or an ARGB integer. Reads return the integer. |
iconId |
string | Which icon to draw. One of marker, explore, circle, square, restaurant, hotel, shopping, bar, theater, museum, library, spoke, parking, other, bus, train, flag, gathering. Defaults to circle. |
size |
number | Icon size - see Marker sizes. The console offers 8, 16, 24, 32 and 40. Defaults to 16. |
isPinned |
boolean | Whether the marker is placed on the map. An unpinned marker is kept but drawn nowhere and left out of the legend. Defaults to true. |
A new marker needs both x and y, unless you send it with "isPinned": false. On a marker that already exists, the keys you leave out keep their current values, so {"markerId": "1759312800000", "x": 0.45} moves that marker and changes nothing else about it.
Positioning markers
x and y are fractions of a square, not pixels and not geographic coordinates. The app fits your floorplan inside a square, centred and with its proportions kept, so a wide image has an empty band above and below it, and a tall one has a band to its left and right. Positions are measured across that whole square, bands included.
To turn a pixel position on your image into x and y, take the image’s width W and height H, and let S be the larger of the two:
x = (px + (S - W) / 2) / S
y = (py + (S - H) / 2) / S
For a floorplan of 2000 x 1200 pixels, S is 2000. A booth at pixel (500, 300) is at x = 500 / 2000 = 0.25 and y = (300 + 400) / 2000 = 0.35.
Two things follow from this:
- The position is where the icon’s top-left corner sits, not its centre. See Marker sizes for how to centre an icon on a point.
- Replacing the floorplan with an image of a different shape moves every marker, because the image then sits differently inside the square. Send new positions together with the new image. A write that changes the image and leaves the markers alone says so in
warnings.
Marker sizes
A marker’s size is measured in pixels against a canvas that is iconScale pixels wide, so an icon always covers the same share of the map: size / iconScale of its width, on a phone and on a tablet alike. With "iconScale": 1000, a marker of size 30 spans 3% of the map’s width.
That also gives you the offset for centring an icon on a point: subtract (size / iconScale) / 2 from both x and y.
A map created through the API starts with iconScale at 1, which switches the scaling off: an icon is then simply size pixels on every screen. Either way the app keeps icons between 8 and 72 pixels.
When someone saves the map in the console’s map editor, iconScale is set to the width of their editor canvas. Sizes chosen through the API against a different iconScale will then look larger or smaller than before, so if a map is edited in both places, read iconScale back from /getMaps before choosing sizes.
Linking sessions to markers
A session points at a marker by name. When a session’s location is the same text as a pinned marker’s label (capital letters and surrounding spaces do not matter), the location on the session page becomes a link that opens the map with that marker highlighted. Set the location with /upsertSession. Two markers that share a label count as one place: both are highlighted together.
Read-only fields. documentId, apiImported, updated and deleted are bookkeeping fields: reads return them, writes ignore them. That makes read-modify-write round trips safe - fetch a map, change what you need, and post the whole record back.
Responses
| Status | Response body | Description |
|---|---|---|
200 OK |
{ "status": "success", "mapId": "map123", "created": true, "markers": [...] } |
Map created (created: true) or edited (created: false, plus a changes map of before/after values). When the request carried markers, the response returns the full list with the ids of any new ones. May also carry warnings / ignoredFields - see Field Types |
400 Bad Request |
{ "error": "Invalid request body", "details": [...] } |
A field has the wrong type or format, name is missing on create, or a marker is invalid. Marker problems name the entry, e.g. markers[3]: 'x' must be at most 1 |
404 Not Found |
{ "error": "Not found", "details": [...] } |
An id was supplied but no such map exists |
500 Internal Server Error |
{ "error": "Server error", "details": [...] } |
Unexpected server error |
Plus the standard auth errors (400/403/404/408/429) - see Authentication.
Example - create a map with two markers
curl "https://api.event-vault.com/upsertMap" \
-X POST \
-H "Content-Type: application/json" \
-H "x-api-key: <your-api-key>" \
-H "x-client-id: <your-client-id>" \
-H "x-event-id: <your-event-id>" \
-H "x-timestamp: $(date +%s%3N)" \
-d '{
"name": "Ground floor",
"imagePathLogo": "https://.../ground-floor.png",
"sortNr": 1,
"iconScale": 1000,
"markers": [
{ "label": "Hall A", "x": 0.42, "y": 0.61, "iconId": "marker", "color": "#C62828", "size": 30 },
{ "label": "Registration", "x": 0.08, "y": 0.47, "iconId": "flag", "size": 20 }
]
}'
The response returns the new mapId and the two markers with their generated markerId. To add a marker later, post the list back with the new entry appended. The existing entries only need their markerId:
curl "https://api.event-vault.com/upsertMap" \
-X POST \
-H "Content-Type: application/json" \
-H "x-api-key: <your-api-key>" \
-H "x-client-id: <your-client-id>" \
-H "x-event-id: <your-event-id>" \
-H "x-timestamp: $(date +%s%3N)" \
-d '{
"mapId": "map123",
"markers": [
{ "markerId": "1759312800000" },
{ "markerId": "1759312800001" },
{ "label": "Hall B", "x": 0.66, "y": 0.61, "iconId": "marker", "color": "#1565C0", "size": 30 }
]
}'
POST /deleteMap
Deletes a map together with its markers. From the organizer’s point of view the deletion is permanent: the map disappears from the console and the app. Sessions whose location pointed at one of its markers keep their location text, which simply stops being a link. Requires maps:write.
Request body fields
| Field | Type | Required | Description |
|---|---|---|---|
mapId |
string | ✓ | ID of the map to delete (documentId is accepted too) |
| Status | Response body | Description |
|---|---|---|
200 OK |
{ "status": "success" } |
Map was deleted. If it had markers, a warnings entry says how many went with it. With ?dryRun=1 the same warning is returned and nothing is deleted |
400 Bad Request |
{ "error": "Invalid request body", "details": [...] } |
mapId is missing |
404 Not Found |
{ "error": "Not found", "details": [...] } |
No map with this ID exists in the event |
500 Internal Server Error |
{ "error": "Server error", "details": [...] } |
Unexpected server error |
Example request
curl "https://api.event-vault.com/deleteMap" \
-X POST \
-H "Content-Type: application/json" \
-H "x-api-key: <your-api-key>" \
-H "x-client-id: <your-client-id>" \
-H "x-event-id: <your-event-id>" \
-H "x-timestamp: $(date +%s%3N)" \
-d '{"mapId": "map123"}'