VC Publisher API

Übersicht

Zusätzlich zur Benutzeroberfläche bietet der VC Publisher eine REST API.

Die interaktive API-Dokumentation (Swagger UI) ist unter folgender URL verfügbar:

https://Publisher-url.de/apidoc/v1/#

Die Publisher-url.de muss durch die tatsächliche URL Ihrer VC Publisher-Instanz ersetzt werden. Alle Endpunkte können direkt im Browser durchsucht und getestet werden. Bei der Verwendung der Swagger UI klicken Sie auf die Schaltfläche „Try it out" und füllen Sie die erforderlichen Informationen für den jeweiligen Endpunkt aus.

Authentifizierung

Jeder API-Endpunkt außer den Login-Endpunkten erfordert ein gültiges Bearer-Token. Das Token wird durch den Login-Vorgang erhalten und muss im Authorization-Header jeder nachfolgenden Anfrage enthalten sein:

Authorization: Bearer <your-token>

Ohne ein gültiges Token antwortet die API mit 401 Unauthorized.

Workflow 1: Login & Authentifizierung

Je nach Anwendungsfall gibt es zwei Anmeldemethoden: API-Token-Login für den programmatischen Zugriff und sitzungsbasierter Login für den UI-Zugriff.

API-Token-Login

Schritt 1 – Token abrufen

Senden Sie eine POST-Anfrage an /api/v1/login mit Benutzername und Passwort:

POST /api/v1/login
Content-Type: application/json

{
  "username": "ihr-benutzername",
  "password": "ihr-passwort"
}

Bei der Verwendung des Login-Endpunkts in der Swagger UI muss "algorithm": "sha-256" entfernt werden, wenn das Passwort im Klartext eingegeben wird. Eine erfolgreiche Antwort gibt 200 OK zurück:

{
  "_id": "64abc...",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "tokenExpires": "2026-03-12T10:00:00.000Z"
}

Das Feld token ist das Bearer-Token. Das Feld tokenExpires gibt an, wann es ungültig wird.

Schritt 2 – Token verwenden

Fügen Sie das Token in den Authorization-Header jeder Anfrage ein:

GET /api/v1/user/whoami
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6...

Klicken Sie in der Swagger UI auf die Schaltfläche „Authorize" und geben Sie das Token ein, um alle über die Oberfläche gestellten Anfragen zu authentifizieren.


Abmelden

Um die aktuelle Sitzung oder das Token zu invalidieren:

GET /api/v1/logout
Authorization: Bearer <token>

Workflow 2: Projekt erstellen

Erfordert die Super-User-Rolle.

Schritt 1 – Projekt erstellen

Zum Erstellen eines Projekts wird der Endpunkt POST /api/v1/project verwendet. Es müssen ein Name, eine Beschreibung und eine Bounding Box angegeben werden.

POST /api/v1/project
Authorization: Bearer <token>
{
  "name": "Mein Beispielprojekt",
  "description": "Ein Projekt zur Demonstration der API",
  "bbox": [-180, -85, 180, 85]
}

Der optionale Query-Parameter managerId weist einen bestimmten Benutzer als Projektmanager zu. Wird er weggelassen, wird der anfragende Benutzer zum Manager.

Eine erfolgreiche Antwort gibt 201 Created zurück:

{
  "_id": "969b26df-ab3...",
  "createdAt": "2026-03-11T11:38:45.156Z",
  "createdBy": "64abc...",
  "updatedAt": "2026-03-11T11:38:45.156Z",
  "updatedBy": "64abc...",
  "name": "Mein Beispielprojekt",
  "description": "Ein Projekt zur Demonstration der API",
  "bbox": [
    -180,
    -85,
    180,
    85
  ],
  "properties": {
  },
  "defaultDataBucketId": "816d4486-f5a..."
}

Schritt 2 – Vorhandene Projekte abrufen

Um ein bestimmtes Projekt anhand seiner ID abzurufen, verwenden Sie den Endpunkt GET /api/v1/project/{projectId}.

