API Reference· v1.3.1

This library provides 3D assets for the Living Magazine Unreal Engine Platform. This application was made as part of the x-CITE CitiVerse project. Access the X-CITE Living Magazine asset library programmatically. Public GET endpoints are intended for Unreal Engine and other clients, with CORS enabled for all origins. Authenticated write endpoints are documented here as well.

Base URL/api/v1

Overview

All responses follow a consistent envelope format:

{
  "data": { ... },       // Response payload (object or array)
  "meta": {              // Pagination info (null for single-resource endpoints)
    "total": 42,
    "limit": 20,
    "offset": 0,
    "hasMore": true
  },
  "error": null          // Error object (null on success)
}

All endpoints support an optional fresh=true query parameter. By default, responses are served from a fast global CDN cache. Add ?fresh=true to bypass the cache and get guaranteed real-time data - ideal for applications like Unreal Engine that need instant updates after changes.

Every endpoint card includes an Open Test Window link so your Unreal Engine developer can quickly inspect live JSON in a separate tab while integrating. For public `GET` routes, the raw JSON can also be opened directly in the browser.

200
Successful request
400
Invalid parameters
404
Resource not found

Endpoints

GET/api/v1/assets

Retrieve a paginated list of all public assets. Supports filtering by asset type and searching by title.

Test This Endpoint
/api/v1/assets?type=3d&search=jas&limit=5

Query Parameters

ParameterTypeDefaultDescription
limitnumber20Number of items per page (max 100)
offsetnumber0Number of items to skip
typestring-Filter by asset type: 3d, image, text, or video
searchstring-Search assets by title (prefix match)
freshbooleanfalseBypass CDN cache for real-time data
{
  "data": [
    {
      "_id": "abc123",
      "title": "Office Chair",
      "slug": "office-chair",
      "assetType": "3d",
      "normalizedScale": 1,
      "fileSize": 2458624,
      "_createdAt": "2025-06-15T10:30:00Z",
      "author": { "_id": "author-1", "name": "Jane Doe" },
      "modelFileUrl": "https://cdn.sanity.io/.../chair.glb",
      "imageFileUrl": null,
      "videoFileUrl": null,
      "thumbnailUrl": "https://cdn.sanity.io/.../thumb.png",
      "textContent": null
    }
  ],
  "meta": { "total": 42, "limit": 20, "offset": 0, "hasMore": true },
  "error": null
}
GET/api/v1/assets/:slug

Retrieve a single public asset by its slug. Returns all asset details including file URLs and author information.

Test This Endpoint
/api/v1/assets/jas

Query Parameters

ParameterTypeDefaultDescription
freshbooleanfalseBypass CDN cache for real-time data
{
  "data": {
    "_id": "abc123",
    "title": "Office Chair",
    "slug": "office-chair",
    "assetType": "3d",
    "normalizedScale": 1,
    "fileSize": 2458624,
    "_createdAt": "2025-06-15T10:30:00Z",
    "author": { "_id": "author-1", "name": "Jane Doe" },
    "modelFileUrl": "https://cdn.sanity.io/.../chair.glb",
    "imageFileUrl": null,
    "videoFileUrl": null,
    "thumbnailUrl": "https://cdn.sanity.io/.../thumb.png",
    "textContent": null
  },
  "meta": null,
  "error": null
}
GET/api/v1/spaces

Retrieve a paginated list of all spaces (geographic locations). Includes asset count per space for efficiency.

Test This Endpoint
/api/v1/spaces?limit=100&fresh=true

Query Parameters

ParameterTypeDefaultDescription
limitnumber20Number of items per page (max 100)
offsetnumber0Number of items to skip
freshbooleanfalseBypass CDN cache for real-time data
{
  "data": [
    {
      "_id": "space-1",
      "title": "Howest Campus",
      "slug": "howest-campus",
      "latitude": 51.1873,
      "longitude": 3.2046,
      "_createdAt": "2025-05-01T09:00:00Z",
      "assetCount": 12
    }
  ],
  "meta": { "total": 5, "limit": 20, "offset": 0, "hasMore": false },
  "error": null
}
GET/api/v1/spaces/:slug

Retrieve a single space with all its placed assets, including model details and transform data (position, rotation, scale).

Test This Endpoint
/api/v1/spaces/bd-city

Query Parameters

