39948-vm/documentation/api-reference.md
2026-07-03 16:11:24 +02:00

33 KiB

API Reference - E2E Documentation

Overview

The Tour Builder Platform exposes a RESTful API built with Express.js. All endpoints follow consistent patterns for CRUD operations, authentication, and response formats.

Base URL: http://localhost:3000/api for local development.

Standard VM: Apache serves the public domain on port 80, the frontend PM2 app listens on 3001, and the backend PM2 app listens on 3000 with NODE_ENV=dev_stage. Use http://127.0.0.1:3000/api/... for direct VM backend checks, or http://tbp.flatlogic.app/api/... through Apache/Cloudflare. See deployment-vm.md.


Authentication

JWT Bearer Token

Most endpoints require JWT authentication via the Authorization header:

Authorization: Bearer <token>

Token Details:

  • Expiration: 6 hours
  • Payload: { id, email, name }
  • Obtained via /api/auth/signin/local or OAuth callbacks

Public Endpoints (No Auth Required)

  • GET /api/health
  • POST /api/auth/signin/local
  • POST /api/auth/send-password-reset-email
  • PUT /api/auth/password-reset
  • PUT /api/auth/verify-email
  • GET /api/auth/email-configured
  • GET /api/auth/signin/google
  • GET /api/auth/signin/microsoft
  • GET /api/runtime-context

Runtime Public Access

In production runtime mode only, certain GET endpoints allow unauthenticated read access (stage requires authentication):

  • GET /api/projects
  • GET /api/tour_pages
  • GET /api/project_audio_tracks
  • GET /api/global-ui-control-defaults
  • GET /api/project-ui-control-settings/project/:projectId/env/production

Note: The X-Runtime-Environment header must be set to production for public access. Stage environment (stage) requires JWT authentication as it serves as a workspace for review.


Standard Response Formats

Success Responses

Single Entity:

{
  "id": "uuid-here",
  "name": "Entity Name",
  "createdAt": "2024-01-01T00:00:00.000Z",
  "updatedAt": "2024-01-01T00:00:00.000Z"
}

List Response:

{
  "rows": [
    { "id": "uuid-1", "name": "Entity 1" },
    { "id": "uuid-2", "name": "Entity 2" }
  ],
  "count": 100
}

Count Response:

{
  "count": 100
}

Error Responses

{
  "error": "Error message description"
}

HTTP Status Codes:

Code Description
200 Success
201 Created
400 Bad Request (validation errors)
401 Unauthorized (missing/invalid token)
403 Forbidden (insufficient permissions)
404 Not Found
429 Too Many Requests (rate limited)
500 Internal Server Error

Rate Limiting

The API uses rate limiting to prevent abuse. Rate limits are applied per IP address, and rate limit headers are returned with each response:

Header Description
X-RateLimit-Limit Maximum requests allowed per window
X-RateLimit-Remaining Remaining requests in current window
X-RateLimit-Reset ISO timestamp when the window resets
Retry-After Seconds until you can retry (when limited)

Rate Limit Configuration