GET /api/v1/project/\{projectId}

Die Rückgabe sieht genauso aus wie die Antwort in Schritt 1.

Um alle Projekte aufzulisten, auf die der authentifizierte Benutzer Zugriff hat, verwenden Sie den Endpunkt GET /api/v1/projects. Die Anfrage erlaubt verschiedene Query-Parameter zum Filtern und Sortieren der Ergebnisse. Die Parameter limit und page steuern die Paginierung, die Parameter sort und orderBy die Sortierung. Diese Parameter steuern die Form der Ausgabe und sind Teil der meisten Listenendpunkte. Die Projektliste unterstützt außerdem spezifische Parameter zum Filtern nach name, description, createdAt, createdBy, updatedAt, updatedBy und bbox.

GET /api/v1/projects

Workflow 3: Benutzer einem Projekt zuweisen

Erfordert die MANAGER-Berechtigung für das Projekt.

Benutzer müssen einem Projekt explizit zugewiesen werden, bevor sie mit ihm interagieren können. Jede Zuweisung verbindet einen Benutzer mit einer Rolle.

Schritt 1 – Benutzer-ID ermitteln

GET /api/v1/users

Der Users-Endpunkt gibt alle Benutzer im System zurück, wenn der Benutzer Administratorrechte hat. Für Benutzer, die nur Projektmanager sind, gibt es den User-Profiles-Endpunkt. Dieser Endpunkt gibt alle Benutzer im System mit eingeschränkten Informationen zurück (ID und Name).

GET /api/v1/user-profiles

Beide Endpunkte bieten eine Filteroption für den username. Der Users-Endpunkt bietet zusätzlich Filter für email, createdAt, createdBy, updatedAt und updatedBy. Die Rückgabe für Users sieht folgendermaßen aus:

{
  "items": [
    {
      "_id": "v6WEM...",
      "createdAt": "2016-02-10T15:46:35.816Z",
      "updatedAt": "2025-08-21T07:35:09.841Z",
      "updatedBy": "v6WEM...",
      "username": "benutzername",
      "email": "benutzer@email.de"
    },
    ...
    ]
}

Die Rückgabe für User-Profiles sieht folgendermaßen aus:

{
  "items": [
    {
      "_id": "v6WEM...",
      "username": "benutzername"
    },
    ...
    ]
}

Beide liefern eine ID, die in Schritt 3 für die Zuweisung eines Benutzers zu einem Projekt benötigt wird.

Schritt 2 – Verfügbare Rollen abrufen

Um einen Benutzer einem Projekt zuzuweisen, muss eine Rolle für den Benutzer angegeben werden. Die verfügbaren Rollen können mit folgendem Endpunkt abgerufen werden:

GET /api/v1/iam/roles

Die Rollen können mit den Standard-Tabellenfiltern und einem Berechtigungsfilter gefiltert werden. Dieser Filter beschreibt die Fähigkeit der Rolle (z. B. getProject). Die Rolle, die dem Benutzer in einem Projekt zugewiesen werden soll, sollte projektbezogen sein. Der Benutzer in einem Projekt sollte mindestens getProject-Berechtigungen haben. Auf dieser Grundlage werden nur zwei mögliche Rollen zurückgegeben: ProjectMember und ProjectManager. Die Rolle ProjectManager umfasst alle projektbezogenen Berechtigungen, während die Rolle ProjectMember hauptsächlich Leseberechtigungen enthält.

