Skip to content

Projects API

Manage projects through the REST API. All endpoints require authentication.

List Projects

http
GET /api/projects/
Authorization: Bearer <token>

Response:

json
{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "550e8400-...",
      "name": "My Mall",
      "description": "Shopping center map",
      "organization": "org-uuid",
      "organization_name": "My Company",
      "group": null,
      "group_name": null,
      "status": "PUBLISH",
      "settings": {
        "defaultLevelId": "level-uuid",
        "scrollMode": "default",
        "theme": "auto",
        "defaultLanguage": "en"
      },
      "appearance": {
        "isZoomControlsVisible": true,
        "isSearchBarVisible": true,
        "isLevelSwitcherVisible": true,
        "canvasBackgroundColor": "#ffffff",
        "canvasBorderRadius": "large",
        "routeColor": "#0066cc",
        "routeWidth": 5,
        "hidePoweredBy": false,
        "customCss": ""
      },
      "analytics": {
        "isEnabled": true,
        "enabledEvents": []
      },
      "thumbnail": null,
      "created_at": "2026-04-01T10:00:00Z",
      "updated_at": "2026-04-12T14:30:00Z",
      "live_updated_at": "2026-04-10T12:00:00Z"
    }
  ]
}

Get Project

http
GET /api/projects/{id}/
Authorization: Bearer <token>

Returns the full project with nested levels, areas, markers, tags, languages, wayfinding, and translations.

Create Project

http
POST /api/projects/
Authorization: Bearer <token>
Content-Type: application/json

{
  "organization": "org-uuid",
  "name": "My Mall",
  "description": "Shopping center map",
  "group": "group-uuid"
}

The project is created in Draft status. Draft and publish limits are enforced based on your subscription plan.

Response: Full project object (same as Get).

Update Project

http
PATCH /api/projects/{id}/
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Updated Name",
  "settings": {
    "defaultLevelId": "level-uuid",
    "scrollMode": "ctrl",
    "theme": "dark",
    "defaultLanguage": "ru"
  },
  "appearance": {
    "isSearchBarVisible": false,
    "canvasBorderRadius": "none"
  }
}

TIP

Use PATCH for partial updates — only include the fields you want to change.

Delete Project

http
DELETE /api/projects/{id}/
Authorization: Bearer <token>

DANGER

Deleting a project permanently removes all levels, areas, markers, and analytics data.

Publish / Unpublish

Publish

http
POST /api/projects/{id}/publish/
Authorization: Bearer <token>

Publishing makes the project accessible via the embed URL and public API. Checks:

  • Subscription must be active (paid plans)
  • Must not exceed organization or group build limit

Unpublish

http
POST /api/projects/{id}/unpublish/
Authorization: Bearer <token>

Moves the project back to Draft. The embed URL stops working.

Update Live

http
POST /api/projects/{id}/update-live/
Authorization: Bearer <token>

Pushes latest changes to the published version without changing status. Only works for already published projects.

Archive / Restore

Archive

http
POST /api/projects/{id}/archive/
Authorization: Bearer <token>

Restore

http
POST /api/projects/{id}/restore/
Authorization: Bearer <token>

Restores an archived project back to Draft status.

Duplicate

http
POST /api/projects/{id}/duplicate/
Authorization: Bearer <token>
Content-Type: application/json

{ "name": "Custom name" }

Creates a deep copy of the project as a new Draft. Body fields are optional — when name is omitted the copy is auto-named "{original} (Copy)", falling back to (Copy 2), (Copy 3), ... if that name is already in use.

Copied: all levels (with their image files), areas, markers, tags, translations, project languages, settings, appearance, analytics configuration, and wayfinding (corridors, branches, transitions).

Not copied: version history snapshots, accumulated analytics events, and the published live snapshot. The copy is always created as Draft, even if the source is Published.

Errors:

  • 403 plan_limit_reached — org or group draft limit would be exceeded
  • 403 — viewer role
  • 400name collides with an existing project in the same organization

Snapshots (Version History)

Pro & EnterpriseVersion history requires a Pro or Enterprise subscription.
Compare plans

List Snapshots

http
GET /api/projects/{id}/snapshots/
Authorization: Bearer <token>

Response:

json
[
  {
    "id": "snapshot-uuid",
    "created_at": "2026-04-12T14:30:00Z"
  }
]

Restore Snapshot

http
POST /api/projects/{id}/snapshots/{snapshot_id}/restore/
Authorization: Bearer <token>

Tags

List Tags

http
GET /api/projects/{id}/tags/
Authorization: Bearer <token>

Response:

json
[
  { "id": "tag-uuid", "name": "Food", "color": "#FF5733" },
  { "id": "tag-uuid", "name": "Shopping", "color": "#3366FF" }
]

Create Tag

http
POST /api/projects/{id}/tags/
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Services",
  "color": "#9E9E9E"
}

Update Tag

http
PATCH /api/projects/{id}/tags/{tag_id}/
Authorization: Bearer <token>
Content-Type: application/json

{
  "name": "Updated Name",
  "color": "#00AA00"
}

Delete Tag

http
DELETE /api/projects/{id}/tags/{tag_id}/
Authorization: Bearer <token>

Images

Upload Image

http
POST /api/projects/{id}/upload-image/
Authorization: Bearer <token>
Content-Type: multipart/form-data

file=<image>

Response:

json
{
  "url": "https://...",
  "path": "projects/uuid/image.png",
  "size": 204800
}

Browse Images

http
GET /api/projects/{id}/images/?page=1&page_size=12
Authorization: Bearer <token>

Response:

json
{
  "images": ["https://..."],
  "page": 1,
  "pageSize": 12,
  "totalImages": 48,
  "totalPages": 4
}

Project Statuses

StatusDescription
DRAFTWork in progress. Not publicly accessible.
PUBLISHLive. Accessible via embed and public API.
ARCHIVEArchived. Not accessible, can be restored.
EXPIREDReserved status — not produced by the normal publish/billing flows (a lapsed subscription moves projects to DRAFT). Treat as not publicly accessible.

Layota Documentation