Limiter Window Max Requests Endpoints
Auth 15 minutes 10 /api/auth/signin/*
Password Reset 1 hour 5 /api/auth/send-password-reset-email
API 1 minute 100 General API endpoints
Upload 1 minute 10 /api/file/upload*
Download 1 minute 200 /api/file/download, /api/file/presign
Search 1 minute 30 /api/search

Note: Rate limiting is skipped for localhost (127.0.0.1, ::1) in development mode.


Standard Entity Endpoints

All entity routes (projects, assets, users, etc.) support these standard endpoints:

Method Endpoint Description
GET /api/{entity} List entities (paginated)
GET /api/{entity}/count Get count only
GET /api/{entity}/autocomplete Autocomplete search
GET /api/{entity}/:id Get single entity by ID
POST /api/{entity} Create entity
PUT /api/{entity}/:id Update entity
DELETE /api/{entity}/:id Delete entity
POST /api/{entity}/deleteByIds Bulk delete
POST /api/{entity}/bulk-import CSV import

GET /api/{entity}/count

Get count of entities matching the query.

Query Parameters: Same as list endpoint

Response:

{
  "count": 100
}

GET /api/{entity}/autocomplete

Get autocomplete suggestions for a field.

Query Parameters:

Parameter Type Description
query string Search query
limit number Max results (default: 10)
offset number Pagination offset

Response:

[
  { "id": "uuid-1", "label": "Option 1" },
  { "id": "uuid-2", "label": "Option 2" }
]

Standard Query Parameters

All list endpoints support these query parameters:

Parameter Type Default Description
limit number 10 Items per page
offset number 0 Pagination offset
page number 0 Page number (alternative to offset)
search string - Text search across searchable fields
sort string - Sort field (e.g., name or name:DESC)
filetype string - Export format (csv)

Entity-Specific Filters

Filters vary by entity based on their SEARCHABLE_FIELDS, RANGE_FIELDS, and ENUM_FIELDS:

# Text search
?search=keyword

# Range filters (numeric/date)
?createdAtRange=2024-01-01,2024-12-31
?sizeRange=0,1000000

# Enum/exact match filters
?type=image
?status=active
?environment=production

# Relationship filters
?projectId=uuid
?tour_pageId=uuid

Authentication Endpoints

POST /api/auth/signin/local

Login with email and password.

Rate Limit: 10 requests per 15 minutes

Request:

{
  "email": "user@example.com",
  "password": "password123"
}

Response:

{
  "id": "user-uuid",
  "email": "user@example.com",
  "firstName": "John",
  "lastName": "Doe",
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

Self-Registration

Self-registration is disabled. The API does not expose POST /api/auth/signup; new users are created through the authenticated Users flow and receive an invitation/setup link.

GET /api/auth/me

Get current authenticated user.

Auth: Required

Response:

{
  "id": "user-uuid",
  "email": "user@example.com",
  "firstName": "John",
  "lastName": "Doe",
  "app_role": {
    "id": "role-uuid",
    "name": "Admin"
  }
}

PUT /api/auth/password-update

Update password for authenticated user.

Auth: Required

Request:

{
  "currentPassword": "oldpassword",
  "newPassword": "newpassword123"
}

POST /api/auth/send-password-reset-email

Send password reset email.

Rate Limit: 5 requests per hour

Request:

{
  "email": "user@example.com"
}

POST /api/auth/send-email-address-verification-email

Resend email verification email for current user.

Auth: Required

Response: true on success

PUT /api/auth/password-reset

Reset password with token.

Request:

{
  "token": "reset-token-from-email",
  "password": "newpassword123"
}

PUT /api/auth/profile

Update user profile.

Auth: Required

Request:

{
  "profile": {
    "firstName": "John",
    "lastName": "Doe",
    "phoneNumber": "+1234567890"
  }
}

OAuth Endpoints

Endpoint Description
GET /api/auth/signin/google Initiate Google OAuth
GET /api/auth/signin/google/callback Google OAuth callback
GET /api/auth/signin/microsoft Initiate Microsoft OAuth
GET /api/auth/signin/microsoft/callback Microsoft OAuth callback

System Endpoints

GET /api/health

Health check endpoint.

Auth: Not required

Response:

{
  "status": "ok",
  "timestamp": "2024-01-01T00:00:00.000Z",
  "uptime": 3600,
  "environment": "production",
  "database": "connected"
}

GET /api/runtime-context

Get runtime context information.

Auth: Not required

Response:

{
  "mode": "admin",
  "projectSlug": null
}

Modes:

  • admin - Full access (localhost or admin subdomain)
  • stage - Stage environment (stage.{project}.domain)
  • production - Production environment ({project}.domain)

File Endpoints

POST /api/file/upload-sessions/init

Initialize chunked upload session.

Auth: Required

Request:

{
  "filename": "video.mp4",
  "size": 104857600,
  "mimeType": "video/mp4",
  "projectId": "project-uuid"
}

Response:

{
  "sessionId": "session-uuid",
  "chunkSize": 5242880,
  "totalChunks": 20,
  "expiresAt": "2024-01-02T00:00:00.000Z"
}

GET /api/file/upload-sessions/:sessionId

Get upload session status.

Auth: Required

Response:

{
  "sessionId": "session-uuid",
  "filename": "video.mp4",
  "uploadedChunks": [0, 1, 2],
  "totalChunks": 20,
  "status": "uploading"
}

PUT /api/file/upload-sessions/:sessionId/chunks/:chunkIndex

Upload file chunk.

Auth: Required

Content-Type: application/octet-stream

Body: Raw binary data

Response:

{
  "chunkIndex": 0,
  "received": true
}

POST /api/file/upload-sessions/:sessionId/finalize

Finalize chunked upload.

Auth: Required

Response:

{
  "success": true,
  "asset": {
    "id": "asset-uuid",
    "url": "https://cdn.example.com/video.mp4",
    "storageKey": "uploads/video.mp4"
  }
}

GET /api/file/download

Download file.

Query Parameters:

  • privateUrl - Encoded file path
  • id - Asset ID (alternative)

Response: File stream with appropriate Content-Type

POST /api/file/presign

Generate presigned URLs for batch asset downloads. For S3 storage, returns direct S3 signed URLs for client-side downloads (bypassing the backend). For other storage providers, returns backend proxy URLs.

Auth: Not required (public endpoint for runtime asset preloading)

Request:

{
  "urls": [
    "uploads/projects/abc/image1.jpg",
    "uploads/projects/abc/video.mp4",
    "uploads/projects/abc/audio.mp3"
  ]
}

Limits:

  • Maximum 50 URLs per request
  • All URLs must be non-empty strings

Response:

{
  "presignedUrls": {
    "uploads/projects/abc/image1.jpg": "https://bucket.s3.region.amazonaws.com/uploads/projects/abc/image1.jpg?X-Amz-...",
    "uploads/projects/abc/video.mp4": "https://bucket.s3.region.amazonaws.com/uploads/projects/abc/video.mp4?X-Amz-...",
    "uploads/projects/abc/audio.mp3": "https://bucket.s3.region.amazonaws.com/uploads/projects/abc/audio.mp3?X-Amz-..."
  }
}

Presigned URL Expiry: 1 hour (3600 seconds)

Use Case: Frontend preloading uses this endpoint to get direct S3 download URLs, enabling:

  • Parallel asset downloads without backend proxy overhead
  • Direct storage in browser Cache API
  • Blob URL creation for instant display

POST /api/file/upload/:table/:field

Legacy single-file upload.

Auth: Required

Content-Type: multipart/form-data


Projects Endpoints

POST /api/projects

Create a new project.

Auth: Required

Request:

{
  "data": {
    "name": "My Tour",
    "slug": "my-tour",
    "description": "A virtual tour",
    "logo_url": "https://...",
    "favicon_url": "https://...",
    "og_image_url": "https://...",
    "theme_config_json": {},
    "custom_css_json": {},
    "cdn_base_url": "https://cdn.example.com"
  }
}

GET /api/projects

List all projects.

Auth: Optional (runtime public mode)

Query Parameters:

  • Standard pagination/filtering

Response:

{
  "rows": [
    {
      "id": "project-uuid",
      "name": "My Tour",
      "slug": "my-tour",
      "tour_pages": [...],
      "assets": [...]
    }
  ],
  "count": 10
}

GET /api/projects/:id

Get project by ID.

Auth: Optional (runtime public mode)

Includes: tour_pages, assets, project_audio_tracks, project_element_defaults

PUT /api/projects/:id

Update project.

Auth: Required

Request:

{
  "id": "project-uuid",
  "data": {
    "name": "Updated Tour Name"
  }
}

DELETE /api/projects/:id

Delete project.

Auth: Required

POST /api/projects/:id/clone

Clone project with all related entities.

Auth: Required

Response:

{
  "id": "new-project-uuid",
  "name": "My Tour (Copy)",
  "slug": "my-tour-copy"
}

POST /api/publish/save-to-stage

Copy all dev environment content to stage for preview.

Auth: Required

Request:

{
  "projectId": "project-uuid"
}

Response:

{
  "success": true,
  "publishEventId": "event-uuid",
  "summary": {
    "pages_copied": 10,
    "audios_copied": 2
  }
}

Note: This is part of the dev → stage → production workflow. Content is edited in dev (Constructor), previewed in stage, then published to production. Page elements, navigation, and transitions are stored in tour_pages.ui_schema_json and copied with pages.

Tour Pages Endpoints

POST /api/tour_pages

Create a tour page.

Auth: Required

Request:

{
  "data": {
    "title": "Home Page",
    "slug": "home",
    "sort_order": 0,
    "projectId": "project-uuid",
    "environment": "dev",
    "background_image_url": "https://...",
    "background_video_url": "https://...",
    "ui_schema_json": {}
  }
}

GET /api/tour_pages

List tour pages.

Auth: Optional (runtime public mode)

Query Parameters:

  • projectId - Filter by project
  • environment - Filter by environment

GET /api/tour_pages/:id

Get tour page by ID.

Includes: project

Note: Page elements are stored directly in the ui_schema_json field.

PUT /api/tour_pages/:id

Update tour page.

Auth: Required

POST /api/tour_pages/reorder

Update page order within a project/environment without touching page content.

Auth: Required

Request:

{
  "data": {
    "projectId": "project-uuid",
    "environment": "dev",
    "orderedPageIds": ["page-uuid-1", "page-uuid-2", "page-uuid-3"]
  }
}

Behavior:

  • Reordering is allowed only in dev.
  • orderedPageIds must contain every dev page in that project exactly once.
  • Duplicate IDs, missing IDs, IDs from another project, and unknown IDs are rejected.
  • The backend updates only sort_order; page content, slugs, navigation links, and media fields are not changed.
  • Stage receives the new order after POST /api/publish/save-to-stage.
  • Production receives the new order after POST /api/publish.

Response:

[
  { "id": "page-uuid-1", "sort_order": 1 },
  { "id": "page-uuid-2", "sort_order": 2 },
  { "id": "page-uuid-3", "sort_order": 3 }
]

Errors:

Status Reason
400 Missing projectId, invalid orderedPageIds, duplicate/missing pages, or environment other than dev
403 Authenticated user is not allowed to update pages in the project

POST /api/tour_pages/:id/duplicate

Duplicate a dev tour page into a new independent dev page.

Auth: Required

Request:

{
  "data": {
    "projectId": "project-uuid",
    "environment": "dev",
    "name": "Lobby Copy",
    "slug": "lobby-copy"
  }
}

Behavior:

  • Only dev pages can be duplicated. Stage and production are updated through Save to Stage and Publish.
  • The duplicate receives a new page ID, unique slug, blank source_key, and sort_order = max(project dev sort_order) + 1.
  • Page media/settings fields and ui_schema_json are copied from the source page.
  • Inline element IDs and nested item IDs in ui_schema_json are regenerated so the new page can be edited independently.
  • Asset URLs, transition URLs, and navigation targetPageSlug values are preserved.
  • Existing reverse-video processing still runs through TourPagesService, so transition reverse URLs are handled consistently with normal page save/create.

Response: Created tour page record.

Errors:

Status Reason
400 Missing source page, source page outside project, or non-dev source/target environment
403 Authenticated user is not allowed to create/update pages in the project

DELETE /api/tour_pages/:id

Delete tour page.

Auth: Required

Constructor behavior: the constructor uses this same endpoint for the active dev page after showing a confirmation modal. After deletion it reloads page data and selects the next page in presentation order when available.


Assets Endpoints

POST /api/assets

Create an asset record.

Auth: Required

Request:

{
  "data": {
    "name": "Hero Image",
    "cdn_url": "https://cdn.example.com/image.jpg",
    "storage_key": "uploads/image.jpg",
    "mime_type": "image/jpeg",
    "checksum": "abc123...",
    "width_px": 1920,
    "height_px": 1080,
    "size_mb": 0.5,
    "duration_sec": null,
    "projectId": "project-uuid"
  }
}

GET /api/assets

List assets.

Auth: Required

Query Parameters:

  • projectId - Filter by project
  • mime_type - Filter by MIME type

Includes: asset_variants, project

GET /api/assets/:id

Get asset by ID.

Includes: asset_variants

PUT /api/assets/:id

Update asset.

Auth: Required

DELETE /api/assets/:id

Delete asset (and file from storage).

Auth: Required


Asset Variants Endpoints

POST /api/asset_variants

Create an asset variant.

Auth: Required

Request:

{
  "data": {
    "assetId": "asset-uuid",
    "variant_type": "webp",
    "cdn_url": "https://cdn.example.com/image.webp",
    "storage_key": "uploads/image.webp",
    "mime_type": "image/webp",
    "width_px": 1920,
    "height_px": 1080,
    "size_bytes": 51200
  }
}

Variant Types:

  • thumbnail - Small preview
  • preview - Medium preview
  • webp - WebP format
  • mp4_low - Low quality video
  • mp4_high - High quality video
  • original - Original file

GET /api/asset_variants

List asset variants.

Auth: Required

Query Parameters:

  • assetId - Filter by parent asset
  • variant_type - Filter by variant type

Project Audio Tracks Endpoints

POST /api/project_audio_tracks

Create a project audio track.

Auth: Required

Request:

{
  "data": {
    "name": "Background Music",
    "projectId": "project-uuid",
    "audio_url": "https://cdn.example.com/music.mp3",
    "duration_sec": 180,
    "volume": 0.8,
    "loop": true,
    "autoplay": true
  }
}

GET /api/project_audio_tracks

List audio tracks.

Auth: Optional (runtime public mode)

Query Parameters:

  • projectId - Filter by project

Project Memberships Endpoints

Manage team collaboration and per-project access control.

POST /api/project_memberships

Create a project membership (invite user to project).

Auth: Required

Request:

{
  "data": {
    "projectId": "project-uuid",
    "userId": "user-uuid",
    "access_level": "editor",
    "is_active": true,
    "invited_at": "2024-01-01T00:00:00.000Z"
  }
}

Access Levels: owner, editor, reviewer, viewer

GET /api/project_memberships

List project memberships.

Auth: Required

Query Parameters:

  • projectId or project - Filter by project
  • userId or user - Filter by user
  • access_level - Filter by access level
  • is_active - Filter by active status

GET /api/project_memberships/:id

Get project membership by ID.

Auth: Required

Includes: project, user

PUT /api/project_memberships/:id

Update project membership.

Auth: Required

Request:

{
  "id": "membership-uuid",
  "data": {
    "access_level": "viewer",
    "is_active": false
  }
}

DELETE /api/project_memberships/:id

Remove user from project.

Auth: Required


PWA Caches Endpoints

Track PWA cache versions and offline asset manifests per project.

POST /api/pwa_caches

Create a PWA cache record.

Auth: Required

Request:

{
  "data": {
    "projectId": "project-uuid",
    "environment": "production",
    "cache_version": "v1704067200000",
    "manifest_json": {},
    "asset_list_json": [],
    "generated_at": "2024-01-01T00:00:00.000Z",
    "is_active": true
  }
}

Environment Values: dev, stage, production

GET /api/pwa_caches

List PWA cache records.

Auth: Required

Query Parameters:

  • projectId or project - Filter by project
  • environment - Filter by environment
  • is_active - Filter by active status

GET /api/pwa_caches/:id

Get PWA cache by ID.

Auth: Required

Includes: project

PUT /api/pwa_caches/:id

Update PWA cache record.

Auth: Required

DELETE /api/pwa_caches/:id

Delete PWA cache record.

Auth: Required


Users Endpoints

POST /api/users

Create a user.

Auth: Required (Admin)

Request:

{
  "data": {
    "email": "newuser@example.com",
    "password": "password123",
    "firstName": "John",
    "lastName": "Doe",
    "phoneNumber": "+1234567890",
    "app_roleId": "role-uuid"
  }
}

GET /api/users

List users.

Auth: Required

Searchable Fields: firstName, lastName, email, phoneNumber

GET /api/users/:id

Get user by ID.

Auth: Required

Includes: app_role

PUT /api/users/:id

Update user.

Auth: Required

DELETE /api/users/:id

Delete user.

Auth: Required (Admin)


Roles Endpoints

POST /api/roles

Create a role.

Auth: Required (Admin)

Request:

{
  "data": {
    "name": "Editor",
    "globalAccess": false
  }
}

GET /api/roles

List roles.

Auth: Required

GET /api/roles/:id

Get role by ID.

Includes: permissions


Permissions Endpoints

POST /api/permissions

Create a permission.

Auth: Required (Admin)

Request:

{
  "data": {
    "roleId": "role-uuid",
    "entity": "projects",
    "action": "read"
  }
}

Actions: create, read, update, delete


Publishing Endpoints

The platform uses a three-tier publishing workflow:

┌─────────────────────────────────────────────────────────────────┐
│  Constructor (dev)    Stage (preview)     Production (live)     │
│       dev        ───►    stage       ───►   production          │
│  "Save to Stage"      "Publish"                                 │
└─────────────────────────────────────────────────────────────────┘

POST /api/publish/save-to-stage

Copy dev content to stage for preview. See Projects Endpoints.

POST /api/publish (or POST /api/publish/publish)

Publish project from stage to production environment. Both endpoints are aliases and perform the same action.

Auth: Required

Request:

{
  "projectId": "project-uuid",
  "title": "v1.0 Release",
  "description": "Initial production release"
}

Response:

{
  "success": true,
  "publishEventId": "event-uuid",
  "summary": {
    "pages_copied": 10,
    "audios_copied": 2
  }
}

Note: Publishes stage environment content to production. Use save-to-stage first to copy changes from dev. Page elements, navigation links, and transitions are stored within tour_pages.ui_schema_json and copied automatically with pages.


Publish Events Endpoints

GET /api/publish_events

List publish events.

Auth: Required

Query Parameters:

  • projectId - Filter by project

Response:

{
  "rows": [
    {
      "id": "event-uuid",
      "projectId": "project-uuid",
      "title": "v1.0 Release",
      "description": "Initial release",
      "publishedAt": "2024-01-01T00:00:00.000Z",
      "createdBy": "user-uuid"
    }
  ],
  "count": 5
}

Access Logs Endpoints

POST /api/access_logs

Create an access log entry.

Auth: Required

Request:

{
  "data": {
    "project": "project-uuid",
    "user": "user-uuid",
    "environment": "production",
    "path": "/api/tour_pages",
    "ip_address": "192.168.1.1",
    "user_agent": "Mozilla/5.0...",
    "accessed_at": "2024-01-01T00:00:00.000Z"
  }
}

Environment Values: admin, stage, production

GET /api/access_logs

List access logs.

Auth: Required

Searchable Fields: path, ip_address, user_agent

Query Parameters:

  • project - Filter by project ID or name
  • user - Filter by user ID or name
  • environment - Filter by environment (admin/stage/production)
  • accessed_atRange - Filter by date range

Presigned URL Requests Endpoints

Track and audit presigned URL generation requests.

POST /api/presigned_url_requests

Create a presigned URL request record.

Auth: Required

Request:

{
  "data": {
    "requested_key": "uploads/projects/abc/image.jpg",
    "mime_type": "image/jpeg",
    "status": "pending",
    "requested_size_mb": 2.5,
    "expires_at": "2024-01-01T01:00:00.000Z"
  }
}

Status Values: pending, completed, expired, failed

GET /api/presigned_url_requests

List presigned URL requests.

Auth: Required

Query Parameters:

  • status - Filter by status
  • requested_key - Filter by storage key

GET /api/presigned_url_requests/:id

Get presigned URL request by ID.

Auth: Required

PUT /api/presigned_url_requests/:id

Update presigned URL request.

Auth: Required

DELETE /api/presigned_url_requests/:id

Delete presigned URL request.

Auth: Required


Global UI Control Defaults Endpoints

Global UI controls are the system-owned fullscreen, sound, and offline buttons. Runtime settings resolve through:

global_ui_control_defaults → project_ui_control_settings → tour_pages.global_ui_controls_settings_json

GET /api/global-ui-control-defaults

Get singleton platform defaults.

Auth: Not required for runtime reads

PUT /api/global-ui-control-defaults/:id

Update singleton platform defaults.

Auth: Required

GET /api/project-ui-control-settings/project/:projectId/env/:environment

Get project/environment overrides. environment is dev, stage, or production.

Auth: Required for dev and stage. Production is public for public presentations and requires JWT/access grants for private production presentations.

PUT /api/project-ui-control-settings/project/:projectId/env/:environment

Upsert project/environment overrides.

Auth: Required

DELETE /api/project-ui-control-settings/project/:projectId/env/:environment

Delete project/environment overrides so runtime falls back to global defaults.

Auth: Required


Element Type Defaults Endpoints

Global platform-wide default settings for each element type. These are the source of truth that get snapshotted to project_element_defaults when a project is created.

Alias: /api/ui-elements routes to the same endpoints as /api/element-type-defaults.

Note: The Constructor page uses project_element_defaults (not this endpoint) to fetch element defaults for the current project. This endpoint is for platform-wide administration of default settings.

GET /api/element-type-defaults

List all element type defaults.

Auth: Required

Response:

{
  "rows": [
    {
      "id": "uuid",
      "element_type": "navigation_next",
      "name": "Navigation: Forward",
      "sort_order": 1,
      "is_active": true,
      "default_settings_json": {
        "width": "60px",
        "height": "60px",
        "opacity": 1
      }
    }
  ],
  "count": 11
}

GET /api/element-type-defaults/:id

Get element type default by ID.

Auth: Required

PUT /api/element-type-defaults/:id

Update element type default settings.

Auth: Required (Admin)

Request:

{
  "id": "uuid",
  "data": {
    "default_settings_json": {
      "width": "80px",
      "height": "80px"
    }
  }
}

Project Element Defaults Endpoints

Project-specific default settings for UI elements. These are automatically snapshotted from global defaults (element_type_defaults) when a project is created. The Constructor page uses this endpoint to fetch element defaults for the current project.

Three-Tier Element Defaults Hierarchy:

element_type_defaults (global) → project_element_defaults (project) → tour_pages.ui_schema_json (instance)

GET /api/project-element-defaults

List project element defaults.

Auth: Required

Query Parameters:

  • projectId or project - Filter by project ID or name (recommended)
  • Supports | pipe separator for multiple values

Response:

{
  "rows": [
    {
      "id": "uuid",
      "projectId": "project-uuid",
      "element_type": "navigation_next",
      "name": "Navigation: Forward",
      "sort_order": 1,
      "settings_json": {
        "width": "60px",
        "height": "60px"
      },
      "source_element_id": "global-default-uuid",
      "snapshot_version": 1
    }
  ],
  "count": 11
}

GET /api/project-element-defaults/:id

Get project element default by ID.

Auth: Required

PUT /api/project-element-defaults/:id

Update project-specific default settings.

Auth: Required

Request:

{
  "id": "uuid",
  "data": {
    "settings_json": {
      "width": "100px",
      "backgroundColor": "#ff0000"
    }
  }
}

POST /api/project-element-defaults/:id/reset

Reset project default to current global default. Copies settings from element_type_defaults and increments snapshot_version.

Auth: Required

Response: Returns the updated project element default record:

{
  "id": "uuid",
  "projectId": "project-uuid",
  "element_type": "navigation_next",
  "name": "Navigation: Forward",
  "sort_order": 1,
  "settings_json": { "width": "60px", "height": "60px" },
  "source_element_id": "global-default-uuid",
  "snapshot_version": 2,
  "createdAt": "2024-01-01T00:00:00.000Z",
  "updatedAt": "2024-01-15T00:00:00.000Z"
}

Error: Returns 500 if global default not found for the element type.

GET /api/project-element-defaults/:id/diff

Compare project default with current global default.

Auth: Required

Response:

{
  "projectDefault": {
    "id": "uuid",
    "element_type": "navigation_next",
    "settings_json": { "width": "100px" }
  },
  "globalDefault": {
    "id": "global-uuid",
    "element_type": "navigation_next",
    "default_settings_json": { "width": "60px" }
  },
  "hasGlobalDefault": true,
  "isDifferent": true,
  "projectSettings": { "width": "100px" },
  "globalSettings": { "width": "60px" }
}

Response when global default not found:

{
  "projectDefault": { ... },
  "globalDefault": null,
  "hasGlobalDefault": false,
  "isDifferent": true
}

Search Endpoint

POST /api/search

Search across all entities. Searches both text fields and numeric fields (cast to text for matching).

Auth: Required

Rate Limit: 30 requests per minute per IP

Request:

{
  "searchQuery": "keyword"
}

Response: Returns a flat array of matching records from all searchable tables. Each record includes tableName and matchAttribute fields to identify the source and matching fields.

[
  {
    "id": "uuid-1",
    "name": "My Project",
    "slug": "my-project",
    "tableName": "projects",
    "matchAttribute": ["name", "slug"]
  },
  {
    "id": "uuid-2",
    "title": "Home Page",
    "tableName": "tour_pages",
    "matchAttribute": ["title"]
  }
]

Searchable Tables & Fields:

Table Text Fields Numeric Fields
users firstName, lastName, phoneNumber, email -
projects name, slug, description, logo_url, favicon_url, og_image_url -
assets name, cdn_url, storage_key, mime_type, checksum size_mb, width_px, height_px, duration_sec
asset_variants cdn_url width_px, height_px, size_mb
presigned_url_requests requested_key, mime_type, status requested_size_mb
tour_pages source_key, name, slug, background_image_url, background_video_url, background_audio_url, ui_schema_json sort_order
project_audio_tracks source_key, name, slug, url volume, sort_order
publish_events error_message pages_copied, transitions_copied, audios_copied
pwa_caches cache_version, manifest_json, asset_list_json -
access_logs path, ip_address, user_agent -

Permission Check: Search results are filtered based on user permissions. Only tables where user has READ_{TABLE_NAME} permission are searched.

Limit: Maximum 50 results per table.


Bulk Operations

POST /api/{entity}/deleteByIds

Bulk delete entities.

Auth: Required

Request:

{
  "data": ["uuid-1", "uuid-2", "uuid-3"]
}

Response:

{
  "deleted": 3
}

POST /api/{entity}/bulk-import

Bulk import from CSV.

Auth: Required

Content-Type: multipart/form-data

Form Fields:

  • file - CSV file
  • importHash - Unique import identifier

Response:

{
  "imported": 50,
  "errors": []
}

CSV Export

Add ?filetype=csv to any list endpoint to export as CSV.

Example:

GET /api/projects?filetype=csv&limit=1000

Response: CSV file download with appropriate headers


Swagger Documentation

Interactive API documentation available at:

GET /api-docs

Provides Swagger UI with all endpoints, request/response schemas, and testing capabilities.