{
  "items": [
    {
      "_id": "84e1b02c-2b...",
      "createdAt": "2023-09-06T08:04:23.379Z",
      "updatedAt": "2026-01-15T08:08:43.385Z",
      "createdBy": "internal",
      "updatedBy": "internal",
      "name": "projectManager",
      "permissions": [
        "getProject",
        "getDatasource",
        "publishDatasource",
        "getUser",
        "getACL",
        "getCredentials",
        "createApp",
        "createModule",
        "editProject",
        "createDatasource",
        "deleteDatasource",
        "editDatasource",
        "createDatabase",
        "getDatabase",
        "deleteDatabase",
        "accessDbImport",
        "accessDbExport",
        "accessDbDelete",
        "accessObjectJob",
        "accessApplyUpdateJob",
        "accessObliqueJob",
        "accessPanoramaJob",
        "accessPointcloudJob",
        "accessSolarJob",
        "accessTerrainJob",
        "accessTMSJob",
        "accessCityDbInfo",
        "grantRole",
        "revokeRole",
        "getJob",
        "abortJob",
        "createDataBucket",
        "getDataBucket",
        "editDataBucket",
        "uploadToDataBucket",
        "deleteDataBucket",
        "getApp",
        "editApp",
        "deleteApp",
        "publishApp",
        "setAppPublic",
        "getModule",
        "editModule",
        "deleteModule"
      ]
    },
    {
      "_id": "be48df30-40...",
      "createdAt": "2023-09-06T08:04:23.381Z",
      "updatedAt": "2023-09-06T08:04:23.381Z",
      "createdBy": "internal",
      "updatedBy": "internal",
      "name": "projectMember",
      "permissions": [
        "getProject",
        "getDatasource",
        "publishDatasource",
        "getUser",
        "getACL",
        "getCredentials",
        "createScenario",
        "createApp",
        "createModule"
      ]
    }
  ],
  "limit": 20,
  "page": 0,
  "totalCount": 2,
  "totalPages": 1
}

Schritt 3 – Benutzer zuweisen

Wenn die erforderlichen Voraussetzungen erfüllt sind (userId, projectId und roleId), kann der Benutzer mit folgendem Endpunkt dem Projekt zugewiesen werden.

PUT /api/v1/project/\{projectId}/user/{userId}
Content-Type: application/json

{
  "roleId": "<role-id-aus-schritt-2>"
}

Eine erfolgreiche Antwort ist 204 No Content.

Schritt 4 – Zuweisung überprüfen

GET /api/v1/project/\{projectId}/users

Dieser Endpunkt gibt eine Liste aller dem Projekt zugewiesenen Benutzer zurück, einschließlich ihrer Rollen.

Benutzer aus einem Projekt entfernen

DELETE /api/v1/project/\{projectId}/user/\{userId}

Dieser Endpunkt ermöglicht es, einen Benutzer aus einem Projekt zu entfernen. Hängen Sie ?purge=true an, um in derselben Operation auch alle Gastapp-Berechtigungen zu entfernen.

Workflow 4: Verarbeitungsauftrag ausführen

Eine Aufgabe (Task) definiert, was verarbeitet werden soll und wann. Ein Job ist die eigentliche Ausführungsinstanz, die beim Ausführen der Aufgabe erstellt wird.

Schritt 1 – Aufgabe erstellen

POST /api/v1/project/\{projectId}/task