ParameterTypeDefaultDescription
freshbooleanfalseBypass CDN cache for real-time data
{
  "data": {
    "_id": "space-1",
    "title": "Howest Campus",
    "slug": "howest-campus",
    "latitude": 51.1873,
    "longitude": 3.2046,
    "_createdAt": "2025-05-01T09:00:00Z",
    "assets": [
      {
        "_key": "m1abc",
        "placedBy": "google-oauth2|12345",
        "model": {
          "_id": "abc123",
          "title": "Office Chair",
          "slug": "office-chair",
          "assetType": "3d",
          "normalizedScale": 1,
          "thumbnailUrl": "https://cdn.sanity.io/.../thumb.png",
          "modelFileUrl": "https://cdn.sanity.io/.../chair.glb"
        },
        "position": { "x": 100, "y": 0, "z": -50 },
        "rotation": { "pitch": 0, "yaw": 45, "roll": 0 },
        "scale": { "x": 1, "y": 1, "z": 1 }
      }
    ]
  },
  "meta": null,
  "error": null
}
GET/api/space-tiles/:slug/tileset

Streaming 3D Tileset (OGC 3D Tiles 1.1) for a space that has hosted tiles. Returns the tileset.json with absolute, georeferenced GLB content URIs - load it directly in Cesium (see the 3D Tiles · Unreal guide below). Public and CORS-enabled. Returns 404 if the space has no hosted tiles. NOTE: this route is NOT under /api/v1, and it returns a raw tileset.json (not the data/meta/error envelope).

Test This Endpoint
/api/space-tiles/test-self-hosted-tiles/tileset
{
  "asset": { "version": "1.1", "generator": "Up3date 3D Tiles Exporter" },
  "geometricError": 873.06,
  "root": {
    "boundingVolume": { "box": [ /* ... */ ] },
    "geometricError": 0,
    "refine": "ADD",
    "content": {
      "uri": "https://<host>/api/proxy-file?url=https%3A%2F%2Fcdn.sanity.io%2F...%2Ftiles.glb"
    },
    "transform": [ /* 4x4 ECEF placement matrix */ ]
  }
}

3D Tiles in Unreal (Cesium)

A space can host a streaming 3D Tileset (an OGC 3D Tiles 1.1 tileset.json + .glb content). Each one is served at a public, CORS-enabled URL that Cesium for Unreal can load directly — no API key or login. The same URL is also published as a 3dtiles resource in the clearly.hub dataset, so the digital-twin loader picks it up automatically too.

Tileset URL
https://xcite-lm-assets.vercel.app/api/space-tiles/{slug}/tileset

Replace {slug} with a space slug from GET /api/v1/spaces. The tileset carries a real-world ECEF transform, so it places itself at its true geographic location.

Load it in Unreal Engine
  1. Enable the Cesium for Unreal plugin (from Fab / the Epic marketplace) and restart the editor.
  2. Open the Cesium panel and add a Blank 3D Tiles Tileset. This creates a Cesium3DTileset actor (and a CesiumGeoreference if the level doesn't have one).
  3. Select the tileset actor → in Details → Cesium, set Source to From Url.
  4. Paste the tileset URL into the Url field. No authentication headers are needed.
  5. Set the CesiumGeoreference Origin Latitude / Longitude to the space's latitude/longitude (from the spaces API) so the scene origin sits on the tiles.
  6. Press Play — the tiles stream in at their real-world location.
Discovering tilesets: call GET /api/v1/spaces for slugs + lat/lon, then request /api/space-tiles/{slug}/tileset. A space with hosted tiles returns the tileset JSON (200); otherwise it returns 404.

Notes

  • Position values are in Unreal Engine units (centimeters). Rotation uses pitch/yaw/roll in degrees.
  • Only public assets are returned by the API. Private assets are excluded.
  • The search parameter uses prefix matching on asset titles.
  • normalizedScale is a uniform scale factor (power of 10: 100, 10, 1, 0.1, 0.01) computed on upload so models display at a consistent ~1 m size. Apply it as the default scale when placing assets.
  • fileSize is the file size in bytes of the uploaded asset (3D model, image, or video). Not present for text assets.
  • File URLs point directly to the Sanity CDN. Supported 3D format: GLB. Video assets can also include videoPreviewFileUrl, a WebM preview for Unreal Engine embedded Chromium.
  • CORS is enabled for all origins. No API key or authentication is needed.