{
  "openapi": "3.1.0",
  "info": {
    "title": "Elido API",
    "description": "URL shortener SaaS — core + analytics API surface.",
    "version": "0.1.0",
    "contact": {
      "name": "Elido",
      "url": "https://elido.app"
    }
  },
  "servers": [
    {
      "url": "https://api.elido.app",
      "description": "Production"
    }
  ],
  "security": [
    {
      "kratosSession": []
    },
    {
      "devUser": []
    }
  ],
  "tags": [
    {
      "name": "health",
      "description": "Health & readiness probes"
    },
    {
      "name": "users",
      "description": "User management (dev seed)"
    },
    {
      "name": "me",
      "description": "Current authenticated user"
    },
    {
      "name": "workspaces",
      "description": "Workspace CRUD"
    },
    {
      "name": "members",
      "description": "Workspace membership"
    },
    {
      "name": "links",
      "description": "Short-link CRUD"
    },
    {
      "name": "lookup",
      "description": "Public link resolution (used by edge-redirect)"
    },
    {
      "name": "analytics",
      "description": "Click analytics (analytics-api service)"
    },
    {
      "name": "campaigns",
      "description": "Campaign CRUD, UTM templates, and link grouping"
    },
    {
      "name": "bio",
      "description": "Bio (link-in-bio) pages and click tracking"
    },
    {
      "name": "qr",
      "description": "Branded QR code generation (qr-generator service)"
    },
    {
      "name": "pixels",
      "description": "Per-workspace retargeting pixel configuration"
    },
    {
      "name": "conversions",
      "description": "Stripe / Shopify conversion ingestion and revenue attribution"
    },
    {
      "name": "domains",
      "description": "Custom domain registration and Apple/Android app-link manifests"
    },
    {
      "name": "branding",
      "description": "Per-workspace white-label config (Business plan)"
    },
    {
      "name": "sso",
      "description": "WorkOS-backed SSO configuration and discovery"
    },
    {
      "name": "scim",
      "description": "WorkOS Directory Sync (SCIM) provisioning"
    },
    {
      "name": "compliance",
      "description": "Workspace compliance posture (HIPAA / SOC 2 / GDPR) and SOC 2 / HIPAA evidence collection"
    },
    {
      "name": "cta",
      "description": "CTA overlay management (Sniply-style call-to-action overlays)"
    },
    {
      "name": "reports",
      "description": "Scheduled email reports, async CSV exports, and broken-link audits (Phase 10)"
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "operationId": "healthz",
        "tags": [
          "health"
        ],
        "summary": "Liveness probe",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/readyz": {
      "get": {
        "operationId": "readyz",
        "tags": [
          "health"
        ],
        "summary": "Readiness probe (checks DB)",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "503": {
            "description": "Not ready",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/v1/ping": {
      "get": {
        "operationId": "ping",
        "tags": [
          "health"
        ],
        "summary": "Simple ping",
        "security": [],
        "responses": {
          "200": {
            "description": "Pong",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "const": "ok"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/users": {
      "post": {
        "operationId": "createUser",
        "tags": [
          "users"
        ],
        "summary": "Create user (dev seed)",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUserInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/users/{user_id}": {
      "get": {
        "operationId": "getUser",
        "tags": [
          "users"
        ],
        "summary": "Get user by ID",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/UserID"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "me"
        ],
        "summary": "Current authenticated user",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "patch": {
        "operationId": "patchMe",
        "tags": [
          "me"
        ],
        "summary": "Patch current user — display name, timezone, onboarding flag",
        "description": "Phase 9 — partial update. All body fields are optional; only the\nprovided ones are applied. Currently supported:\n  - `display_name` (1..120 chars; validated server-side)\n  - `timezone` (IANA name; rejected if not resolvable via\n    `time.LoadLocation`)\n  - `onboarding_completed` (boolean; flips the dashboard\n    checklist and stamps `users.onboarding_completed_at`)\n\nFuture preference toggles land here too without a SDK bump —\nthe handler ignores absent fields so old clients keep working.\n",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchMeInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/workspaces": {
      "post": {
        "operationId": "createWorkspace",
        "tags": [
          "workspaces"
        ],
        "summary": "Create workspace (caller becomes owner)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkspaceInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "get": {
        "operationId": "listWorkspaces",
        "tags": [
          "workspaces"
        ],
        "summary": "List workspaces for current user (includes role)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkspaceWithRole"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}": {
      "get": {
        "operationId": "getWorkspace",
        "tags": [
          "workspaces"
        ],
        "summary": "Get workspace by ID (any member)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateWorkspace",
        "tags": [
          "workspaces"
        ],
        "summary": "Update workspace (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkspaceInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/members": {
      "get": {
        "operationId": "listMembers",
        "tags": [
          "members"
        ],
        "summary": "List workspace members (any member)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WorkspaceMember"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "addMember",
        "tags": [
          "members"
        ],
        "summary": "Add member to workspace (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddMemberInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceMemberBasic"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/members/{user_id}": {
      "delete": {
        "operationId": "removeMember",
        "tags": [
          "members"
        ],
        "summary": "Remove member from workspace (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "$ref": "#/components/parameters/UserID"
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/links": {
      "get": {
        "operationId": "listLinks",
        "tags": [
          "links"
        ],
        "summary": "List workspace links (any member)",
        "description": "Cursor-paginated. The response includes `next_cursor` (base64-encoded\nopaque token) when more rows are available; pass it back as `?cursor=`\nfor the next page. `next_cursor: null` indicates the last page.\n\nThe legacy `?offset=` parameter is still accepted for one release as a\ndeprecated fallback. Responses to offset-based requests carry a\n`Deprecation: cursor pagination available` header.\n",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque base64-encoded cursor returned by a previous response. Omit on the first page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "deprecated": true,
            "description": "Deprecated. Pass `cursor` instead.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedLinks"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "operationId": "createLink",
        "tags": [
          "links"
        ],
        "summary": "Create short link (editor+, slug auto-generated if omitted)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLinkInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/links/{link_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "link_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "operationId": "getLink",
        "tags": [
          "links"
        ],
        "summary": "Fetch a single link by id (viewer+); 404 if not in workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateLink",
        "tags": [
          "links"
        ],
        "summary": "Partial update (editor+); fields omitted are unchanged",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLinkInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "delete": {
        "operationId": "deleteLink",
        "tags": [
          "links"
        ],
        "summary": "Soft-delete a link (editor+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/links/{link_id}/scans": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "link_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "name": "limit",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        }
      ],
      "get": {
        "operationId": "listLinkSafetyScans",
        "tags": [
          "safety"
        ],
        "summary": "Full url-scanner verdict history for a link, newest first",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LinkSafetyScan"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/safety/suspect": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "limit",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 200,
            "default": 50
          }
        },
        {
          "name": "offset",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        }
      ],
      "get": {
        "operationId": "listSuspectLinks",
        "tags": [
          "safety"
        ],
        "summary": "Workspace moderation queue — links currently suspect or blocked",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/SuspectLinkRow"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/lookup": {
      "get": {
        "operationId": "lookupLink",
        "tags": [
          "lookup"
        ],
        "summary": "Resolve link by (host|domain_id) + slug — public, no auth",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "host",
            "in": "query",
            "description": "Hostname, e.g. f.elido.me",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "domain_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Link"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/timeseries": {
      "get": {
        "operationId": "getTimeseries",
        "tags": [
          "analytics"
        ],
        "summary": "Click counts bucketed by interval",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Start date (YYYY-MM-DD). Default 30 days before `to`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "End date (YYYY-MM-DD). Default today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "interval",
            "in": "query",
            "description": "Bucket size",
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "day"
              ],
              "default": "day"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TimeseriesPoint"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/links/top": {
      "get": {
        "operationId": "getTopLinks",
        "tags": [
          "analytics"
        ],
        "summary": "Most-clicked links in time range",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "description": "Start date (YYYY-MM-DD). Default 30 days before `to`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "End date (YYYY-MM-DD). Default today.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10,
              "minimum": 1,
              "maximum": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TopLink"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/funnel": {
      "get": {
        "operationId": "getFunnel",
        "tags": [
          "analytics"
        ],
        "summary": "Engagement funnel — unique visitors per cumulative time window",
        "description": "Returns 4 funnel steps (`total`, `1h`, `24h`, `7d`) showing how\nmany unique visitors clicked within each cumulative window from the\nfirst event in the query range. Used as an engagement-decay signal.\n",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "steps"
                  ],
                  "properties": {
                    "steps": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FunnelStep"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/cohorts": {
      "get": {
        "operationId": "getCohorts",
        "tags": [
          "analytics"
        ],
        "summary": "Weekly cohort retention matrix",
        "description": "Returns one row per (cohort_week, week_offset). cohort_week is the\nISO week of the visitor's first click; week_offset is 0-based weeks\nsince acquisition. Matrix is sparse — cells with zero visitors are\nomitted; the dashboard zero-fills.\n",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "weeks",
            "in": "query",
            "description": "Max week_offset to include (1..12, default 8)",
            "schema": {
              "type": "integer",
              "default": 8,
              "minimum": 1,
              "maximum": 12
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "buckets"
                  ],
                  "properties": {
                    "buckets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CohortBucket"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/summary": {
      "get": {
        "operationId": "getEngagementSummary",
        "tags": [
          "analytics"
        ],
        "summary": "High-level engagement metrics (clicks / unique / returning / bounce)",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementSummary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/heatmap": {
      "get": {
        "operationId": "getHeatmap",
        "tags": [
          "analytics"
        ],
        "summary": "Click counts grouped by hour-of-day × day-of-week (UTC)",
        "description": "Returns one cell per (hour, day_of_week) bucket with non-zero clicks.\n`hour` is 0..23 UTC, `dow` is 1=Monday … 7=Sunday (ClickHouse\ntoDayOfWeek convention). Callers should zero-fill the 7×24 grid.\n",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "cells"
                  ],
                  "properties": {
                    "cells": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/HeatmapCell"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/clicks/recent": {
      "get": {
        "operationId": "getRecentClicks",
        "tags": [
          "analytics"
        ],
        "summary": "Recent clicks — newest first, cursor-paginated",
        "description": "Cursor-paginated. The response includes `next_cursor` (base64\nopaque token over `(timestamp, link_id)`) when more rows are\navailable; pass it back as `?cursor=` for the next page.\n`next_cursor: null` indicates the last page.\n\nThe legacy windowed (no-cursor) shape is still served when\n`?cursor=` is omitted, for backwards compatibility with\nclients that haven't been updated. Those responses also carry\na `Deprecation: cursor pagination available` header.\n",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "Opaque base64 cursor returned by a previous response. Omit on the first page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Page size (1..500, default 100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RecentClick"
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/ltv": {
      "get": {
        "operationId": "getLTV",
        "tags": [
          "analytics"
        ],
        "summary": "Lifetime-value report — engagement + revenue per acquisition cohort",
        "description": "For each ISO week of link first-click acquisition, returns visitor\ncount, lifetime click count, and attributed revenue (from\nStripe / Shopify conversions joined by `link_id`). Revenue is\nscoped to a single currency (`?currency=USD` default); links with\nno conversions in that currency contribute zero. When the\nanalytics-api process has no Postgres connection, all\n`revenue_*` fields are zero — the engagement view still renders.\n",
        "security": [
          {
            "internalToken": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WorkspaceID"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "link_id",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "currency",
            "in": "query",
            "description": "3-letter ISO currency code (default USD).",
            "schema": {
              "type": "string",
              "minLength": 3,
              "maxLength": 3,
              "default": "USD"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "currency",
                    "cohorts"
                  ],
                  "properties": {
                    "currency": {
                      "type": "string",
                      "description": "Currency the revenue figures are denominated in."
                    },
                    "cohorts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LTVCohort"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/campaigns": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listCampaigns",
        "tags": [
          "campaigns"
        ],
        "summary": "List campaigns with link counts",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Campaign"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createCampaign",
        "tags": [
          "campaigns"
        ],
        "summary": "Create a campaign (editor+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCampaignInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/campaigns/{campaign_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/CampaignID"
        }
      ],
      "patch": {
        "operationId": "updateCampaign",
        "tags": [
          "campaigns"
        ],
        "summary": "Update a campaign (editor+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCampaignInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteCampaign",
        "tags": [
          "campaigns"
        ],
        "summary": "Delete a campaign — links lose their campaign_id but survive",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/campaigns/{campaign_id}/links": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/CampaignID"
        }
      ],
      "get": {
        "operationId": "listCampaignLinks",
        "tags": [
          "campaigns"
        ],
        "summary": "List links assigned to a campaign",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedLinks"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "assignCampaignLinks",
        "tags": [
          "campaigns"
        ],
        "summary": "Bulk-assign links to this campaign (≤100 per call)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignLinkIds"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      },
      "delete": {
        "operationId": "unassignCampaignLinks",
        "tags": [
          "campaigns"
        ],
        "summary": "Bulk-unassign links from this campaign (≤100 per call)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignLinkIds"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/bio": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listBioPages",
        "tags": [
          "bio"
        ],
        "summary": "List bio pages owned by the workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BioPage"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createBioPage",
        "tags": [
          "bio"
        ],
        "summary": "Create a new bio page (username globally unique)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBioPageInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BioPage"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/bio/{bio_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/BioID"
        }
      ],
      "patch": {
        "operationId": "updateBioPage",
        "tags": [
          "bio"
        ],
        "summary": "Update display, theme, publish state",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBioPageInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BioPage"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteBioPage",
        "tags": [
          "bio"
        ],
        "summary": "Permanently delete a bio page and its links",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/bio/{bio_id}/links": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/BioID"
        }
      ],
      "get": {
        "operationId": "listBioLinks",
        "tags": [
          "bio"
        ],
        "summary": "List the link blocks on a bio page (sorted by sort_order)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BioLink"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createBioLink",
        "tags": [
          "bio"
        ],
        "summary": "Add a link block",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBioLinkInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BioLink"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/bio/{bio_id}/links/{link_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/BioID"
        },
        {
          "name": "link_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "patch": {
        "operationId": "updateBioLink",
        "tags": [
          "bio"
        ],
        "summary": "Update a single bio link",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBioLinkInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BioLink"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteBioLink",
        "tags": [
          "bio"
        ],
        "summary": "Remove a single bio link",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/bio/{bio_id}/heatmap": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "$ref": "#/components/parameters/BioID"
        }
      ],
      "get": {
        "operationId": "bioHeatmap",
        "tags": [
          "bio"
        ],
        "summary": "Click totals per bio link (lifetime)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BioHeatmapEntry"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/bio/{username}": {
      "get": {
        "operationId": "publicBioPage",
        "tags": [
          "bio"
        ],
        "summary": "Public render payload — no auth, used by bio-renderer",
        "security": [],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicBioPage"
                }
              }
            }
          },
          "404": {
            "description": "Not published or unknown username"
          }
        }
      }
    },
    "/v1/bio/{username}/click": {
      "post": {
        "operationId": "trackBioClick",
        "tags": [
          "bio"
        ],
        "summary": "Public click beacon — fire-and-forget from the rendered page",
        "security": [],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "link_id"
                ],
                "properties": {
                  "link_id": {
                    "type": "integer",
                    "format": "int64"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Recorded"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/domains": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listDomains",
        "tags": [
          "domains"
        ],
        "summary": "List custom domains registered to the workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Domain"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/domains/{domain_id}/app-links": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "domain_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "patch": {
        "operationId": "updateAppLinks",
        "tags": [
          "domains"
        ],
        "summary": "Upload Universal Links / App Links manifests for a domain",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppLinksInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/qr/generate": {
      "post": {
        "operationId": "generateQR",
        "tags": [
          "qr"
        ],
        "summary": "Render a branded QR code as PNG, SVG, or both",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateQRInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Single-format requests return the raw image bytes with the\nmatching Content-Type (image/png or image/svg+xml). Multi-format\nrequests return JSON with `png` (base64) and `svg` (string).\n",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateQRMultiResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/conversions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "limit",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "default": 50
          }
        },
        {
          "name": "offset",
          "in": "query",
          "schema": {
            "type": "integer",
            "minimum": 0,
            "default": 0
          }
        }
      ],
      "get": {
        "operationId": "listConversions",
        "tags": [
          "conversions"
        ],
        "summary": "Paginated list of attributed Stripe / Shopify orders",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedConversions"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/conversions/summary": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "conversionSummary",
        "tags": [
          "conversions"
        ],
        "summary": "Total revenue, count, and average order value",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionSummary"
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/conversions/stripe": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "post": {
        "operationId": "stripeWebhook",
        "tags": [
          "conversions"
        ],
        "summary": "Stripe webhook receiver (Stripe-Signature verified)",
        "description": "Verifies `Stripe-Signature` (HMAC-SHA256 of `t.body` with the secret\nfrom `PUT /pixels`). Listens for `checkout.session.completed` and\n`payment_intent.succeeded`; reads `metadata.elido_link_id` or\n`client_reference_id` for attribution.\n",
        "security": [],
        "parameters": [
          {
            "name": "Stripe-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Stripe event envelope (see Stripe docs)"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Accepted"
          },
          "401": {
            "description": "Bad signature or no secret configured"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/conversions/shopify": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "post": {
        "operationId": "shopifyWebhook",
        "tags": [
          "conversions"
        ],
        "summary": "Shopify webhook receiver (X-Shopify-Hmac-Sha256 verified)",
        "description": "Listens for `orders/paid`. Looks for `note_attributes[].name ==\n\"elido_link_id\"` for attribution.\n",
        "security": [],
        "parameters": [
          {
            "name": "X-Shopify-Hmac-Sha256",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Shopify Order resource (see Shopify docs)"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Accepted"
          },
          "401": {
            "description": "Bad signature or no secret configured"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/pixels": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getPixels",
        "tags": [
          "pixels"
        ],
        "summary": "Fetch pixel configuration (admin only — secrets returned as booleans)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pixels"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsertPixels",
        "tags": [
          "pixels"
        ],
        "summary": "Upsert pixel IDs and Stripe / Shopify webhook secrets",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertPixelsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pixels"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deletePixels",
        "tags": [
          "pixels"
        ],
        "summary": "Clear all pixel IDs and webhook secrets at once",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/branding": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getBranding",
        "tags": [
          "branding"
        ],
        "summary": "Read white-label config",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Branding"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsertBranding",
        "tags": [
          "branding"
        ],
        "summary": "Upsert white-label config (Business plan only — 402 on lower tiers)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertBrandingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Branding"
                }
              }
            }
          },
          "402": {
            "description": "Branding mutations require the Business plan"
          },
          "409": {
            "description": "portal_hostname already claimed by another workspace"
          }
        }
      },
      "delete": {
        "operationId": "deleteBranding",
        "tags": [
          "branding"
        ],
        "summary": "Reset to Elido defaults",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/portal/lookup": {
      "get": {
        "operationId": "portalLookup",
        "tags": [
          "branding"
        ],
        "summary": "Resolve a custom portal hostname to a workspace_id (public)",
        "security": [],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "workspace_id"
                  ],
                  "properties": {
                    "workspace_id": {
                      "type": "integer",
                      "format": "int64"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Hostname not claimed or branding disabled"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/sso": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getSSO",
        "tags": [
          "sso"
        ],
        "summary": "Read SSO configuration (admin only)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SSOConfig"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsertSSO",
        "tags": [
          "sso"
        ],
        "summary": "Bind a WorkOS Organization + Connection to this workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertSSOInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SSOConfig"
                }
              }
            }
          },
          "409": {
            "description": "connection_id or domain already enabled elsewhere"
          }
        }
      },
      "delete": {
        "operationId": "deleteSSO",
        "tags": [
          "sso"
        ],
        "summary": "Remove SSO binding",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/sso/discover": {
      "get": {
        "operationId": "discoverSSO",
        "tags": [
          "sso"
        ],
        "summary": "Public — map an email domain to a WorkOS connection_id",
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "connection_id",
                    "organization_id"
                  ],
                  "properties": {
                    "connection_id": {
                      "type": "string"
                    },
                    "organization_id": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No SSO record for this domain"
          }
        }
      }
    },
    "/v1/sso/by-connection": {
      "get": {
        "operationId": "lookupSSOByConnection",
        "tags": [
          "sso"
        ],
        "summary": "Public — map a WorkOS connection_id back to a workspace_id",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "workspace_id"
                  ],
                  "properties": {
                    "workspace_id": {
                      "type": "integer",
                      "format": "int64"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No workspace bound to this connection_id"
          }
        }
      }
    },
    "/v1/ai/resolve": {
      "get": {
        "operationId": "aiResolve",
        "tags": [
          "ai"
        ],
        "summary": "Resolve a short URL to structured metadata (for AI agents / LLM tool-use)",
        "description": "Accepts a full Elido short URL and returns JSON-LD metadata describing\nthe destination — designed for AI agents, LLM tool-use, and\nprogrammatic link inspection. No authentication required.\n",
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Full short URL (e.g. https://f.elido.me/abc)",
            "schema": {
              "type": "string",
              "format": "uri"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Structured metadata about the short link destination",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "shortUrl",
                    "destinationUrl",
                    "status",
                    "safety"
                  ],
                  "properties": {
                    "@context": {
                      "type": "string",
                      "example": "https://schema.org"
                    },
                    "@type": {
                      "type": "string",
                      "example": "WebPage"
                    },
                    "shortUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "destinationUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "name": {
                      "type": "string",
                      "description": "Page title"
                    },
                    "description": {
                      "type": "string"
                    },
                    "image": {
                      "type": "string",
                      "format": "uri"
                    },
                    "siteName": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "disabled"
                      ]
                    },
                    "safety": {
                      "type": "object",
                      "properties": {
                        "score": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 100
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "clean",
                            "suspect",
                            "blocked"
                          ]
                        }
                      }
                    },
                    "category": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid url parameter"
          },
          "404": {
            "description": "Short link not found"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/scim": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getSCIM",
        "tags": [
          "scim"
        ],
        "summary": "Read SCIM directory binding (admin only)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScimDirectory"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "upsertSCIM",
        "tags": [
          "scim"
        ],
        "summary": "Bind a WorkOS Directory and rotate the webhook secret",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertScimDirectoryInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScimDirectory"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteSCIM",
        "tags": [
          "scim"
        ],
        "summary": "Remove the SCIM binding",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/scim/enabled": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "patch": {
        "operationId": "setSCIMEnabled",
        "tags": [
          "scim"
        ],
        "summary": "Toggle the enabled flag without rotating the webhook secret",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/scim/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listSCIMUsers",
        "tags": [
          "scim"
        ],
        "summary": "List directory users + their Elido user link",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ScimDirectoryUser"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/compliance": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getWorkspaceCompliance",
        "tags": [
          "compliance"
        ],
        "summary": "Read the workspace's compliance posture",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceCompliance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "updateWorkspaceCompliance",
        "tags": [
          "compliance"
        ],
        "summary": "Update mode and / or audit retention",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkspaceComplianceInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceCompliance"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/compliance/evidence": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getComplianceEvidence",
        "tags": [
          "compliance"
        ],
        "summary": "SOC 2 / HIPAA evidence snapshot — JSON",
        "description": "Returns a point-in-time snapshot of the workspace's posture\n(mode + retention), access controls (members per role, custom\nroles, SSO/SCIM bound, IP allowlist, API keys), audit-log\nvolume over the trailing 30 / 90 days, and integration\nbindings. Designed to be dropped into a Vanta / Drata-style\nevidence pack or attached to a security questionnaire as\nmachine-readable proof of state on a given date.\n",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvidenceSnapshot"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/compliance/evidence.zip": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "getComplianceEvidenceBundle",
        "tags": [
          "compliance"
        ],
        "summary": "SOC 2 / HIPAA evidence bundle — downloadable ZIP",
        "description": "Streams a ZIP archive containing `evidence.json`, the trailing\n90 days of audit events as CSV, current membership as CSV, the\nIP allowlist as CSV, and a README mapping each file back to the\nSOC 2 control it covers.\n",
        "responses": {
          "200": {
            "description": "ZIP archive",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/cta": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listCtaOverlays",
        "tags": [
          "cta"
        ],
        "summary": "List CTA overlays for the workspace",
        "responses": {
          "200": {
            "description": "CTA overlay list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CtaOverlay"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createCtaOverlay",
        "tags": [
          "cta"
        ],
        "summary": "Create a CTA overlay",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CtaOverlayCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CtaOverlay"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/cta/{cta_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "cta_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "operationId": "getCtaOverlay",
        "tags": [
          "cta"
        ],
        "summary": "Get a single CTA overlay",
        "responses": {
          "200": {
            "description": "CTA overlay",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CtaOverlay"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateCtaOverlay",
        "tags": [
          "cta"
        ],
        "summary": "Update a CTA overlay",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CtaOverlayUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CtaOverlay"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteCtaOverlay",
        "tags": [
          "cta"
        ],
        "summary": "Delete a CTA overlay",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/cta/{cta_id}/stats": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "cta_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "operationId": "getCtaOverlayStats",
        "tags": [
          "cta"
        ],
        "summary": "Get impression/click stats for a CTA overlay",
        "responses": {
          "200": {
            "description": "Stats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cta_overlay_id": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "impressions": {
                      "type": "integer",
                      "format": "int64"
                    },
                    "clicks": {
                      "type": "integer",
                      "format": "int64"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/scim/webhook": {
      "post": {
        "operationId": "scimWebhook",
        "tags": [
          "scim"
        ],
        "summary": "WorkOS Directory Sync webhook (signature-verified, public)",
        "description": "Verifies the `WorkOS-Signature` header (`t=<ts>,v1=<hmac_hex>`) using\nthe `webhook_secret` configured on the SCIM record. Routes\n`dsync.user.{created,updated,deleted}` events to provisioning.\n",
        "security": [],
        "parameters": [
          {
            "name": "WorkOS-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "WorkOS event envelope"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Accepted"
          },
          "401": {
            "description": "Bad signature or unknown directory_id"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/scheduled-reports": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listScheduledReports",
        "tags": [
          "reports"
        ],
        "summary": "List scheduled email reports for the workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ScheduledReport"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createScheduledReport",
        "tags": [
          "reports"
        ],
        "summary": "Create a scheduled email report",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScheduledReportInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledReport"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/scheduled-reports/{report_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "report_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "patch": {
        "operationId": "updateScheduledReport",
        "tags": [
          "reports"
        ],
        "summary": "Update a scheduled report (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateScheduledReportInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduledReport"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteScheduledReport",
        "tags": [
          "reports"
        ],
        "summary": "Delete a scheduled report (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/analytics-export-jobs": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "post": {
        "operationId": "createAnalyticsExportJob",
        "tags": [
          "reports"
        ],
        "summary": "Enqueue an async CSV export job (Phase 10.B.1)",
        "description": "Triggers an async CSV export of the workspace's clicks. The\nnotification worker streams ClickHouse → MinIO and emails the\ndownload URL to the requesting user when complete. Response\ncarries the job id; poll the dashboard's reports page or\nwatch the email inbox.\n",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAnalyticsExportJobInput"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted; job queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsExportJob"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/broken-links": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listBrokenLinks",
        "tags": [
          "reports"
        ],
        "summary": "List links with non-2xx destinations from the latest scan (Phase 10.D)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BrokenLink"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/funnel-definitions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "get": {
        "operationId": "listFunnelDefinitions",
        "tags": [
          "analytics"
        ],
        "summary": "List saved funnel definitions for the workspace",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "items"
                  ],
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FunnelDefinition"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createFunnelDefinition",
        "tags": [
          "analytics"
        ],
        "summary": "Save a funnel definition for re-use",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFunnelDefinitionInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelDefinition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/funnel-definitions/{definition_id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        },
        {
          "name": "definition_id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "delete": {
        "operationId": "deleteFunnelDefinition",
        "tags": [
          "analytics"
        ],
        "summary": "Delete a saved funnel definition (admin+)",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/analytics/workspaces/{workspace_id}/funnel-run": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "post": {
        "operationId": "runFunnel",
        "tags": [
          "analytics"
        ],
        "summary": "Execute a multi-step funnel against the workspace's clicks",
        "description": "Phase 10.C — multi-step click → conversion funnel. Steps are\ndefined as `{kind: \"click\" | \"conversion\", link_id?, event_name?,\ntime_window_seconds}`. Returns per-step visitor counts, drop-off\npercentages, and the attribution-model interpretation\n(first/last/linear touch).\n",
        "security": [
          {
            "internalToken": []
          },
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RunFunnelInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/workspaces/{workspace_id}/links/suggest-slug": {
      "parameters": [
        {
          "$ref": "#/components/parameters/WorkspaceID"
        }
      ],
      "post": {
        "operationId": "suggestSlug",
        "tags": [
          "links"
        ],
        "summary": "Suggest 3–5 slug candidates via Anthropic Claude Haiku 4.5",
        "description": "Phase 12.E.1 (ADR-0032). Calls Anthropic on the server with the\ndestination URL + optional metadata-fetcher enrichment + tags\nand returns 3–5 candidate slugs. 503 when `ANTHROPIC_API_KEY`\nis unset (the dashboard hides the chip-row in that case).\nPer-workspace rate-limit: 10/minute, burst 5.\n",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SuggestSlugInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuggestSlugResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "422": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "description": "Rate-limit exceeded (10/min/workspace)"
          },
          "503": {
            "description": "AI not configured or upstream error"
          }
        }
      }
    },
    "/v1/qr/gs1": {
      "post": {
        "operationId": "generateGS1QR",
        "tags": [
          "qr"
        ],
        "summary": "Generate a GS1 Digital Link QR code (PNG/SVG)",
        "description": "Phase 12.E.3. Encodes a GS1 Digital Link URI built from the\nprovided GTIN (+ optional batch/lot/serial/expiration) under\nthe workspace's primary domain. Output is the same shape as\n`/v1/qr/generate`.\n",
        "security": [
          {
            "kratosSession": []
          },
          {
            "devUser": []
          },
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateGS1QRInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PNG / SVG QR payload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GenerateQRResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "kratosSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "ory_kratos_session",
        "description": "Ory Kratos session cookie (or Authorization Bearer token)"
      },
      "devUser": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Dev-User-ID",
        "description": "Dev-only bypass — user ID as int64 (ENV=development only)"
      },
      "internalToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "Service-to-service internal token (analytics-api)"
      },
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Per-workspace API key issued in the dashboard (Settings → API Keys).\nSent as `Authorization: Bearer elido_…`. The key resolves to its\nowning workspace; endpoints under `/v1/workspaces/{workspace_id}/…`\nreturn 403 if the path's `workspace_id` doesn't match the key's\nscope.\n"
      },
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth2 authorization-code + PKCE via Ory Hydra. Access tokens are\nbearer-authorised at api-core and scoped to one or more of the\napplication scopes below. Refresh tokens are issued only when the\nclient requests `offline_access`.\n",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://hydra.elido.app/oauth2/auth",
            "tokenUrl": "https://hydra.elido.app/oauth2/token",
            "refreshUrl": "https://hydra.elido.app/oauth2/token",
            "scopes": {
              "elido.links": "Read + write short links in the user's workspaces.",
              "elido.workspaces": "Read workspace metadata + memberships.",
              "offline_access": "Issue a refresh token alongside the access token."
            }
          }
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional client-generated key (UUID v4 recommended). When set on a\nPOST/PUT/PATCH the server dedupes retries within 24h. Same key with\na different request body returns 422 `idempotency_key_mismatch`.\n",
        "schema": {
          "type": "string",
          "maxLength": 255
        }
      },
      "WorkspaceID": {
        "name": "workspace_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "format": "int64"
        }
      },
      "UserID": {
        "name": "user_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "format": "int64"
        }
      },
      "CampaignID": {
        "name": "campaign_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "format": "int64"
        }
      },
      "BioID": {
        "name": "bio_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "integer",
          "format": "int64"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Not authenticated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient role",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Conflict": {
        "description": "Unique constraint violation",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string"
          }
        }
      },
      "PlanTier": {
        "type": "string",
        "enum": [
          "free",
          "paid",
          "business"
        ]
      },
      "LinkStatus": {
        "type": "string",
        "enum": [
          "active",
          "disabled"
        ]
      },
      "WorkspaceRole": {
        "type": "string",
        "enum": [
          "owner",
          "admin",
          "editor",
          "viewer"
        ]
      },
      "User": {
        "type": "object",
        "required": [
          "id",
          "kratos_identity_id",
          "email",
          "full_name",
          "created_at",
          "updated_at",
          "timezone"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "kratos_identity_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "timezone": {
            "type": "string"
          },
          "onboarding_completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "default": "UTC"
          }
        }
      },
      "CreateUserInput": {
        "type": "object",
        "required": [
          "kratos_identity_id",
          "email"
        ],
        "properties": {
          "kratos_identity_id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "full_name": {
            "type": "string"
          }
        }
      },
      "Workspace": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "name",
          "plan_tier",
          "created_at",
          "updated_at",
          "deleted_at",
          "default_timezone"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "plan_tier": {
            "$ref": "#/components/schemas/PlanTier"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "default_timezone": {
            "type": "string",
            "default": "UTC"
          }
        }
      },
      "WorkspaceWithRole": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Workspace"
          },
          {
            "type": "object",
            "required": [
              "role"
            ],
            "properties": {
              "role": {
                "$ref": "#/components/schemas/WorkspaceRole"
              },
              "branding_primary_color": {
                "type": "string",
                "nullable": true,
                "description": "Workspace primary colour (hex or oklch) when branding is enabled, null otherwise."
              },
              "branding_logo_url": {
                "type": "string",
                "nullable": true,
                "description": "Workspace logo URL when branding is enabled and the logo is hosted (not a data URL), null otherwise."
              },
              "branding_brand_name": {
                "type": "string",
                "nullable": true,
                "description": "Display name override when branding is enabled, null otherwise."
              }
            }
          }
        ]
      },
      "CreateWorkspaceInput": {
        "type": "object",
        "required": [
          "slug",
          "name"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "plan_tier": {
            "$ref": "#/components/schemas/PlanTier",
            "default": "free"
          }
        }
      },
      "UpdateWorkspaceInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string",
            "minLength": 1
          },
          "default_timezone": {
            "type": "string"
          }
        }
      },
      "WorkspaceMember": {
        "type": "object",
        "required": [
          "workspace_id",
          "user_id",
          "role",
          "created_at",
          "email",
          "full_name"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "user_id": {
            "type": "integer",
            "format": "int64"
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "custom_role_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "When set, the member's effective permissions come from the\nreferenced custom role rather than the built-in role preset.\n"
          },
          "custom_role_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the custom role; null if unset."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "WorkspaceMemberBasic": {
        "type": "object",
        "required": [
          "workspace_id",
          "user_id",
          "role",
          "created_at"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "user_id": {
            "type": "integer",
            "format": "int64"
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AddMemberInput": {
        "type": "object",
        "required": [
          "user_id",
          "role"
        ],
        "properties": {
          "user_id": {
            "type": "integer",
            "format": "int64"
          },
          "role": {
            "$ref": "#/components/schemas/WorkspaceRole"
          }
        }
      },
      "Link": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "domain_id",
          "slug",
          "destination_url",
          "title",
          "tags",
          "status",
          "expires_at",
          "created_by_user_id",
          "created_at",
          "updated_at",
          "deleted_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "domain_id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string"
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "$ref": "#/components/schemas/LinkStatus"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_by_user_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "deleted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "redirect_status": {
            "type": "integer",
            "format": "int32",
            "enum": [
              301,
              302,
              307
            ]
          },
          "max_clicks": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "minimum": 1,
            "description": "Per-link click cap; null = no cap."
          },
          "folder_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Folder this link belongs to; null = unfiled."
          },
          "rotation_mode": {
            "type": "string",
            "enum": [
              "weighted",
              "round_robin"
            ],
            "description": "Variant-selection strategy. Defaults to \"weighted\"."
          },
          "show_splash": {
            "type": "boolean",
            "description": "Opt the link into the conversion-tracking splash interstitial.\nWhen true, edge serves an HTML page that fires the workspace's\nMeta / Google / LinkedIn / TikTok pixels and JS-redirects to\nthe destination.\n"
          },
          "risk_score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100,
            "description": "url-scanner composite risk score (0=safe, 100=definitely\nmalicious). The latest scan's score is mirrored onto the link.\n"
          },
          "abuse_status": {
            "type": "string",
            "enum": [
              "clean",
              "suspect",
              "blocked"
            ],
            "description": "Anti-abuse classification. The edge serves HTTP 451 when this\nis \"blocked\"; \"suspect\" links continue to redirect but appear\nin the workspace moderation queue.\n"
          },
          "scanned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When risk_score / abuse_status were last refreshed by url-scanner."
          }
        }
      },
      "LinkSafetyScan": {
        "type": "object",
        "description": "One row of a link's safety-scan history.",
        "required": [
          "id",
          "link_id",
          "workspace_id",
          "source",
          "verdict",
          "score",
          "kind",
          "scanned_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "link_id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "source": {
            "type": "string",
            "description": "Which feed produced this verdict; usually 'composite'."
          },
          "verdict": {
            "type": "string",
            "enum": [
              "clean",
              "suspect",
              "blocked",
              "unknown"
            ]
          },
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "threats": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "signals": {
            "type": "object",
            "additionalProperties": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "create",
              "update",
              "rescan"
            ]
          },
          "scanned_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SuspectLinkRow": {
        "type": "object",
        "description": "One row of the workspace moderation queue.",
        "required": [
          "id",
          "slug",
          "destination_url",
          "risk_score",
          "abuse_status",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string"
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "risk_score": {
            "type": "integer"
          },
          "abuse_status": {
            "type": "string",
            "enum": [
              "clean",
              "suspect",
              "blocked"
            ]
          },
          "scanned_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WorkspacePixels": {
        "type": "object",
        "description": "Workspace-level conversion-tracking pixel IDs. Each platform is\nnullable; null = the workspace hasn't configured that platform.\n",
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "meta_pixel_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "google_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "linkedin_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "tiktok_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpsertWorkspacePixelsInput": {
        "type": "object",
        "properties": {
          "meta_pixel_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "google_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "linkedin_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "tiktok_id": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Folder": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "color",
          "link_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string"
          },
          "link_count": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateFolderInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "color": {
            "type": "string"
          }
        }
      },
      "UpdateFolderInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "color": {
            "type": "string"
          }
        }
      },
      "Tag": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "color",
          "link_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string"
          },
          "link_count": {
            "type": "integer",
            "format": "int64"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateTagInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "color": {
            "type": "string"
          }
        }
      },
      "UpdateTagInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "color": {
            "type": "string"
          }
        }
      },
      "PaginatedLinks": {
        "type": "object",
        "required": [
          "items",
          "limit"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Link"
            }
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Opaque base64-encoded cursor for the next page; null when no more rows."
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "description": "Deprecated. Returned only when the request used `?offset=`."
          }
        }
      },
      "CreateLinkInput": {
        "type": "object",
        "required": [
          "domain_id",
          "destination_url"
        ],
        "properties": {
          "domain_id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string",
            "description": "Auto-generated via Skip32+base62 if omitted"
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "redirect_status": {
            "type": "integer",
            "format": "int32",
            "enum": [
              301,
              302,
              307
            ],
            "description": "HTTP redirect status the edge returns. Defaults to 302 when omitted."
          },
          "max_clicks": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "description": "Per-link click cap; omit for no cap."
          },
          "folder_id": {
            "type": "integer",
            "format": "int64",
            "description": "Folder ID to file this link under; omit for unfiled."
          },
          "rotation_mode": {
            "type": "string",
            "enum": [
              "weighted",
              "round_robin"
            ],
            "description": "Variant-selection strategy. Defaults to \"weighted\"."
          },
          "show_splash": {
            "type": "boolean",
            "description": "Opt into the conversion-tracking splash interstitial."
          }
        }
      },
      "UpdateLinkInput": {
        "type": "object",
        "description": "All fields optional; omitted fields are unchanged.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "status": {
            "$ref": "#/components/schemas/LinkStatus"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "password": {
            "type": "string",
            "description": "Tri-state. Omit to leave unchanged, \"\" to clear, anything else\nto set/rotate. Server hashes with Argon2id; plaintext is never\nstored.\n"
          },
          "targeting_rules": {
            "type": "array",
            "description": "Geo / device / browser routing rules. The first matching rule\nwins; non-matches fall through to the link's destination_url\n(or A/B variant rotation if any are active).\n",
            "items": {
              "$ref": "#/components/schemas/TargetingRule"
            }
          },
          "redirect_status": {
            "type": "integer",
            "format": "int32",
            "enum": [
              301,
              302,
              307
            ]
          },
          "max_clicks": {
            "type": "integer",
            "format": "int32",
            "minimum": 0,
            "description": "Per-link click cap. Send 0 to clear a previously-set cap;\nanything > 0 sets the new cap.\n"
          },
          "folder_id": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Move into folder. Send 0 to detach from any folder; > 0 to set.\n"
          },
          "rotation_mode": {
            "type": "string",
            "enum": [
              "weighted",
              "round_robin"
            ],
            "description": "Switch variant-selection strategy."
          },
          "show_splash": {
            "type": "boolean",
            "description": "Opt into / out of the conversion-tracking splash interstitial."
          }
        }
      },
      "TargetingRule": {
        "type": "object",
        "required": [
          "destination_url",
          "match"
        ],
        "properties": {
          "match": {
            "type": "object",
            "description": "All listed conditions must hold for the rule to fire. Empty\nfields / lists are wildcards. Legacy single-value fields\n(country / device / browser) are kept for backwards\ncompatibility; new rules should use the multi-value\ncollections.\n",
            "properties": {
              "country": {
                "type": "string",
                "description": "Legacy. ISO-3166-1 alpha-2."
              },
              "device": {
                "type": "string",
                "enum": [
                  "mobile",
                  "tablet",
                  "desktop"
                ],
                "description": "Legacy single value."
              },
              "browser": {
                "type": "string",
                "description": "Legacy. chrome / safari / firefox / edge."
              },
              "countries": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "ANY-OF, case-insensitive ISO-3166-1 alpha-2."
              },
              "devices": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "mobile",
                    "tablet",
                    "desktop"
                  ]
                }
              },
              "browsers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "os": {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "ios",
                    "android",
                    "macos",
                    "windows",
                    "linux"
                  ]
                }
              },
              "languages": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Primary language tag (en / uk / ru / …)."
              },
              "user_agent_regex": {
                "type": "string",
                "maxLength": 256,
                "description": "Go regex compiled at edge. Capped to 256 chars; invalid\npatterns reject the rule on save.\n"
              },
              "time_start": {
                "type": "string",
                "pattern": "^[0-2][0-9]:[0-5][0-9]$",
                "description": "HH:MM 24h, inclusive."
              },
              "time_end": {
                "type": "string",
                "pattern": "^[0-2][0-9]:[0-5][0-9]$",
                "description": "HH:MM 24h, inclusive. Wraparound (22:00→02:00) supported."
              },
              "timezone": {
                "type": "string",
                "description": "IANA TZ name (default UTC)."
              },
              "days_of_week": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 0,
                  "maximum": 6
                },
                "description": "0=Sunday … 6=Saturday. Empty = any day."
              }
            }
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "label": {
            "type": "string"
          }
        }
      },
      "TimeseriesPoint": {
        "type": "object",
        "required": [
          "ts",
          "count"
        ],
        "properties": {
          "ts": {
            "type": "string",
            "format": "date-time"
          },
          "count": {
            "type": "integer",
            "format": "uint64"
          }
        }
      },
      "TopLink": {
        "type": "object",
        "required": [
          "link_id",
          "slug",
          "count"
        ],
        "properties": {
          "link_id": {
            "type": "integer",
            "format": "uint64"
          },
          "slug": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "format": "uint64"
          }
        }
      },
      "FunnelStep": {
        "type": "object",
        "required": [
          "window",
          "unique_visitors",
          "total_clicks"
        ],
        "properties": {
          "window": {
            "type": "string",
            "enum": [
              "total",
              "1h",
              "24h",
              "7d"
            ]
          },
          "unique_visitors": {
            "type": "integer",
            "format": "uint64"
          },
          "total_clicks": {
            "type": "integer",
            "format": "uint64"
          }
        }
      },
      "CohortBucket": {
        "type": "object",
        "required": [
          "cohort_week",
          "week_offset",
          "visitors"
        ],
        "properties": {
          "cohort_week": {
            "type": "string",
            "format": "date",
            "description": "ISO week start (Monday, YYYY-MM-DD)."
          },
          "week_offset": {
            "type": "integer",
            "format": "uint64",
            "description": "0-based weeks since the cohort's acquisition week."
          },
          "visitors": {
            "type": "integer",
            "format": "uint64"
          }
        }
      },
      "EngagementSummary": {
        "type": "object",
        "required": [
          "total_clicks",
          "unique_visitors",
          "returning_visitors",
          "avg_clicks_per_visitor",
          "bounce_rate"
        ],
        "properties": {
          "total_clicks": {
            "type": "integer",
            "format": "uint64"
          },
          "unique_visitors": {
            "type": "integer",
            "format": "uint64"
          },
          "returning_visitors": {
            "type": "integer",
            "format": "uint64"
          },
          "avg_clicks_per_visitor": {
            "type": "number",
            "format": "double"
          },
          "bounce_rate": {
            "type": "number",
            "format": "double",
            "description": "Fraction of unique visitors that clicked exactly once (0..1)."
          }
        }
      },
      "HeatmapCell": {
        "type": "object",
        "required": [
          "hour",
          "dow",
          "count"
        ],
        "properties": {
          "hour": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23,
            "description": "Hour of day (UTC)"
          },
          "dow": {
            "type": "integer",
            "minimum": 1,
            "maximum": 7,
            "description": "Day of week (1=Mon, 7=Sun)"
          },
          "count": {
            "type": "integer",
            "format": "uint64"
          }
        }
      },
      "LTVCohort": {
        "type": "object",
        "required": [
          "cohort_week",
          "links_acquired",
          "visitors",
          "clicks_total",
          "revenue_cents",
          "currency",
          "clicks_per_link",
          "revenue_per_link_cents",
          "revenue_per_visitor_cents"
        ],
        "properties": {
          "cohort_week": {
            "type": "string",
            "format": "date",
            "description": "ISO week of first click on the cohort's links."
          },
          "links_acquired": {
            "type": "integer",
            "format": "uint64",
            "description": "Distinct links whose first click fell in this week."
          },
          "visitors": {
            "type": "integer",
            "format": "uint64",
            "description": "Unique visitors (by IP) who ever clicked a cohort link."
          },
          "clicks_total": {
            "type": "integer",
            "format": "uint64",
            "description": "Lifetime click sum across the cohort's links."
          },
          "revenue_cents": {
            "type": "integer",
            "format": "int64",
            "description": "Lifetime revenue in cents, attributed via link_id from Stripe / Shopify conversions."
          },
          "currency": {
            "type": "string",
            "description": "3-letter ISO currency code revenue figures are denominated in."
          },
          "clicks_per_link": {
            "type": "number",
            "format": "double"
          },
          "revenue_per_link_cents": {
            "type": "number",
            "format": "double"
          },
          "revenue_per_visitor_cents": {
            "type": "number",
            "format": "double"
          }
        }
      },
      "Campaign": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "archived",
          "link_count",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "utm_source": {
            "type": [
              "string",
              "null"
            ]
          },
          "utm_medium": {
            "type": [
              "string",
              "null"
            ]
          },
          "utm_campaign": {
            "type": [
              "string",
              "null"
            ]
          },
          "utm_term": {
            "type": [
              "string",
              "null"
            ]
          },
          "utm_content": {
            "type": [
              "string",
              "null"
            ]
          },
          "start_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "end_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "archived": {
            "type": "boolean"
          },
          "link_count": {
            "type": "integer",
            "format": "int32"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCampaignInput": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string"
          },
          "utm_source": {
            "type": "string"
          },
          "utm_medium": {
            "type": "string"
          },
          "utm_campaign": {
            "type": "string"
          },
          "utm_term": {
            "type": "string"
          },
          "utm_content": {
            "type": "string"
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "UpdateCampaignInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "description": {
            "type": "string"
          },
          "utm_source": {
            "type": "string"
          },
          "utm_medium": {
            "type": "string"
          },
          "utm_campaign": {
            "type": "string"
          },
          "utm_term": {
            "type": "string"
          },
          "utm_content": {
            "type": "string"
          },
          "start_date": {
            "type": "string",
            "format": "date"
          },
          "end_date": {
            "type": "string",
            "format": "date"
          },
          "archived": {
            "type": "boolean"
          }
        }
      },
      "CampaignLinkIds": {
        "type": "object",
        "required": [
          "link_ids"
        ],
        "properties": {
          "link_ids": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "integer",
              "format": "int64"
            }
          }
        }
      },
      "BioTheme": {
        "type": "object",
        "description": "Visual config — every field is optional and falls back to the\nrenderer's defaults (dark slate background, indigo buttons).\n",
        "properties": {
          "bg_color": {
            "type": "string"
          },
          "text_color": {
            "type": "string"
          },
          "button_style": {
            "type": "string",
            "enum": [
              "solid",
              "outline",
              "soft"
            ]
          },
          "button_color": {
            "type": "string"
          },
          "button_radius": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "BioPage": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "username",
          "display_name",
          "is_published",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "username": {
            "type": "string",
            "minLength": 3,
            "maxLength": 32,
            "description": "3–32 lowercase letters, digits, hyphens, or underscores. Globally unique."
          },
          "display_name": {
            "type": "string"
          },
          "bio": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "theme": {
            "$ref": "#/components/schemas/BioTheme"
          },
          "is_published": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateBioPageInput": {
        "type": "object",
        "required": [
          "username",
          "display_name"
        ],
        "properties": {
          "username": {
            "type": "string",
            "minLength": 3,
            "maxLength": 32
          },
          "display_name": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          },
          "avatar_url": {
            "type": "string",
            "format": "uri"
          },
          "is_published": {
            "type": "boolean",
            "default": false
          },
          "theme": {
            "$ref": "#/components/schemas/BioTheme"
          }
        }
      },
      "UpdateBioPageInput": {
        "type": "object",
        "properties": {
          "display_name": {
            "type": "string"
          },
          "bio": {
            "type": "string"
          },
          "avatar_url": {
            "type": "string",
            "format": "uri"
          },
          "is_published": {
            "type": "boolean"
          },
          "theme": {
            "$ref": "#/components/schemas/BioTheme"
          }
        }
      },
      "BioLink": {
        "type": "object",
        "required": [
          "id",
          "bio_page_id",
          "title",
          "url",
          "sort_order",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "bio_page_id": {
            "type": "integer",
            "format": "int64"
          },
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "icon": {
            "type": [
              "string",
              "null"
            ],
            "description": "Lucide icon name"
          },
          "sort_order": {
            "type": "integer",
            "format": "int32"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateBioLinkInput": {
        "type": "object",
        "required": [
          "title",
          "url"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "icon": {
            "type": "string"
          },
          "sort_order": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "UpdateBioLinkInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "icon": {
            "type": "string"
          },
          "sort_order": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "BioHeatmapEntry": {
        "type": "object",
        "required": [
          "bio_link_id",
          "clicks"
        ],
        "properties": {
          "bio_link_id": {
            "type": "integer",
            "format": "int64"
          },
          "clicks": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "PublicBioPage": {
        "type": "object",
        "description": "Public render payload — strips workspace and admin fields.",
        "required": [
          "username",
          "display_name",
          "links"
        ],
        "properties": {
          "username": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "bio": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "theme": {
            "$ref": "#/components/schemas/BioTheme"
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "title",
                "url",
                "sort_order"
              ],
              "properties": {
                "id": {
                  "type": "integer",
                  "format": "int64"
                },
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "icon": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "sort_order": {
                  "type": "integer",
                  "format": "int32"
                }
              }
            }
          }
        }
      },
      "DomainStatus": {
        "type": "string",
        "enum": [
          "pending",
          "verified",
          "active",
          "failed"
        ]
      },
      "Domain": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "hostname",
          "status",
          "is_wildcard",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "hostname": {
            "type": "string"
          },
          "verify_token": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/DomainStatus"
          },
          "is_wildcard": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "verified_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "fail_reason": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AppLinksInput": {
        "type": "object",
        "description": "Either field may be omitted. Submitted JSON is served verbatim at the\ndomain's well-known path; Elido does not validate it beyond JSON\nshape.\n",
        "properties": {
          "apple_app_site_association": {
            "type": "object",
            "description": "Served at /.well-known/apple-app-site-association"
          },
          "android_assetlinks": {
            "type": "array",
            "description": "Served at /.well-known/assetlinks.json",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "GenerateQRInput": {
        "type": "object",
        "required": [
          "content"
        ],
        "properties": {
          "content": {
            "type": "string",
            "description": "URL or text to encode"
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "minimum": 256,
            "maximum": 2048,
            "default": 512
          },
          "error_correction": {
            "type": "string",
            "enum": [
              "L",
              "M",
              "Q",
              "H"
            ],
            "default": "M"
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "png",
                "svg"
              ]
            },
            "default": [
              "png"
            ]
          },
          "foreground": {
            "type": "string",
            "description": "Hex, e.g. #0f172a"
          },
          "background": {
            "type": "string",
            "description": "Hex, e.g. #ffffff"
          },
          "module_style": {
            "type": "string",
            "enum": [
              "square",
              "dot",
              "rounded"
            ]
          },
          "eye_style": {
            "type": "string",
            "enum": [
              "square",
              "rounded",
              "leaf"
            ]
          },
          "eye_pupil_style": {
            "type": "string",
            "enum": [
              "square",
              "dot"
            ]
          },
          "eye_border_color": {
            "type": "string"
          },
          "eye_pupil_color": {
            "type": "string"
          },
          "logo_data_url": {
            "type": "string",
            "description": "data:image/… URL or https:// URL fetched by the browser"
          },
          "logo_size_pct": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 1,
            "default": 0.18
          },
          "logo_pad": {
            "type": "boolean",
            "default": true
          },
          "frame_enabled": {
            "type": "boolean",
            "default": false
          },
          "frame_color": {
            "type": "string"
          },
          "frame_label": {
            "type": "string",
            "maxLength": 32
          },
          "frame_label_color": {
            "type": "string"
          }
        }
      },
      "GenerateQRMultiResponse": {
        "type": "object",
        "description": "Returned when the request asks for both png and svg.",
        "properties": {
          "png": {
            "type": "string",
            "description": "Base64-encoded PNG bytes"
          },
          "svg": {
            "type": "string",
            "description": "Inline SVG document"
          }
        }
      },
      "ConversionPlatform": {
        "type": "string",
        "enum": [
          "stripe",
          "shopify"
        ]
      },
      "Conversion": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "platform",
          "external_id",
          "revenue_cents",
          "currency",
          "converted_at",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "platform": {
            "$ref": "#/components/schemas/ConversionPlatform"
          },
          "external_id": {
            "type": "string"
          },
          "link_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "campaign_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "revenue_cents": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "customer_email": {
            "type": [
              "string",
              "null"
            ],
            "format": "email"
          },
          "converted_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginatedConversions": {
        "type": "object",
        "required": [
          "conversions",
          "limit",
          "offset"
        ],
        "properties": {
          "conversions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Conversion"
            }
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "ConversionSummary": {
        "type": "object",
        "required": [
          "total_conversions",
          "total_revenue_cents"
        ],
        "properties": {
          "total_conversions": {
            "type": "integer",
            "format": "int64"
          },
          "total_revenue_cents": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "Pixels": {
        "type": "object",
        "description": "Webhook secrets are never returned — only the boolean flags\n`stripe_webhook_set` / `shopify_webhook_set`. Rotate by sending\na new value on PUT.\n",
        "required": [
          "workspace_id",
          "stripe_webhook_set",
          "shopify_webhook_set",
          "updated_at"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "meta_pixel_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "google_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "linkedin_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "tiktok_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "stripe_webhook_set": {
            "type": "boolean"
          },
          "shopify_webhook_set": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpsertPixelsInput": {
        "type": "object",
        "description": "Empty strings clear the corresponding value; omitted fields stay\nunchanged.\n",
        "properties": {
          "meta_pixel_id": {
            "type": "string"
          },
          "google_id": {
            "type": "string"
          },
          "linkedin_id": {
            "type": "string"
          },
          "tiktok_id": {
            "type": "string"
          },
          "stripe_webhook_secret": {
            "type": "string"
          },
          "shopify_webhook_secret": {
            "type": "string"
          }
        }
      },
      "Branding": {
        "type": "object",
        "required": [
          "workspace_id",
          "enabled",
          "configured"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "brand_name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "primary_color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hex or oklch(...)"
          },
          "email_from_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "portal_hostname": {
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "configured": {
            "type": "boolean",
            "description": "True once any field has been set"
          }
        }
      },
      "UpsertBrandingInput": {
        "type": "object",
        "properties": {
          "brand_name": {
            "type": "string",
            "maxLength": 80
          },
          "logo_url": {
            "type": "string",
            "format": "uri"
          },
          "primary_color": {
            "type": "string"
          },
          "email_from_name": {
            "type": "string"
          },
          "portal_hostname": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "SSOConfig": {
        "type": "object",
        "required": [
          "workspace_id",
          "organization_id",
          "connection_id",
          "domain",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "organization_id": {
            "type": "string",
            "description": "WorkOS Organization ID, prefixed org_"
          },
          "connection_id": {
            "type": "string",
            "description": "WorkOS Connection ID, prefixed conn_"
          },
          "domain": {
            "type": "string",
            "description": "Email domain that maps to this connection"
          },
          "enabled": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpsertSSOInput": {
        "type": "object",
        "required": [
          "organization_id",
          "connection_id",
          "domain"
        ],
        "properties": {
          "organization_id": {
            "type": "string"
          },
          "connection_id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "ScimDirectory": {
        "type": "object",
        "required": [
          "workspace_id",
          "directory_id",
          "organization_id",
          "default_role",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "directory_id": {
            "type": "string",
            "description": "WorkOS Directory ID"
          },
          "organization_id": {
            "type": "string"
          },
          "default_role": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpsertScimDirectoryInput": {
        "type": "object",
        "required": [
          "directory_id",
          "webhook_secret"
        ],
        "properties": {
          "directory_id": {
            "type": "string"
          },
          "organization_id": {
            "type": "string"
          },
          "webhook_secret": {
            "type": "string",
            "description": "HMAC secret for the WorkOS-Signature header"
          },
          "default_role": {
            "type": "string",
            "default": "viewer"
          }
        }
      },
      "SetScimEnabledInput": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "ScimDirectoryUser": {
        "type": "object",
        "required": [
          "id",
          "directory_user_id",
          "email",
          "first_name",
          "last_name",
          "state",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "directory_user_id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "state": {
            "type": "string",
            "description": "WorkOS state — typically 'active' or 'suspended'"
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "Null until the user finishes onboarding (sets a password or\nsigns in via SSO).\n"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "IPRule": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "cidr",
          "label",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "cidr": {
            "type": "string",
            "description": "IPv4 / IPv6 CIDR or single address"
          },
          "label": {
            "type": "string",
            "description": "Free-text label, surfaced in the dashboard"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateIPRuleInput": {
        "type": "object",
        "required": [
          "cidr"
        ],
        "properties": {
          "cidr": {
            "type": "string",
            "description": "IPv4 / IPv6 CIDR or single address"
          },
          "label": {
            "type": "string"
          }
        }
      },
      "SetIPAllowlistEnabledInput": {
        "type": "object",
        "required": [
          "enabled"
        ],
        "properties": {
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "PermissionCategory": {
        "type": "object",
        "required": [
          "name",
          "permissions"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Category key — links / domains / billing / …"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CustomRole": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "description",
          "permissions",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "description": {
            "type": "string"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCustomRoleInput": {
        "type": "object",
        "required": [
          "name",
          "permissions"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "description": {
            "type": "string"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "UpdateCustomRoleInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "description": {
            "type": "string"
          },
          "permissions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CustomRolesListResponse": {
        "type": "object",
        "required": [
          "items",
          "catalog",
          "presets"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomRole"
            }
          },
          "catalog": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PermissionCategory"
            },
            "description": "Permission catalogue, organised by category."
          },
          "presets": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Built-in role → permission-list map, keyed by role\n(`viewer`, `editor`, `admin`, `owner`).\n"
          }
        }
      },
      "UpdateMemberRoleInput": {
        "type": "object",
        "required": [
          "role"
        ],
        "properties": {
          "role": {
            "type": "string",
            "description": "Built-in workspace role — owner / admin / editor / viewer"
          },
          "custom_role_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64",
            "description": "When set, the member's effective permissions are the\nreferenced custom role's permission list, ignoring the\nbuilt-in role preset.\n"
          }
        }
      },
      "MarketplaceDomain": {
        "type": "object",
        "required": [
          "id",
          "hostname",
          "description",
          "category",
          "price_cents",
          "currency",
          "min_tier",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "hostname": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string",
            "description": "Free-text bucket the dashboard groups by."
          },
          "price_cents": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string",
            "description": "3-letter ISO currency code."
          },
          "min_tier": {
            "type": "string",
            "description": "Minimum plan tier required to claim."
          },
          "claimed_by_workspace_id": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "claimed_at": {
            "type": "string",
            "description": "RFC3339 timestamp; empty when unclaimed."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ClaimMarketplaceDomainResponse": {
        "type": "object",
        "required": [
          "marketplace_id",
          "domain_id",
          "hostname",
          "price_cents",
          "currency",
          "claimed_at"
        ],
        "properties": {
          "marketplace_id": {
            "type": "integer",
            "format": "int64"
          },
          "domain_id": {
            "type": "integer",
            "format": "int64"
          },
          "hostname": {
            "type": "string"
          },
          "price_cents": {
            "type": "integer",
            "format": "int64"
          },
          "currency": {
            "type": "string"
          },
          "claimed_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ComplianceMode": {
        "type": "string",
        "enum": [
          "none",
          "gdpr",
          "hipaa",
          "soc2"
        ],
        "description": "Workspace-level compliance posture. Drives audit-event tagging\nand the per-mode default audit retention. See\n`docs/compliance/` for the control matrix per mode.\n"
      },
      "WorkspaceCompliance": {
        "type": "object",
        "required": [
          "workspace_id",
          "mode",
          "ip_allowlist_enabled",
          "default_audit_retention_days"
        ],
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "mode": {
            "$ref": "#/components/schemas/ComplianceMode"
          },
          "audit_retention_days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32",
            "description": "Per-workspace override of the default retention in days.\nWhen omitted / null, the platform default for the active\nmode applies (`default_audit_retention_days`).\n"
          },
          "ip_allowlist_enabled": {
            "type": "boolean"
          },
          "default_audit_retention_days": {
            "type": "integer",
            "format": "int32"
          }
        }
      },
      "UpdateWorkspaceComplianceInput": {
        "type": "object",
        "properties": {
          "mode": {
            "$ref": "#/components/schemas/ComplianceMode"
          },
          "audit_retention_days": {
            "type": "integer",
            "format": "int32",
            "description": "Override the platform default. Use `reset_audit_retention`\nto clear and fall back to the default.\n"
          },
          "reset_audit_retention": {
            "type": "boolean",
            "description": "When true, audit_retention_days is cleared."
          }
        }
      },
      "EvidencePosture": {
        "type": "object",
        "required": [
          "mode",
          "default_audit_retention_days",
          "ip_allowlist_enabled",
          "ip_rules_count"
        ],
        "properties": {
          "mode": {
            "$ref": "#/components/schemas/ComplianceMode"
          },
          "audit_retention_days": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int32"
          },
          "default_audit_retention_days": {
            "type": "integer",
            "format": "int32"
          },
          "ip_allowlist_enabled": {
            "type": "boolean"
          },
          "ip_rules_count": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "EvidenceAccess": {
        "type": "object",
        "required": [
          "members_total",
          "members_by_role",
          "custom_roles_count",
          "pending_invitations",
          "api_keys_active"
        ],
        "properties": {
          "members_total": {
            "type": "integer",
            "format": "int64"
          },
          "members_by_role": {
            "type": "object",
            "additionalProperties": {
              "type": "integer",
              "format": "int64"
            },
            "description": "Count of members per built-in role (`owner`/`admin`/`editor`/`viewer`)."
          },
          "custom_roles_count": {
            "type": "integer",
            "format": "int64"
          },
          "pending_invitations": {
            "type": "integer",
            "format": "int64"
          },
          "api_keys_active": {
            "type": "integer",
            "format": "int64"
          },
          "api_keys_last_created": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "EvidenceAuditing": {
        "type": "object",
        "required": [
          "events_last_30_days",
          "events_last_90_days"
        ],
        "properties": {
          "events_last_30_days": {
            "type": "integer",
            "format": "int64"
          },
          "events_last_90_days": {
            "type": "integer",
            "format": "int64"
          },
          "oldest_retained": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "newest_event": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "EvidenceIntegrations": {
        "type": "object",
        "required": [
          "sso_bound",
          "scim_bound",
          "scim_enabled",
          "baa_signed_count"
        ],
        "properties": {
          "sso_bound": {
            "type": "boolean"
          },
          "scim_bound": {
            "type": "boolean"
          },
          "scim_enabled": {
            "type": "boolean"
          },
          "baa_signed_count": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "EvidenceSnapshot": {
        "type": "object",
        "required": [
          "workspace_id",
          "collected_at",
          "posture",
          "access",
          "auditing",
          "integrations",
          "controls_matrix_url"
        ],
        "description": "Point-in-time evidence snapshot. Maps onto SOC 2 Trust Services\nCriteria CC1.5 / CC6.* / CC7.1; the `controls_matrix_url`\npoints at the human-readable narrative an auditor expects to\naccompany this artefact.\n",
        "properties": {
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "collected_at": {
            "type": "string",
            "format": "date-time"
          },
          "posture": {
            "$ref": "#/components/schemas/EvidencePosture"
          },
          "access": {
            "$ref": "#/components/schemas/EvidenceAccess"
          },
          "auditing": {
            "$ref": "#/components/schemas/EvidenceAuditing"
          },
          "integrations": {
            "$ref": "#/components/schemas/EvidenceIntegrations"
          },
          "controls_matrix_url": {
            "type": "string",
            "format": "uri",
            "description": "Public URL of the SOC 2 control-matrix document."
          }
        }
      },
      "CtaOverlay": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "cta_type",
          "position",
          "bg_color",
          "text_color",
          "button_bg",
          "button_text_color",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "cta_type": {
            "type": "string",
            "enum": [
              "text_button",
              "banner",
              "modal",
              "custom_html"
            ]
          },
          "position": {
            "type": "string",
            "enum": [
              "bottom_bar",
              "top_bar",
              "popup",
              "slide_in"
            ]
          },
          "headline": {
            "type": [
              "string",
              "null"
            ]
          },
          "body_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "button_text": {
            "type": [
              "string",
              "null"
            ]
          },
          "button_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "custom_html": {
            "type": [
              "string",
              "null"
            ]
          },
          "bg_color": {
            "type": "string"
          },
          "text_color": {
            "type": "string"
          },
          "button_bg": {
            "type": "string"
          },
          "button_text_color": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CtaOverlayCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "cta_type": {
            "type": "string",
            "enum": [
              "text_button",
              "banner",
              "modal",
              "custom_html"
            ],
            "default": "text_button"
          },
          "position": {
            "type": "string",
            "enum": [
              "bottom_bar",
              "top_bar",
              "popup",
              "slide_in"
            ],
            "default": "bottom_bar"
          },
          "headline": {
            "type": "string"
          },
          "body_text": {
            "type": "string"
          },
          "button_text": {
            "type": "string"
          },
          "button_url": {
            "type": "string"
          },
          "image_url": {
            "type": "string"
          },
          "custom_html": {
            "type": "string"
          },
          "bg_color": {
            "type": "string",
            "default": "#4f46e5"
          },
          "text_color": {
            "type": "string",
            "default": "#ffffff"
          },
          "button_bg": {
            "type": "string",
            "default": "#ffffff"
          },
          "button_text_color": {
            "type": "string",
            "default": "#4f46e5"
          }
        }
      },
      "CtaOverlayUpdate": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "cta_type": {
            "type": "string",
            "enum": [
              "text_button",
              "banner",
              "modal",
              "custom_html"
            ]
          },
          "position": {
            "type": "string",
            "enum": [
              "bottom_bar",
              "top_bar",
              "popup",
              "slide_in"
            ]
          },
          "headline": {
            "type": "string"
          },
          "body_text": {
            "type": "string"
          },
          "button_text": {
            "type": "string"
          },
          "button_url": {
            "type": "string"
          },
          "image_url": {
            "type": "string"
          },
          "custom_html": {
            "type": "string"
          },
          "bg_color": {
            "type": "string"
          },
          "text_color": {
            "type": "string"
          },
          "button_bg": {
            "type": "string"
          },
          "button_text_color": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "PatchMeInput": {
        "type": "object",
        "description": "Partial update for the current user. All fields optional; only\nprovided fields are applied.\n",
        "properties": {
          "display_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone name (validated server-side via time.LoadLocation)."
          },
          "onboarding_completed": {
            "type": "boolean",
            "description": "Flips users.onboarding_completed_at on or off."
          }
        }
      },
      "RecentClick": {
        "type": "object",
        "required": [
          "link_id",
          "slug",
          "clicked_at"
        ],
        "properties": {
          "link_id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string"
          },
          "clicked_at": {
            "type": "string",
            "format": "date-time"
          },
          "country_code": {
            "type": "string",
            "nullable": true
          },
          "device": {
            "type": "string",
            "nullable": true
          },
          "browser": {
            "type": "string",
            "nullable": true
          },
          "referrer": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ScheduledReport": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "cron",
          "recipients",
          "enabled",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "cron": {
            "type": "string",
            "description": "Standard 5-field cron expression (UTC)."
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "last_run_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateScheduledReportInput": {
        "type": "object",
        "required": [
          "name",
          "cron",
          "recipients"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "cron": {
            "type": "string"
          },
          "recipients": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "type": "string",
              "format": "email"
            }
          }
        }
      },
      "UpdateScheduledReportInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "cron": {
            "type": "string"
          },
          "recipients": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            }
          },
          "enabled": {
            "type": "boolean"
          }
        }
      },
      "AnalyticsExportJob": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "status",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "status": {
            "type": "string",
            "enum": [
              "queued",
              "running",
              "succeeded",
              "failed"
            ]
          },
          "download_url": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CreateAnalyticsExportJobInput": {
        "type": "object",
        "required": [
          "from",
          "to"
        ],
        "properties": {
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          },
          "link_id": {
            "type": "integer",
            "format": "int64",
            "description": "Optional. When set, scopes the export to a single link."
          }
        }
      },
      "BrokenLink": {
        "type": "object",
        "required": [
          "link_id",
          "slug",
          "destination_url",
          "status_code",
          "last_checked_at"
        ],
        "properties": {
          "link_id": {
            "type": "integer",
            "format": "int64"
          },
          "slug": {
            "type": "string"
          },
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "status_code": {
            "type": "integer"
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "last_checked_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FunnelDefinition": {
        "type": "object",
        "required": [
          "id",
          "workspace_id",
          "name",
          "steps",
          "attribution_model",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "workspace_id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelStepDefinition"
            }
          },
          "attribution_model": {
            "type": "string",
            "enum": [
              "first_touch",
              "last_touch",
              "linear"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FunnelStepDefinition": {
        "type": "object",
        "required": [
          "kind",
          "time_window_seconds"
        ],
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "click",
              "conversion"
            ]
          },
          "link_id": {
            "type": "integer",
            "format": "int64",
            "description": "Required when kind=click."
          },
          "event_name": {
            "type": "string",
            "description": "Required when kind=conversion."
          },
          "time_window_seconds": {
            "type": "integer",
            "minimum": 1,
            "description": "Maximum elapsed time from the previous step (1..604800)."
          }
        }
      },
      "CreateFunnelDefinitionInput": {
        "type": "object",
        "required": [
          "name",
          "steps"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "steps": {
            "type": "array",
            "minItems": 1,
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/FunnelStepDefinition"
            }
          },
          "attribution_model": {
            "type": "string",
            "enum": [
              "first_touch",
              "last_touch",
              "linear"
            ],
            "default": "last_touch"
          }
        }
      },
      "RunFunnelInput": {
        "type": "object",
        "required": [
          "steps"
        ],
        "properties": {
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelStepDefinition"
            }
          },
          "attribution_model": {
            "type": "string",
            "enum": [
              "first_touch",
              "last_touch",
              "linear"
            ],
            "default": "last_touch"
          },
          "from": {
            "type": "string",
            "format": "date"
          },
          "to": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "FunnelResult": {
        "type": "object",
        "required": [
          "steps"
        ],
        "properties": {
          "attribution_model": {
            "type": "string"
          },
          "steps": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "position",
                "visitors"
              ],
              "properties": {
                "position": {
                  "type": "integer"
                },
                "visitors": {
                  "type": "integer",
                  "format": "int64"
                },
                "dropoff_pct": {
                  "type": "number",
                  "format": "double"
                }
              }
            }
          }
        }
      },
      "SuggestSlugInput": {
        "type": "object",
        "required": [
          "destination_url"
        ],
        "properties": {
          "destination_url": {
            "type": "string",
            "format": "uri"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "context": {
            "type": "string",
            "description": "Optional free-form hint (e.g. \"promo for Q3 launch\")."
          }
        }
      },
      "SuggestSlugResponse": {
        "type": "object",
        "required": [
          "suggestions"
        ],
        "properties": {
          "suggestions": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5,
            "items": {
              "type": "string"
            }
          },
          "cached": {
            "type": "boolean",
            "description": "True when served from the in-process 24h cache."
          }
        }
      },
      "GenerateGS1QRInput": {
        "type": "object",
        "required": [
          "gtin"
        ],
        "properties": {
          "gtin": {
            "type": "string",
            "description": "8/12/13/14-digit GTIN.",
            "pattern": "^[0-9]{8,14}$"
          },
          "batch_lot": {
            "type": "string"
          },
          "serial": {
            "type": "string"
          },
          "expiration_date": {
            "type": "string",
            "format": "date"
          },
          "size_px": {
            "type": "integer",
            "minimum": 64,
            "maximum": 2048,
            "default": 512
          },
          "format": {
            "type": "string",
            "enum": [
              "png",
              "svg"
            ],
            "default": "png"
          }
        }
      },
      "GenerateQRResponse": {
        "type": "object",
        "required": [
          "content_type",
          "data"
        ],
        "properties": {
          "content_type": {
            "type": "string",
            "enum": [
              "image/png",
              "image/svg+xml"
            ]
          },
          "data": {
            "type": "string",
            "description": "Base64-encoded payload (PNG bytes) or raw SVG markup,\ndepending on `content_type`.\n"
          }
        }
      }
    }
  }
}