{
  "labels": [],
  "tags": {},
  "debugLevel": 2,
  "priority": 1,
  "name": "Test_api_task",
  "description": "task with api settings",
  "parameters": {
  "datasource": {
    "command": "create",
    "name": "Vector_Test"
  },
  "options": {
    "input": {
      "dataSource": {
        "@type": "GeoJSONSource",
        "fileSet": [
          {
            "dir": "C:\\path\\to\\input\\data",
            "fileName": [
              {
                "name": "*.json"
              }
            ]
          }
        ],
        "extrudeInfo": {
          "extrudePoints": false,
          "extrudeLines": false,
          "extrudePolygons": false,
          "heightPropertyName": "",
          "defaultExtrudedHeight": 0
        },
        "defaultColor": {
          "@type": "ColorSymbol",
          "value": "#cccccc"
        }
      },
      "heightMode": {
        "type": "absolute",
        "offset": 0
      }
    },
    "modelOptions": {
      "defaultShininess": 0.2,
      "defaultCreaseAngle": 10,
      "renderPrimitiveOutlines": {
        "value": false,
        "color": "#000000",
        "outlineMode": "Surfaces",
        "polygonArray": true
      }
    },
    "tiling": {
      "geometricErrorComputationStrategy": {
        "@type": "GeometricErrorComputationRelativeToTileSizeStrategy",
        "geometricErrorToTileSizeRatio": 0.0115866254
      },
      "value": {
        "@type": "SingleLevelTiling",
        "spatialSubdivisionSchema": {
          "@type": "QuadtreeSubdivision"
        },
        "fixedGeneralization": {
          "@type": "FixedGeneralization",
          "tolerance": 0,
          "texelSize": 0
        },
        "fixedObjectSizeFilter": {
          "@type": "FixedObjectSizeFilter",
          "thresholdValue": 0
        },
        "tileLevel": 15
      },
      "featureSelectionMode": "containsCenter"
    },
    "processing": {
      "convertMaterialsToTextures": false
    },
    "output": {
      "tiles3D_1_1": {
        "layerJson": {
          "maxLevelsInTileset": 3,
          "prettyPrint": true
        },
        "gltfOptions": {
          "exportMetadata": true,
          "addSubfeaturesIndicator": true,
          "backFaceCulling": true,
          "transparencyMode": "combined",
          "alphaFilterThreshold": 0.8,
          "metallicFactor": 0,
          "minFilter": "linear",
          "magFilter": "linear",
          "prettyPrint": true,
          "reverseFeatureIdLabels": true,
          "srgbValuesInPbrBaseColorFactor": false,
          "usePrimitiveOutlineExtension": true,
          "useMaterialsUnlitExtension": false,
          "useUnsignedShortIndexAccessors": false,
          "imageEncoding": "jpeg_png",
          "jpegOptions": {
            "jpegCompressionQuality": 0.8,
            "jpegChromaSubsampling": "4_2_2"
          },
          "pngOptions": {
            "pngCompressionQuality": 0.5
          }
        }
      }
    }
  }
},
  "properties": {},
  "jobType": "vcTilesVector",
  "jobVersion": "",
  "schedule": {
    "type": "immediate"
  }
}

Das Feld jobType bestimmt den Typ der Verarbeitung. Das Objekt parameters ist jobtyp-spezifisch.

Das Feld schedule steuert, wann der Job ausgeführt wird:

Schedule-Wert Verhalten

{ "type": "immediate" }

Der Job wird ausgeführt, sobald ein Verarbeitungs-Runner verfügbar ist

{ "type": "scheduled", "scheduled": "2026-03-12T08:00:00Z" }

Der Job wird zu einem bestimmten UTC-Datum und einer bestimmten Uhrzeit ausgeführt

{ "type": "cron", "cron": "0 3 * * *" }

Der Job wiederholt sich nach einem CRON-Zeitplan

Eine erfolgreiche Antwort gibt 200 OK mit dem erstellten Task-Objekt einschließlich seiner _id zurück.

{
  "jobVersion": "",
  "priority": 1,
  "debugLevel": 2,
  "tags": {},
  "labels": [],
  "properties": {},
  "name": "Test_api_task",
  "description": "task with api settings",
  "jobType": "vcTilesVector",
  "schedule": {
    "type": "immediate"
  },
  "projectId": "b68056fc-86ed-4681-...",
  "createdAt": "2026-03-12T13:59:38.664Z",
  "updatedAt": "2026-03-12T13:59:38.664Z",
  "createdBy": "v6WEM2A92...",
  "updatedBy": "v6WEM2A92...",
  "_id": "07047f43-26ed-4a40-...",
  "lastJobId": "954b1c80-7917-4ca0-...",
  "parameters": { ... },
}

Workflow 5: Daten hochladen & Datenquelle erstellen

Teil A – Daten in einen Data Bucket hochladen

Ein Data Bucket ist ein Speichercontainer innerhalb eines Projekts. Jedes Projekt hat einen Standard-Data-Bucket, der automatisch zusammen mit dem Projekt erstellt wird.

Schritt 1 – Ziel-Data-Bucket ermitteln

GET /api/v1/project/\{projectId}/data-buckets

Die Antwort enthält eine Liste der Data Buckets im Projekt.

