{"openapi":"3.0.0","info":{"title":"VisiBug API","version":"1.0.0","description":"\nA SaaS bug reporting and feedback collection system API.\n\n## Authentication\n\nThere are three authentication methods:\n\n### 1. API Keys (Recommended)\nUse API keys for all integrations. Include the key in the Authorization header:\n```\nAuthorization: Bearer pk_live_xxxxxxxxxxxx\n```\n\n**Key Types:**\n- `pk_*` (Publishable) - Safe for frontend/widget, limited scopes\n- `sk_*` (Secret) - Server-side only, full access\n- `rk_*` (Restricted) - Custom scopes for partners\n\n### 2. Session Cookie (Dashboard)\nUsed by the admin dashboard. Login via `POST /api/auth/login` to receive a session cookie.\n\n### 3. Legacy Header Auth (Deprecated)\nFor backwards compatibility, the widget still accepts:\n- `X-Project-ID`: Your project's unique ID\n- `X-User-Email`: (optional) End user's email\n\n## Rate Limits\nRate limits vary by API key type and plan:\n- Free: 60/min, 1,000/day\n- Pro: 300/min, 10,000/day\n- Enterprise: 1,000/min, 100,000/day\n    ","contact":{"name":"API Support"}},"servers":[{"url":"https://support-tool.vercel.app","description":"Current environment"}],"tags":[{"name":"Authentication","description":"User authentication endpoints"},{"name":"API Keys","description":"Manage API keys for integrations"},{"name":"Reports","description":"Bug reports and feedback management"},{"name":"Conversations","description":"User-admin messaging system"},{"name":"Admin","description":"Admin-only endpoints for workspace management"},{"name":"Widget","description":"Endpoints used by the embedded widget"},{"name":"Webhooks","description":"Webhook endpoints for integrations"},{"name":"Team","description":"Team member management and project access"},{"name":"Billing","description":"Billing, usage, and checkout"},{"name":"Domains","description":"Custom domain management and verification"},{"name":"Entitlements","description":"Feature flags, limits, and plan entitlements"},{"name":"Platform Admin","description":"Platform-wide administration (requires platform admin)"}],"paths":{"/api/auth/login":{"post":{"tags":["Authentication"],"summary":"Login to dashboard","description":"Authenticate a workspace user and receive a session cookie.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"admin@example.com"},"password":{"type":"string","minLength":1,"example":"your-password"}}}}}},"responses":{"200":{"description":"Login successful","headers":{"Set-Cookie":{"description":"Session cookie (support_tool_session)","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"workspace":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Acme Corp"},"slug":{"type":"string","example":"acme-corp"}}},"user":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/auth/logout":{"post":{"tags":["Authentication"],"summary":"Logout from dashboard","description":"Clear the session cookie and log out the user.","responses":{"200":{"description":"Logout successful","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true}}}}}}}}},"/api/auth/signup":{"post":{"tags":["Authentication"],"summary":"Create a new workspace","description":"Register a new workspace and admin user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password","workspaceName","workspaceSlug"],"properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8},"workspaceName":{"type":"string","example":"Acme Corp"},"workspaceSlug":{"type":"string","pattern":"^[a-z0-9-]+$","example":"acme-corp"}}}}}},"responses":{"201":{"description":"Workspace created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"workspace":{"$ref":"#/components/schemas/Workspace"},"project":{"$ref":"#/components/schemas/Project"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"409":{"description":"Workspace slug already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/session":{"get":{"tags":["Authentication"],"summary":"Get current session","description":"Retrieve the current user session information.","security":[{"cookieAuth":[]}],"responses":{"200":{"description":"Session retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"authenticated":{"type":"boolean"},"workspace":{"$ref":"#/components/schemas/Workspace"},"user":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/ingest":{"post":{"tags":["Widget","Reports"],"summary":"Submit a bug report or feedback","description":"\nSubmit a new bug report or feedback from the embedded widget.\n\nThis endpoint:\n1. Validates the project ID\n2. Validates the payload\n3. Returns immediately with a tracking token\n4. Processes the report in the background (screenshot upload, conversation creation, etc.)\n        ","parameters":[{"$ref":"#/components/parameters/XProjectId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportInput"}}}},"responses":{"201":{"description":"Report received and being processed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Report received and is being processed"},"token":{"type":"string","description":"Token for tracking this report","example":"usr_abc123xyz"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Origin not allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/my-tickets":{"get":{"tags":["Widget"],"summary":"Get user tickets","description":"Get all tickets for a user (from widget). Requires token or email query param.","parameters":[{"$ref":"#/components/parameters/XProjectId"},{"name":"token","in":"query","description":"End-user token received from ingest response","schema":{"type":"string"}},{"name":"email","in":"query","description":"User email to lookup tickets","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"Tickets retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"tickets":{"type":"array","items":{"type":"object","properties":{"report_id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["issue","feedback"]},"status":{"type":"string"},"user_message":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/v1/conversations":{"get":{"tags":["Conversations"],"summary":"List conversations","description":"Get all conversations for a user (widget) or workspace (dashboard).","security":[{"widgetAuth":[]}],"parameters":[{"$ref":"#/components/parameters/XProjectIdOptional"},{"$ref":"#/components/parameters/XUserEmail"}],"responses":{"200":{"description":"Conversations retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"conversations":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"}}},"post":{"tags":["Conversations"],"summary":"Create a conversation","description":"Start a new conversation from the widget.","parameters":[{"$ref":"#/components/parameters/XProjectId"},{"$ref":"#/components/parameters/XUserEmail"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1},"user_name":{"type":"string"}}}}}},"responses":{"201":{"description":"Conversation created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"conversation":{"$ref":"#/components/schemas/Conversation"},"message":{"$ref":"#/components/schemas/Message"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/conversations/{id}/messages":{"get":{"tags":["Conversations"],"summary":"Get conversation messages","description":"Retrieve all messages in a conversation.","parameters":[{"$ref":"#/components/parameters/ConversationId"},{"$ref":"#/components/parameters/XProjectIdOptional"},{"$ref":"#/components/parameters/XUserEmail"}],"responses":{"200":{"description":"Messages retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}}}}}},"post":{"tags":["Conversations"],"summary":"Send a message","description":"Add a new message to a conversation.","parameters":[{"$ref":"#/components/parameters/ConversationId"},{"$ref":"#/components/parameters/XProjectIdOptional"},{"$ref":"#/components/parameters/XUserEmail"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1},"author_name":{"type":"string"}}}}}},"responses":{"201":{"description":"Message sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/conversations/{id}/stream":{"get":{"tags":["Conversations"],"summary":"Stream conversation updates","description":"Server-Sent Events (SSE) endpoint for real-time message updates.","parameters":[{"$ref":"#/components/parameters/ConversationId"}],"responses":{"200":{"description":"SSE stream established","content":{"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events stream"}}}}}}},"/api/v1/public/workspace-settings":{"get":{"tags":["Widget"],"summary":"Get public workspace settings","description":"Get widget settings for rendering (public, no auth required).","parameters":[{"$ref":"#/components/parameters/XProjectId"}],"responses":{"200":{"description":"Public settings retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSettings"}}}}}}},"/api/webhooks/stripe":{"post":{"tags":["Webhooks"],"summary":"Stripe webhook","description":"Handle Stripe payment and subscription events.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Webhook processed"}}}}},"components":{"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"support_tool_session","description":"Session cookie from login"},"widgetAuth":{"type":"apiKey","in":"header","name":"X-Project-ID","description":"Project ID header for widget authentication"}},"parameters":{"XProjectId":{"name":"X-Project-ID","in":"header","required":true,"description":"Project ID for widget authentication","schema":{"type":"string","format":"uuid"}},"XProjectIdOptional":{"name":"X-Project-ID","in":"header","required":false,"description":"Project ID for widget authentication","schema":{"type":"string","format":"uuid"}},"XUserEmail":{"name":"X-User-Email","in":"header","required":false,"description":"User email for tracking conversations","schema":{"type":"string","format":"email"}},"ReportId":{"name":"id","in":"path","required":true,"description":"Report ID","schema":{"type":"string","format":"uuid"}},"ConversationId":{"name":"id","in":"path","required":true,"description":"Conversation ID","schema":{"type":"string","format":"uuid"}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"details":{"type":"object"}}},"Workspace":{"type":"object","properties":{"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"created_at":{"type":"string","format":"date-time"}}},"Project":{"type":"object","properties":{"project_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"active":{"type":"boolean"},"allowed_domains":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string","format":"date-time"}}},"ReportInput":{"type":"object","required":["user_message","browser"],"properties":{"type":{"type":"string","enum":["issue","feedback"],"default":"issue"},"user_message":{"type":"string","minLength":1,"maxLength":5000},"reporter":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"}}},"browser":{"type":"object","required":["userAgent","url"],"properties":{"userAgent":{"type":"string"},"screenSize":{"type":"string","example":"1920x1080"},"viewport":{"type":"string","example":"1200x800"},"url":{"type":"string","format":"uri"},"language":{"type":"string"}}},"logs_buffer":{"type":"array","items":{"type":"object","properties":{"timestamp":{"type":"string"},"level":{"type":"string"},"message":{"type":"string"}}}},"network_logs":{"type":"array","items":{"type":"object"}},"dom_interactions":{"type":"array","items":{"type":"object"}},"screenshot_base64":{"type":"string","format":"base64"},"user_metadata":{"type":"object"}}},"Report":{"type":"object","properties":{"report_id":{"type":"string","format":"uuid"},"project_id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid","nullable":true},"type":{"type":"string","enum":["issue","feedback"]},"status":{"type":"string","enum":["open","in_progress","resolved","closed"]},"user_message":{"type":"string"},"reporter_email":{"type":"string","nullable":true},"reporter_name":{"type":"string","nullable":true},"browser_info":{"type":"object"},"current_url":{"type":"string"},"screenshot_url":{"type":"string","nullable":true},"console_logs":{"type":"array","items":{"type":"object"}},"network_logs":{"type":"array","items":{"type":"object"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Conversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"project_id":{"type":"string","format":"uuid"},"user_email":{"type":"string"},"user_name":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["open","closed","waiting_on_user"]},"message_count":{"type":"integer"},"unread_by_admin":{"type":"integer"},"unread_by_user":{"type":"integer"},"waiting_on_user":{"type":"boolean"},"last_message_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"author_type":{"type":"string","enum":["user","admin"]},"author_email":{"type":"string"},"author_name":{"type":"string"},"message":{"type":"string"},"read_by_user":{"type":"boolean"},"read_by_admin":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"WorkspaceSettings":{"type":"object","properties":{"workspace_id":{"type":"string","format":"uuid"},"gradient_start":{"type":"string","example":"#3b82f6"},"gradient_end":{"type":"string","example":"#1e40af"},"widget_position":{"type":"string","enum":["bottom-right","bottom-left","top-right","top-left"]},"widget_button_color":{"type":"string","example":"#000000"},"widget_header_message":{"type":"string"},"nav_home":{"type":"boolean"},"nav_messages":{"type":"boolean"},"nav_tickets":{"type":"boolean"},"nav_help":{"type":"boolean"},"nav_updates":{"type":"boolean"}}},"WorkspaceSettingsInput":{"type":"object","properties":{"gradient_start":{"type":"string"},"gradient_end":{"type":"string"},"widget_position":{"type":"string","enum":["bottom-right","bottom-left","top-right","top-left"]},"widget_button_color":{"type":"string"},"widget_header_message":{"type":"string"},"nav_home":{"type":"boolean"},"nav_messages":{"type":"boolean"},"nav_tickets":{"type":"boolean"},"nav_help":{"type":"boolean"},"nav_updates":{"type":"boolean"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Production Widget"},"key_prefix":{"type":"string","example":"pk_live_a1b2","description":"First 12 characters of the key"},"key_type":{"type":"string","enum":["publishable","secret","restricted"]},"scopes":{"type":"array","items":{"type":"string"},"example":["reports:write","conversations:read"]},"rate_limit_per_minute":{"type":"integer","example":100},"rate_limit_per_day":{"type":"integer","example":10000},"active":{"type":"boolean"},"last_used_at":{"type":"string","format":"date-time","nullable":true},"total_requests":{"type":"integer"},"expires_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"created_by":{"type":"string","format":"email"},"revoked_at":{"type":"string","format":"date-time","nullable":true},"revoked_by":{"type":"string","format":"email","nullable":true}}},"TeamMember":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]},"workspace_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"last_login_at":{"type":"string","format":"date-time","nullable":true},"project_ids":{"type":"array","items":{"type":"string"}},"access_mode":{"type":"string","enum":["full","restricted"]}}},"PlanInfo":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"plan_key":{"type":"string","example":"pro"},"plan_name":{"type":"string","example":"Pro"},"price_monthly":{"type":"number","example":29},"price_yearly":{"type":"number","example":290}}},"PlanDetailed":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"plan_key":{"type":"string"},"plan_name":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","enum":["draft","active","legacy","archived"]},"price_monthly":{"type":"number"},"price_annual":{"type":"number"},"display_order":{"type":"integer"},"is_featured":{"type":"boolean"},"badge_text":{"type":"string","nullable":true},"trial_days":{"type":"integer"},"features":{"type":"array","items":{"type":"object"}},"limits":{"type":"array","items":{"type":"object"}},"workspace_count":{"type":"integer"}}},"UsageMetric":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer","description":"Max allowed or \"unlimited\""}}},"FeatureStatus":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"feature_key":{"type":"string"},"feature_name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"is_enabled":{"type":"boolean"}}},"FeatureEntitlement":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"feature_key":{"type":"string"},"feature_name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"is_enabled":{"type":"boolean"},"purchase_type":{"type":"string","enum":["plan_only","addon","free"]},"visibility_when_locked":{"type":"string","enum":["show_locked","hidden","show_teaser"]},"addon_price_monthly":{"type":"number","nullable":true},"addon_price_yearly":{"type":"number","nullable":true}}},"LimitEntitlement":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"limit_key":{"type":"string"},"limit_name":{"type":"string"},"description":{"type":"string"},"unit":{"type":"string"},"current_value":{"type":"integer","description":"Effective limit (plan + addons + overrides)"},"used_value":{"type":"integer"},"purchase_type":{"type":"string"},"expansion_pack_size":{"type":"integer","nullable":true},"expansion_pack_price_monthly":{"type":"number","nullable":true}}},"CustomDomain":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspace_id":{"type":"string","format":"uuid"},"domain":{"type":"string","example":"support.example.com"},"verification_status":{"type":"string","enum":["pending","verified","failed"]},"verification_token":{"type":"string"},"required_dns_records":{"type":"array","items":{"type":"object"}},"is_primary":{"type":"boolean"},"is_active":{"type":"boolean"},"ssl_status":{"type":"string","enum":["pending","provisioning","active","failed"]},"created_at":{"type":"string","format":"date-time"},"verified_at":{"type":"string","format":"date-time","nullable":true}}},"Feature":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"feature_key":{"type":"string"},"feature_name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"display_order":{"type":"integer"},"is_active":{"type":"boolean"}}},"LimitType":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"limit_key":{"type":"string"},"limit_name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"unit":{"type":"string"},"is_active":{"type":"boolean"}}}},"responses":{"BadRequest":{"description":"Bad request - invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Unauthorized - authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}