{
  "openapi": "3.0.3",
  "info": {
    "title": "App Builder API",
    "version": "1.0.0",
    "description": "App Builder \u2014 custom apps, versions, templates, components, and datasets."
  },
  "servers": [
    {
      "url": "https://versus-demo.com"
    }
  ],
  "paths": {
    "/api/app-templates/": {
      "get": {
        "operationId": "app_templates_list",
        "description": "Read-only catalog for the \"New App\" template gallery. Creation\nalways goes through VersusAppViewSet.new_version(from_template_id=...)\nagainst a real (empty) app the user just created \u2014 this viewset only\nlists what's available to clone from.",
        "parameters": [
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "app-templates"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AppTemplate"
                  }
                }
              }
            },
            "description": ""
          }
        },
        "summary": "List app templates"
      }
    },
    "/api/app-templates/{id}/": {
      "get": {
        "operationId": "app_templates_retrieve",
        "description": "Read-only catalog for the \"New App\" template gallery. Creation\nalways goes through VersusAppViewSet.new_version(from_template_id=...)\nagainst a real (empty) app the user just created \u2014 this viewset only\nlists what's available to clone from.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this app template.",
            "required": true
          }
        ],
        "tags": [
          "app-templates"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppTemplate"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve app template"
      }
    },
    "/api/apps/": {
      "get": {
        "operationId": "apps_list",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/VersusApp"
                  }
                }
              }
            },
            "description": ""
          }
        },
        "summary": "List apps"
      },
      "post": {
        "operationId": "apps_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Create app"
      }
    },
    "/api/apps/{app_pk}/versions/": {
      "get": {
        "operationId": "apps_versions_list",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "A page number within the paginated result set.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAppVersionList"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Versions: app"
      },
      "post": {
        "operationId": "apps_versions_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Versions: app"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/": {
      "get": {
        "operationId": "apps_versions_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve version"
      },
      "put": {
        "operationId": "apps_versions_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update version"
      },
      "patch": {
        "operationId": "apps_versions_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update version"
      },
      "delete": {
        "operationId": "apps_versions_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/discard/": {
      "delete": {
        "operationId": "apps_versions_discard_destroy",
        "description": "Permanently delete a draft version. Refuses published/rolled_back versions.",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Discard: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/entitlement-options/": {
      "get": {
        "operationId": "apps_versions_entitlement_options_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Entitlement options: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/entitlements/": {
      "get": {
        "operationId": "apps_versions_entitlements_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Entitlements: version"
      },
      "post": {
        "operationId": "apps_versions_entitlements_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Entitlements: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/entitlements/{ent_pk}/": {
      "patch": {
        "operationId": "apps_versions_entitlements_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "ent_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update entitlement"
      },
      "delete": {
        "operationId": "apps_versions_entitlements_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "ent_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete entitlement"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/navigation/": {
      "patch": {
        "operationId": "apps_versions_navigation_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Navigation: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/preview/": {
      "post": {
        "operationId": "apps_versions_preview_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Preview: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/publish/": {
      "post": {
        "operationId": "apps_versions_publish_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Publish: version"
      }
    },
    "/api/apps/{app_pk}/versions/{id}/theme/": {
      "patch": {
        "operationId": "apps_versions_theme_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppVersionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppVersion"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Theme: version"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/": {
      "get": {
        "operationId": "apps_versions_forms_list",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FormDefinitionList"
                  }
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Forms: version"
      },
      "post": {
        "operationId": "apps_versions_forms_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Forms: version"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/": {
      "get": {
        "operationId": "apps_versions_forms_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve form"
      },
      "put": {
        "operationId": "apps_versions_forms_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update form"
      },
      "patch": {
        "operationId": "apps_versions_forms_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update form"
      },
      "delete": {
        "operationId": "apps_versions_forms_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/binding/": {
      "get": {
        "operationId": "apps_versions_forms_binding_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Binding: form"
      },
      "put": {
        "operationId": "apps_versions_forms_binding_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Binding: form"
      },
      "patch": {
        "operationId": "apps_versions_forms_binding_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Binding: form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/embed-tokens/": {
      "get": {
        "operationId": "apps_versions_forms_embed_tokens_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Embed tokens: form"
      },
      "post": {
        "operationId": "apps_versions_forms_embed_tokens_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Embed tokens: form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/embed-tokens/{token_pk}/": {
      "delete": {
        "operationId": "apps_versions_forms_embed_tokens_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "token_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete embed token"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/fields/": {
      "post": {
        "operationId": "apps_versions_forms_fields_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Fields: form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/fields/{field_pk}/": {
      "patch": {
        "operationId": "apps_versions_forms_fields_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "field_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedFormDefinitionRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update field"
      },
      "delete": {
        "operationId": "apps_versions_forms_fields_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "field_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete field"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/render-schema/": {
      "get": {
        "operationId": "apps_versions_forms_render_schema_retrieve",
        "description": "Return the form's field list with conditional_logic pre-evaluated.\nQuery params: any field_key=value pairs to evaluate against, plus\n_as_role=<role> for RBAC filtering.\n\nUsed by the runtime to resolve initial visibility and required states.",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Render schema: form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/forms/{id}/reorder-fields/": {
      "post": {
        "operationId": "apps_versions_forms_reorder_fields_create",
        "description": "Accepts {order: [field_id, ...]} and updates positions.",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/FormDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormDefinition"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Reorder fields: form"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/pages/": {
      "get": {
        "operationId": "apps_versions_pages_list",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "A page number within the paginated result set.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAppPageList"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Pages: version"
      },
      "post": {
        "operationId": "apps_versions_pages_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Pages: version"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/pages/{id}/": {
      "get": {
        "operationId": "apps_versions_pages_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve page"
      },
      "put": {
        "operationId": "apps_versions_pages_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update page"
      },
      "patch": {
        "operationId": "apps_versions_pages_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppPageRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppPageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppPageRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update page"
      },
      "delete": {
        "operationId": "apps_versions_pages_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete page"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/pages/{id}/publish/": {
      "post": {
        "operationId": "apps_versions_pages_publish_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Publish: page"
      }
    },
    "/api/apps/{app_pk}/versions/{version_pk}/pages/{id}/unpublish/": {
      "post": {
        "operationId": "apps_versions_pages_unpublish_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "app_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string"
            },
            "required": true
          },
          {
            "in": "path",
            "name": "version_pk",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppPageRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppPage"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Unpublish: page"
      }
    },
    "/api/apps/{id}/": {
      "get": {
        "operationId": "apps_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve app"
      },
      "put": {
        "operationId": "apps_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update app"
      },
      "patch": {
        "operationId": "apps_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update app"
      },
      "delete": {
        "operationId": "apps_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete app"
      }
    },
    "/api/apps/{id}/new_version/": {
      "post": {
        "operationId": "apps_new_version_create",
        "description": "Create a new draft AppVersion (clones from source_version_id or highest version).\n\nfrom_template_id is a distinct, explicit path for the \"New App\"\ntemplate gallery \u2014 it clones from an AppTemplate's source_version,\nwhich deliberately lives on a DIFFERENT (hidden, is_template_source)\napp, so it bypasses the app.versions scoping below on purpose. Kept\nseparate from source_version_id rather than loosening that\nlookup's scope, since existing callers use source_version_id\nassuming it's always one of this same app's own versions.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "New version: app"
      }
    },
    "/api/apps/{id}/rollback/": {
      "post": {
        "operationId": "apps_rollback_create",
        "description": "Re-point published_version to a prior published AppVersion.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/VersusAppRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Rollback: app"
      }
    },
    "/api/apps/{id}/sso/": {
      "get": {
        "operationId": "apps_sso_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Sso: app"
      },
      "patch": {
        "operationId": "apps_sso_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this versus app.",
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedVersusAppRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VersusApp"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Sso: app"
      }
    },
    "/api/apps/runtime/{slug}/": {
      "get": {
        "operationId": "apps_runtime_retrieve",
        "description": "Public-facing endpoint that returns the published (or previewed) app config.",
        "parameters": [
          {
            "in": "path",
            "name": "slug",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "apps"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "No response body"
          }
        },
        "summary": "Retrieve runtime"
      }
    },
    "/api/components/": {
      "get": {
        "operationId": "components_list",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "name": "ordering",
            "required": false,
            "in": "query",
            "description": "Which field to use when ordering the results.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "required": false,
            "in": "query",
            "description": "A page number within the paginated result set.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page_size",
            "required": false,
            "in": "query",
            "description": "Number of results to return per page.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "A search term.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "tags": [
          "components"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedAppComponentList"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "List components"
      },
      "post": {
        "operationId": "components_create",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "tags": [
          "components"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppComponent"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Create component"
      }
    },
    "/api/components/{id}/": {
      "get": {
        "operationId": "components_retrieve",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this app component.",
            "required": true
          }
        ],
        "tags": [
          "components"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppComponent"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Retrieve component"
      },
      "put": {
        "operationId": "components_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this app component.",
            "required": true
          }
        ],
        "tags": [
          "components"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/AppComponentRequest"
              }
            }
          },
          "required": true
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppComponent"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update component"
      },
      "patch": {
        "operationId": "components_partial_update",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this app component.",
            "required": true
          }
        ],
        "tags": [
          "components"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppComponentRequest"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppComponentRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PatchedAppComponentRequest"
              }
            }
          }
        },
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppComponent"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "Update component"
      },
      "delete": {
        "operationId": "components_destroy",
        "description": "Deploy-safe base for making an existing DRF ModelViewSet tenant-isolated\n(VS-SPEC-TENANT-IDENTITY-001 \u00a714). Use as the FIRST base:\n\n    class DeviceViewSet(TenantScopedModelViewSet, viewsets.ModelViewSet):\n        queryset = Device.objects.select_related(...)\n        ...\n\nUnlike the strict TenantScopedViewSet pilot, this **degrades gracefully**:\nit is INERT unless the tenant_scoped alias is configured\n(TENANT_SCOPED_DATABASE_URL) AND the request carries a tenant_id claim.\nWhen inert it behaves exactly like a plain ModelViewSet \u2014 so the rollout\nlands additively and isolation switches on only once the non-superuser\nPostgres role exists (mirrors tenant_subdomain.py's \"inert unless\nconfigured\" contract). When active: reads route through the RLS-enforcing\nconnection and tenant_id is stamped server-side (never client input).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "A UUID string identifying this app component.",
            "required": true
          }
        ],
        "tags": [
          "components"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "204": {
            "description": "No response body"
          }
        },
        "summary": "Delete component"
      }
    },
    "/api/datasets/": {
      "get": {
        "operationId": "datasets_retrieve",
        "tags": [
          "datasets"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "No response body"
          }
        },
        "summary": "List datasets"
      }
    },
    "/api/datasets/{key}/data/": {
      "get": {
        "operationId": "datasets_data_retrieve",
        "parameters": [
          {
            "in": "path",
            "name": "key",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "tags": [
          "datasets"
        ],
        "security": [
          {
            "jwtAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "No response body"
          }
        },
        "summary": "Data: dataset"
      }
    }
  },
  "components": {
    "schemas": {
      "VersusAppRequest": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": "string"
          },
          "default_locale": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10
          },
          "access_min_level": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "access_scoped_role_ids": {}
        },
        "required": [
          "name",
          "slug"
        ]
      },
      "OrientationEnum": {
        "enum": [
          "left_rail",
          "top_bar"
        ],
        "type": "string",
        "description": "* `left_rail` - Left Rail\n* `top_bar` - Top Bar"
      },
      "AppThemeModeEnum": {
        "enum": [
          "light",
          "dark",
          "system"
        ],
        "type": "string",
        "description": "* `light` - Light\n* `dark` - Dark\n* `system` - System"
      },
      "WorkflowBindingChangeTypeEnum": {
        "enum": [
          "standard",
          "normal"
        ],
        "type": "string",
        "description": "* `standard` - Standard\n* `normal` - Normal"
      },
      "AppComponent": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "key": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "description": {
            "type": "string"
          },
          "widget_tree": {},
          "params_schema": {},
          "is_builtin": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "created_at",
          "id",
          "key",
          "name",
          "updated_at"
        ]
      },
      "FormField": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "field_key": {
            "type": "string",
            "maxLength": 100
          },
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "help_text": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/FormFieldTypeEnum"
          },
          "required": {
            "type": "boolean"
          },
          "default_value": {
            "nullable": true
          },
          "placeholder": {
            "type": "string",
            "maxLength": 300
          },
          "validation": {},
          "options_source": {
            "nullable": true
          },
          "maps_to_input": {
            "type": "string",
            "maxLength": 200
          },
          "role_visibility": {},
          "position": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          }
        },
        "required": [
          "field_key",
          "id",
          "label",
          "type"
        ]
      },
      "PatchedAppPageRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "position": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "status": {
            "$ref": "#/components/schemas/AppPageStatusEnum"
          },
          "layout": {},
          "visibility": {},
          "is_landing_for": {}
        }
      },
      "FormDefinitionList": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "request_type_key": {
            "type": "string",
            "maxLength": 100
          },
          "sub_action": {
            "type": "string",
            "maxLength": 50
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "category": {
            "type": "string",
            "description": "Groups catalog items by category in the CatalogList widget",
            "maxLength": 60
          },
          "icon": {
            "type": "string",
            "description": "Icon name for this catalog item card",
            "maxLength": 50
          },
          "intro_md": {
            "type": "string",
            "readOnly": true
          },
          "field_count": {
            "type": "string",
            "readOnly": true
          },
          "has_binding": {
            "type": "string",
            "readOnly": true
          },
          "submission_stats": {
            "type": "string",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "field_count",
          "has_binding",
          "id",
          "intro_md",
          "name",
          "request_type_key",
          "submission_stats",
          "updated_at"
        ]
      },
      "AppVersionRequest": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "created_by": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "AppTemplate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string"
          },
          "icon": {
            "type": "string",
            "maxLength": 50
          },
          "category": {
            "type": "string",
            "maxLength": 100
          },
          "sort_order": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "form_count": {
            "type": "integer",
            "readOnly": true
          }
        },
        "required": [
          "form_count",
          "id",
          "name"
        ]
      },
      "VersusAppStatusEnum": {
        "enum": [
          "draft",
          "published",
          "archived"
        ],
        "type": "string",
        "description": "* `draft` - Draft\n* `published` - Published\n* `archived` - Archived"
      },
      "PatchedAppVersionRequest": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "created_by": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "FormDefinitionRequest": {
        "type": "object",
        "properties": {
          "request_type_key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "sub_action": {
            "type": "string",
            "maxLength": 50
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "category": {
            "type": "string",
            "description": "Groups catalog items by category in the CatalogList widget",
            "maxLength": 60
          },
          "icon": {
            "type": "string",
            "description": "Icon name for this catalog item card",
            "maxLength": 50
          },
          "intro_md": {
            "type": "string"
          },
          "success_md": {
            "type": "string"
          },
          "layout": {},
          "conditional_logic": {}
        },
        "required": [
          "name",
          "request_type_key"
        ]
      },
      "PaginatedAppComponentList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=4"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=2"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppComponent"
            }
          }
        }
      },
      "State26fEnum": {
        "enum": [
          "draft",
          "preview",
          "published",
          "rolled_back"
        ],
        "type": "string",
        "description": "* `draft` - Draft\n* `preview` - Preview\n* `published` - Published\n* `rolled_back` - Rolled Back"
      },
      "PatchedVersusAppRequest": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "description": {
            "type": "string"
          },
          "default_locale": {
            "type": "string",
            "minLength": 1,
            "maxLength": 10
          },
          "access_min_level": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "access_scoped_role_ids": {}
        }
      },
      "FormDefinition": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "request_type_key": {
            "type": "string",
            "maxLength": 100
          },
          "sub_action": {
            "type": "string",
            "maxLength": 50
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "category": {
            "type": "string",
            "description": "Groups catalog items by category in the CatalogList widget",
            "maxLength": 60
          },
          "icon": {
            "type": "string",
            "description": "Icon name for this catalog item card",
            "maxLength": 50
          },
          "intro_md": {
            "type": "string"
          },
          "success_md": {
            "type": "string"
          },
          "layout": {},
          "conditional_logic": {},
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormField"
            },
            "readOnly": true
          },
          "binding": {
            "allOf": [
              {
                "$ref": "#/components/schemas/WorkflowBinding"
              }
            ],
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "binding",
          "created_at",
          "fields",
          "id",
          "name",
          "request_type_key",
          "updated_at"
        ]
      },
      "AppPageStatusEnum": {
        "enum": [
          "draft",
          "published"
        ],
        "type": "string",
        "description": "* `draft` - Draft\n* `published` - Published"
      },
      "AppPageRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "slug": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "position": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "status": {
            "$ref": "#/components/schemas/AppPageStatusEnum"
          },
          "layout": {},
          "visibility": {},
          "is_landing_for": {}
        },
        "required": [
          "name",
          "slug"
        ]
      },
      "PaginatedAppPageList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=4"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=2"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppPage"
            }
          }
        }
      },
      "PatchedAppComponentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "description": {
            "type": "string"
          },
          "widget_tree": {},
          "params_schema": {},
          "is_builtin": {
            "type": "boolean"
          }
        }
      },
      "FormFieldTypeEnum": {
        "enum": [
          "text",
          "textarea",
          "number",
          "select",
          "multiselect",
          "date",
          "datetime",
          "toggle",
          "device_picker",
          "environment_picker",
          "ip_input",
          "cidr",
          "port",
          "fqdn",
          "member_list",
          "cert_picker",
          "zone_picker",
          "file",
          "ca_account_picker",
          "cert_profile_picker",
          "pool_member_table",
          "fw_rule_table",
          "panos_device_group",
          "panos_version_select",
          "panos_content_policy",
          "secret_copy",
          "privileged_session"
        ],
        "type": "string",
        "description": "* `text` - Text\n* `textarea` - Textarea\n* `number` - Number\n* `select` - Select\n* `multiselect` - Multi-select\n* `date` - Date\n* `datetime` - Date & Time\n* `toggle` - Toggle\n* `device_picker` - Device Picker\n* `environment_picker` - Environment Picker\n* `ip_input` - IP Address\n* `cidr` - CIDR\n* `port` - Port\n* `fqdn` - FQDN\n* `member_list` - Member List\n* `cert_picker` - Certificate Picker\n* `zone_picker` - Zone Picker\n* `file` - File Upload\n* `ca_account_picker` - CA Profile Picker\n* `cert_profile_picker` - Certificate Profile Picker\n* `pool_member_table` - Pool Member Table\n* `fw_rule_table` - Firewall Rule Table\n* `panos_device_group` - PAN-OS Device Group\n* `panos_version_select` - PAN-OS Version Selector\n* `panos_content_policy` - PAN-OS Content Policy\n* `secret_copy` - Secret Copy (vault)\n* `privileged_session` - Privileged Session (vault)"
      },
      "AppVersionList": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "version_no": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "state": {
            "$ref": "#/components/schemas/State26fEnum"
          },
          "created_by_name": {
            "type": "string",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "created_at",
          "created_by_name",
          "id",
          "version_no"
        ]
      },
      "PaginatedAppVersionList": {
        "type": "object",
        "required": [
          "count",
          "results"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "example": 123
          },
          "next": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=4"
          },
          "previous": {
            "type": "string",
            "nullable": true,
            "format": "uri",
            "example": "http://api.example.org/accounts/?page=2"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AppVersion"
            }
          }
        }
      },
      "VersusApp": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "slug": {
            "type": "string",
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "description": {
            "type": "string"
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VersusAppStatusEnum"
              }
            ],
            "readOnly": true
          },
          "published_version": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AppVersionList"
              }
            ],
            "readOnly": true
          },
          "default_locale": {
            "type": "string",
            "maxLength": 10
          },
          "access_min_level": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "access_scoped_role_ids": {},
          "created_by": {
            "type": "integer",
            "readOnly": true,
            "nullable": true
          },
          "created_by_name": {
            "type": "string",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "version_count": {
            "type": "string",
            "readOnly": true
          }
        },
        "required": [
          "created_at",
          "created_by",
          "created_by_name",
          "id",
          "name",
          "published_version",
          "slug",
          "status",
          "updated_at",
          "version_count"
        ]
      },
      "AppPage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "app_version": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "name": {
            "type": "string",
            "maxLength": 200
          },
          "slug": {
            "type": "string",
            "maxLength": 200,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "position": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648
          },
          "status": {
            "$ref": "#/components/schemas/AppPageStatusEnum"
          },
          "layout": {},
          "visibility": {},
          "is_landing_for": {},
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          }
        },
        "required": [
          "app_version",
          "created_at",
          "id",
          "name",
          "slug",
          "updated_at"
        ]
      },
      "AppTheme": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "logo_url": {
            "type": "string"
          },
          "favicon_url": {
            "type": "string"
          },
          "wordmark_text": {
            "type": "string",
            "maxLength": 100
          },
          "color_primary": {
            "type": "string",
            "maxLength": 20
          },
          "color_secondary": {
            "type": "string",
            "maxLength": 20
          },
          "color_accent": {
            "type": "string",
            "maxLength": 20
          },
          "color_bg": {
            "type": "string",
            "maxLength": 20
          },
          "color_surface": {
            "type": "string",
            "maxLength": 20
          },
          "color_text": {
            "type": "string",
            "maxLength": 20
          },
          "color_semantic": {},
          "typography": {},
          "mode": {
            "$ref": "#/components/schemas/AppThemeModeEnum"
          },
          "custom_css": {
            "type": "string"
          }
        },
        "required": [
          "id"
        ]
      },
      "NavigationConfig": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "orientation": {
            "$ref": "#/components/schemas/OrientationEnum"
          },
          "items": {}
        },
        "required": [
          "id"
        ]
      },
      "PatchedFormDefinitionRequest": {
        "type": "object",
        "properties": {
          "request_type_key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "sub_action": {
            "type": "string",
            "maxLength": 50
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "category": {
            "type": "string",
            "description": "Groups catalog items by category in the CatalogList widget",
            "maxLength": 60
          },
          "icon": {
            "type": "string",
            "description": "Icon name for this catalog item card",
            "maxLength": 50
          },
          "intro_md": {
            "type": "string"
          },
          "success_md": {
            "type": "string"
          },
          "layout": {},
          "conditional_logic": {}
        }
      },
      "WorkflowBinding": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "workflow_ref": {
            "type": "string",
            "maxLength": 300
          },
          "input_map": {},
          "approval_policy_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "itsm_binding_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "env_overrides": {},
          "direct_run": {
            "type": "boolean"
          },
          "gates": {},
          "change_type": {
            "$ref": "#/components/schemas/WorkflowBindingChangeTypeEnum"
          }
        },
        "required": [
          "id"
        ]
      },
      "AppVersion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "app": {
            "type": "string",
            "format": "uuid",
            "readOnly": true
          },
          "version_no": {
            "type": "integer",
            "readOnly": true
          },
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "state": {
            "allOf": [
              {
                "$ref": "#/components/schemas/State26fEnum"
              }
            ],
            "readOnly": true
          },
          "config_snapshot": {
            "readOnly": true
          },
          "theme": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AppTheme"
              }
            ],
            "readOnly": true
          },
          "navigation": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NavigationConfig"
              }
            ],
            "readOnly": true
          },
          "created_by": {
            "type": "integer",
            "nullable": true
          },
          "created_by_name": {
            "type": "string",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "nullable": true
          }
        },
        "required": [
          "app",
          "config_snapshot",
          "created_at",
          "created_by_name",
          "id",
          "navigation",
          "published_at",
          "state",
          "theme",
          "version_no"
        ]
      },
      "AppComponentRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "key": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "pattern": "^[-a-zA-Z0-9_]+$"
          },
          "version": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": 0
          },
          "description": {
            "type": "string"
          },
          "widget_tree": {},
          "params_schema": {},
          "is_builtin": {
            "type": "boolean"
          }
        },
        "required": [
          "key",
          "name"
        ]
      }
    }
  }
}