{
  "items": [
    {
      "_id": "57d6913d-af53-4292-...",
      "properties": {},
      "name": "default-b68056fc-86ed-...",
      "createdAt": "2026-01-08T09:15:15.741Z",
      "updatedAt": "2026-01-08T09:15:15.741Z",
      "createdBy": "v6WEM2A92ozfZaAu5",
      "updatedBy": "v6WEM2A92ozfZaAu5",
      "projectId": "b68056fc-86ed-4681-..."
    }
  ],
  "limit": 20,
  "page": 0,
  "totalCount": 1,
  "totalPages": 1
}

Schritt 2 – Datei hochladen

POST /api/v1/project/\{projectId}/data-bucket/{dataBucketId}/upload

Hängen Sie overwrite=true an, um eine vorhandene Datei mit demselben Namen zu überschreiben. Die Swagger UI bietet ein Datei-Upload-Feld, über das Benutzer zur Datei auf ihrem lokalen Computer navigieren können.

Ein erfolgreicher Einzeldatei-Upload gibt 204 zurück. Beim Hochladen mehrerer Dateien kann die API 207 Multi-Status zurückgeben, wenn nur einige Dateien erfolgreich waren.

Teil B – Datenquelle erstellen

Eine Datenquelle ist eine registrierte Referenz auf Daten, die in einem Data Bucket oder unter einer externen URL gespeichert sind.

Es gibt zwei Quelltypen: internal (Data Bucket) und external (URL).

Interne Datenquelle:

POST /api/v1/project/\{projectId}/datasource

{
  "name": "Name der Datenquelle",
  "type": "geojson",
  "typeProperties": {
    "screenSpaceError": 16
  },
  "sourceProperties": {
    "type": "internal",
    "dataBucketId": "{dataBucketId}",
    "dataBucketKey": "pfad/zur/hochgeladenen/datei.json"
  }
}

Externe Datenquelle:

POST /api/v1/project/\{projectId}/datasource

{
  "name": "Name der Datenquelle",
  "type": "wms",
  "typeProperties": {
    "layers": ["layer_name"],
    "version": "1.3.0",
    "format": "image/png"
  },
  "sourceProperties": {
    "type": "external",
    "url": "https://example.com/wms"
  }
}

Die folgenden type-Werte werden unterstützt:

Typ Beschreibung

tileset

3D-Kachelset (z. B. Cesium 3D Tiles)

geojson

GeoJSON-Vektordaten

oblique

Schrägluftbilder

qmesh

Quantized-Mesh-Gelände

meshinmesh

Geländenetz im Netz

wms

Web Map Service

wmts

Web Map Tile Service

tms

Tile Map Service

cog

Cloud Optimized GeoTIFF

flatgeobuf

FlatGeobuf-Vektordaten

i3s

I3S Scene Layer

vectortiles

Vektorkacheln

generic

Generischer / benutzerdefinierter Typ

panorama

Panoramabilder

Eine erfolgreiche Antwort gibt 201 Created zurück:

{
  "_id": "ds-id-xyz...",
  "name": "Name der Datenquelle",
  "type": "geojson",
  "uri": "https://publisher-url.de/data/...",
  "projectId": "proj-id-abc123",
  "jobIds": [],
  "publishTaskIds": [],
  "dataUpdatedAt": "2026-03-11T09:30:00.000Z",
  "dataUpdatedBy": "user-id"
}

Schritt 5 – Alle Datenquellen auflisten

GET /api/v1/project/\{projectId}/datasources

Workflow 6: App mit Modulen erstellen

Schritt 1 – App erstellen

Um eine App zu erstellen, senden Sie eine POST-Anfrage an /api/v1/project/{projectId}/app mit dem App-Namen, einer Beschreibung und einem Array von Modul-IDs. Das Feld mapVersion gibt die VC Map Viewer Engine-Version als Semver-Bereich an. Zusätzlich kann eine MemberId als Query-String hinzugefügt werden. Wenn keine MemberId angegeben wird, wird die App mit den Berechtigungen des anfragenden Benutzers erstellt. Wenn eine MemberId angegeben wird, wird die App mit den Berechtigungen dieses Benutzers erstellt. Die MemberId muss dem Projekt bereits zugewiesen sein.

POST /api/v1/project/\{projectId}/app
{
  "name": "Meine Stadt-App",
  "description": "Öffentlich zugängliche 3D-Stadt-App",
  "mapVersion": "^6.0.0",
  "moduleIds": ["module-id-abc"]
}

Wenn mehrere Module in moduleIds aufgeführt sind, werden deren Layer und Viewpoints sequenziell zusammengeführt. Die Erstellung eines Moduls wird im nächsten Schritt beschrieben, aber Module können auch unabhängig erstellt und später zur App hinzugefügt werden.

Eine erfolgreiche Antwort gibt 201 Created zurück:

{
  "_id": "app-id-xyz",
  "name": "Meine Stadt-App",
  "projectId": "proj-id-abc123",
  "moduleIds": ["module-id-abc"],
  "mapVersion": "^6.0.0",
  "publishTaskIds": [],
  "isPublic": false,
  "createdAt": "2026-03-13T10:47:45.931Z",
  "updatedAt": "2026-03-13T10:47:45.931Z",
  "createdBy": "v6WEM2A92ozfZaAu5",
  "updatedBy": "v6WEM2A92ozfZaAu5"
}

Speichern Sie die _id als {appId}. Die App ist erst öffentlich zugänglich, nachdem sie in Schritt 6 veröffentlicht wurde.

Schritt 2 – Modul erstellen

POST /api/v1/project/\{projectId}/module

{
   "name":"Mein Basismodul",
   "description":"Beschreibung meines Basismoduls",
   "properties":{
   },
   "layers":[
      {
         "type":"OpenStreetMapLayer",
         "name":"OpenStreetMapLayer(1)",
         "properties":{
            "attributions":{
               "provider":"OpenStreetMap contributors",
               "url":"http://www.openstreetmap.org/",
               "year":"2026"
            }
         },
         "activeOnStartup":true,
         "zIndex":0
      },
      {
         "type":"GeoJSONLayer",
         "name":"test_api_datasource",
         "activeOnStartup":true,
         "url":"./datasource-data/f4a59d97-4401-45ab-b31a-2e5ad6569fc9/testLake3_withZ.json",
         "extent":{
            "coordinates":[
               12.278030916360558,
               53.76142514632812,
               12.32886225819537,
               53.778920631506764
            ],
            "projection":{
               "type":"Projection",
               "epsg":"EPSG:4326"
            },
            "type":"Extent"
         },
         "datasourceId":"f4a59d97-4401-45ab-b31a-2e5ad6569fc9",
         "zIndex":0
      }
   ],
   "maps":[
      {
         "type":"CesiumMap",
         "name":"CesiumMap"
      }
   ],
   "contentTree":[
      {
         "type":"LayerContentTreeItem",
         "name":"OpenStreetMapLayer(1)",
         "layerName":"OpenStreetMapLayer(1)"
      }
   ],
   "startingMapName":"CesiumMap",
}

Die Layer im Modul können auf Datenquellen referenzieren, die in Workflow 5 erstellt wurden. Eine erfolgreiche Antwort gibt 201 Created zurück:

{
  "_id": "module-id-abc",
  "name": "Mein Basismodul",
  "projectId": "proj-id-abc123",
  "layers": [ ... ],
  "viewpoints": [ ... ],
  "createdAt": "2026-03-11T09:45:00.000Z"
}

Schritt 3 – Module hinzufügen

Dies ersetzt das bestehende moduleIds-Array vollständig – fügen Sie alle Module ein, nicht nur die neuen: Es müssen nur die Felder in den Anfrage-Body aufgenommen werden, die überschrieben werden sollen.

PUT /api/v1/project/\{projectId}/app/\{appId}

{
  "moduleIds": ["module-id-abc", "module-id-second"]
}