{
  "openapi": "3.1.0",
  "info": {
    "title": "HookSense API",
    "version": "1.0.0",
    "description": "HookSense is a webhook inspection SaaS that lets you capture, inspect, replay,\nand monitor incoming webhooks in real time. This specification covers all public\nand authenticated API endpoints.\n\n## Authentication\nMost endpoints require a JWT token stored in an HTTP-only cookie named `token`.\nThe cookie is set automatically on signup, login, or GitHub OAuth callback.\n\n## Plans\nHookSense offers three plans: **Free**, **Hook**, and **Sense**. Many features\nare gated by plan. Endpoints that require a paid plan return `403` with\n`{ \"error\": \"...\", \"upgrade\": true }`.\n\n## Rate Limiting\nRate-limited endpoints return `429` when the limit is exceeded. Rate limit\nmetadata is conveyed via standard headers.\n",
    "contact": {
      "name": "HookSense",
      "url": "https://hooksense.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://hooksense.com",
      "description": "Production"
    },
    {
      "url": "http://localhost:3001",
      "description": "Development"
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Signup, login, logout, email verification, password reset, OAuth"
    },
    {
      "name": "Endpoints",
      "description": "Create, list, update, claim, and configure webhook endpoints"
    },
    {
      "name": "Requests",
      "description": "View captured webhook requests, replay, diagnose"
    },
    {
      "name": "Billing",
      "description": "Checkout sessions, customer portal, promo codes, LemonSqueezy webhook"
    },
    {
      "name": "Notifications",
      "description": "Notification channels (email, Slack, Discord)"
    },
    {
      "name": "Teams",
      "description": "Team management, invites, members"
    },
    {
      "name": "Admin",
      "description": "Admin-only routes for promos, stats, feature flags"
    },
    {
      "name": "Webhooks",
      "description": "Webhook capture endpoint (the URL providers send webhooks to)"
    },
    {
      "name": "Health",
      "description": "Server health check"
    }
  ],
  "components": {
    "securitySchemes": {
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "token",
        "description": "JWT token stored in an HTTP-only cookie"
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum number of requests allowed in the current window",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Number of requests remaining in the current window",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp (seconds) when the rate limit window resets",
        "schema": {
          "type": "integer"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "upgrade": {
            "type": "boolean",
            "description": "Present and true when the error is due to plan limits"
          }
        }
      },
      "Ok": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "plan": {
            "$ref": "#/components/schemas/PlanName"
          },
          "planExpiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "emailVerified": {
            "type": "boolean"
          },
          "isAdmin": {
            "type": "boolean"
          }
        }
      },
      "UserAuth": {
        "type": "object",
        "description": "User object returned from signup and login (no isAdmin or planExpiresAt)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "plan": {
            "$ref": "#/components/schemas/PlanName"
          },
          "emailVerified": {
            "type": "boolean"
          }
        }
      },
      "PlanName": {
        "type": "string",
        "enum": [
          "free",
          "hook",
          "sense"
        ]
      },
      "Endpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "userId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "customResponseStatus": {
            "type": "integer",
            "default": 200
          },
          "customResponseBody": {
            "type": "string",
            "nullable": true
          },
          "customResponseHeaders": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "customDomain": {
            "type": "string",
            "nullable": true
          },
          "customDomainVerifiedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "webhookSecret": {
            "type": "string",
            "nullable": true
          },
          "signatureProvider": {
            "type": "string",
            "nullable": true,
            "enum": [
              "stripe",
              "github",
              "shopify",
              "custom",
              null
            ]
          },
          "inactivityThreshold": {
            "type": "integer",
            "description": "Inactivity threshold in minutes for monitoring alerts"
          }
        }
      },
      "WebhookRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpointId": {
            "type": "string",
            "format": "uuid"
          },
          "method": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "queryParams": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "body": {
            "type": "string",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "nullable": true
          },
          "sourceIp": {
            "type": "string",
            "nullable": true
          },
          "sizeBytes": {
            "type": "integer"
          },
          "detectedProvider": {
            "type": "string",
            "nullable": true,
            "enum": [
              "stripe",
              "github",
              "shopify",
              "twilio",
              "sendgrid",
              "paddle",
              "linear",
              "slack",
              null
            ]
          },
          "receivedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SignatureVerification": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "provider": {
            "type": "string",
            "enum": [
              "stripe",
              "github",
              "shopify",
              "custom"
            ]
          },
          "algorithm": {
            "type": "string"
          },
          "headerUsed": {
            "type": "string"
          },
          "detectedProvider": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "ReplayResult": {
        "type": "object",
        "properties": {
          "status": {
            "type": "integer"
          },
          "statusText": {
            "type": "string"
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "body": {
            "type": "string"
          }
        }
      },
      "ReplayLog": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "targetUrl": {
            "type": "string"
          },
          "responseStatus": {
            "type": "integer",
            "nullable": true
          },
          "responseDurationMs": {
            "type": "integer",
            "nullable": true
          },
          "replayedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "EndpointAnalytics": {
        "type": "object",
        "properties": {
          "totalRequests": {
            "type": "integer"
          },
          "methodBreakdown": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "avgSizeBytes": {
            "type": "number"
          },
          "requestsOverTime": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "timestamp": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "topSourceIps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ip": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          },
          "peakHour": {
            "type": "string"
          },
          "avgRequestsPerHour": {
            "type": "number"
          }
        }
      },
      "HealthMetrics": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "healthy",
              "warning",
              "down"
            ]
          },
          "summary": {
            "$ref": "#/components/schemas/MetricsSummary"
          },
          "timeline": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MetricsTimeline"
            }
          },
          "period": {
            "type": "string"
          }
        }
      },
      "MetricsSummary": {
        "type": "object",
        "properties": {
          "totalRequests": {
            "type": "integer"
          },
          "successCount": {
            "type": "integer"
          },
          "failCount": {
            "type": "integer"
          },
          "failRate": {
            "type": "number",
            "description": "Percentage with 2 decimal places"
          },
          "lastRequestAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "MetricsTimeline": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "endpointId": {
            "type": "string",
            "format": "uuid"
          },
          "period": {
            "type": "string"
          },
          "periodStart": {
            "type": "string",
            "format": "date-time"
          },
          "totalRequests": {
            "type": "integer"
          },
          "successCount": {
            "type": "integer"
          },
          "failCount": {
            "type": "integer"
          },
          "avgLatencyMs": {
            "type": "number",
            "nullable": true
          },
          "p95LatencyMs": {
            "type": "number",
            "nullable": true
          },
          "lastRequestAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "HealthSummary": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "healthy",
              "warning",
              "down"
            ]
          },
          "totalRequests": {
            "type": "integer"
          },
          "failRate": {
            "type": "number"
          },
          "lastRequestAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "AlertState": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpointId": {
            "type": "string",
            "format": "uuid"
          },
          "ruleType": {
            "type": "string",
            "enum": [
              "stopped",
              "high_fail_rate",
              "latency_spike"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "healthy",
              "alerting",
              "recovered"
            ]
          },
          "triggeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolvedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastNotifiedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "RetryJob": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "endpointId": {
            "type": "string",
            "format": "uuid"
          },
          "requestId": {
            "type": "string",
            "format": "uuid"
          },
          "targetUrl": {
            "type": "string"
          },
          "attemptNumber": {
            "type": "integer"
          },
          "maxAttempts": {
            "type": "integer"
          },
          "nextRetryAt": {
            "type": "string",
            "format": "date-time"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "succeeded",
              "failed",
              "exhausted"
            ]
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "lastResponseStatus": {
            "type": "integer",
            "nullable": true
          },
          "lastResponseDurationMs": {
            "type": "integer",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "diagnosis": {
            "$ref": "#/components/schemas/Diagnosis"
          }
        }
      },
      "Diagnosis": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "enum": [
              "auth",
              "server",
              "network",
              "timeout",
              "signature",
              "unknown"
            ]
          },
          "title": {
            "type": "string"
          },
          "suggestion": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "info",
              "warning",
              "critical"
            ]
          }
        }
      },
      "NotificationChannel": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "endpointId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "email",
              "slack",
              "discord"
            ]
          },
          "target": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Team": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "ownerId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "role": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TeamMember": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string"
          },
          "joinedAt": {
            "type": "string",
            "format": "date-time"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "TeamDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Team"
          },
          {
            "type": "object",
            "properties": {
              "members": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TeamMember"
                }
              },
              "endpoints": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          }
        ]
      },
      "TeamInvite": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "teamId": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string"
          },
          "token": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdminStats": {
        "type": "object",
        "properties": {
          "totalUsers": {
            "type": "integer"
          },
          "totalEndpoints": {
            "type": "integer"
          },
          "totalRequests": {
            "type": "integer"
          }
        }
      },
      "PromoCode": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "durationDays": {
            "type": "integer"
          },
          "maxRedemptions": {
            "type": "integer",
            "nullable": true
          },
          "currentRedemptions": {
            "type": "integer"
          },
          "active": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PromoRedemption": {
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "userEmail": {
            "type": "string",
            "format": "email"
          },
          "userName": {
            "type": "string",
            "nullable": true
          },
          "redeemedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FeatureFlag": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "category": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required or invalid credentials",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient permissions or plan upgrade required",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Resource already exists",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/auth/signup": {
      "post": {
        "operationId": "signup",
        "tags": [
          "Auth"
        ],
        "summary": "Create a new account",
        "description": "Register a new user with email and password. Sets a JWT cookie on success\nand sends a verification email. Rate limited to 5 attempts per IP per 15 minutes.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 254
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created successfully",
            "headers": {
              "Set-Cookie": {
                "description": "JWT token cookie",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserAuth"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "description": "Email already registered",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "operationId": "login",
        "tags": [
          "Auth"
        ],
        "summary": "Log in with email and password",
        "description": "Authenticate with email and password. Sets a JWT cookie on success.\nProgressive lockout applies after repeated failed attempts: delay after 5\nfailures, longer delay after 10, and full block after 15 within a 15-minute window.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "password"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful",
            "headers": {
              "Set-Cookie": {
                "description": "JWT token cookie",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserAuth"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "description": "Invalid email or password",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "operationId": "logout",
        "tags": [
          "Auth"
        ],
        "summary": "Log out",
        "description": "Clears the JWT cookie.",
        "responses": {
          "200": {
            "description": "Logged out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Auth"
        ],
        "summary": "Get current authenticated user",
        "description": "Returns the currently authenticated user or `{ user: null }` if not logged in.\nAlso performs silent token refresh when the JWT is past its half-life (12 hours)\nand checks for plan expiry with automatic downgrade.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "responses": {
          "200": {
            "description": "Current user (or null if unauthenticated)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/User"
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/verify-email": {
      "post": {
        "operationId": "verifyEmail",
        "tags": [
          "Auth"
        ],
        "summary": "Verify email address",
        "description": "Verify a user's email using the token sent via email.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Email verified (or already verified)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "emailVerified": {
                      "type": "boolean"
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/api/auth/resend-verification": {
      "post": {
        "operationId": "resendVerification",
        "tags": [
          "Auth"
        ],
        "summary": "Resend email verification",
        "description": "Regenerates the verification token and re-sends the verification email. Requires authentication.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Verification email sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "Email is already verified",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/auth/forgot-password": {
      "post": {
        "operationId": "forgotPassword",
        "tags": [
          "Auth"
        ],
        "summary": "Request password reset",
        "description": "Sends a password reset email if the account exists. Always returns success\nto prevent email enumeration. Rate limited to 5 per IP per 15 minutes.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reset email sent (always returns success)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/auth/reset-password": {
      "post": {
        "operationId": "resetPassword",
        "tags": [
          "Auth"
        ],
        "summary": "Reset password with token",
        "description": "Set a new password using a reset token received via email.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Password reset successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or expired token, or password too short",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/github": {
      "get": {
        "operationId": "githubOAuthStart",
        "tags": [
          "Auth"
        ],
        "summary": "Start GitHub OAuth flow",
        "description": "Redirects the user to GitHub for OAuth authorization. Sets a `github_oauth_state`\ncookie for CSRF protection. Returns 503 if GitHub OAuth is not configured.\n",
        "responses": {
          "302": {
            "description": "Redirect to GitHub authorization URL"
          },
          "503": {
            "description": "GitHub OAuth not configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/github/callback": {
      "get": {
        "operationId": "githubOAuthCallback",
        "tags": [
          "Auth"
        ],
        "summary": "GitHub OAuth callback",
        "description": "Handles the OAuth callback from GitHub. Validates the state parameter,\nexchanges the authorization code for an access token, creates or links the\nuser account, and redirects to the app with a JWT cookie set.\n",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to app on success, or to login page with error parameter on failure"
          }
        }
      }
    },
    "/api/auth/cli": {
      "get": {
        "operationId": "cliLogin",
        "tags": [
          "Auth"
        ],
        "summary": "Browser-based login for CLI",
        "description": "The CLI opens this URL in the user's browser. If the user is already\nauthenticated, it generates a fresh JWT and POSTs it to the CLI's local\ncallback server. If not logged in, redirects to the login page with a\nreturn URL. Port must be in range 1024-65535.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "port",
            "in": "query",
            "required": true,
            "description": "The local port where the CLI is listening for the callback",
            "schema": {
              "type": "integer",
              "minimum": 1024,
              "maximum": 65535
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML page that auto-submits the token to the CLI's local server",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "302": {
            "description": "Redirect to login page if not authenticated"
          },
          "400": {
            "description": "Missing or invalid port parameter",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/features": {
      "get": {
        "operationId": "getFeatureFlags",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get public feature flags",
        "description": "Returns a map of feature flag keys to their enabled status.",
        "responses": {
          "200": {
            "description": "Feature flags map",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints": {
      "get": {
        "operationId": "listEndpoints",
        "tags": [
          "Endpoints"
        ],
        "summary": "List authenticated user's endpoints",
        "description": "Returns all webhook endpoints owned by the authenticated user.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of endpoints",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Endpoint"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createEndpoint",
        "tags": [
          "Endpoints"
        ],
        "summary": "Create a new webhook endpoint",
        "description": "Creates a new webhook capture endpoint. Anonymous users can create endpoints\nwithout authentication. Authenticated users are subject to plan-based endpoint\nlimits. Rate limited to 5 per IP per 15 minutes.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "responses": {
          "201": {
            "description": "Endpoint created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          },
          "403": {
            "description": "Endpoint limit reached for current plan",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "current": {
                          "type": "integer"
                        },
                        "max": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/endpoints/{slug}": {
      "get": {
        "operationId": "getEndpoint",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get endpoint by slug",
        "description": "Returns a single endpoint by its slug. No authentication required.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateEndpoint",
        "tags": [
          "Endpoints"
        ],
        "summary": "Update endpoint configuration",
        "description": "Update endpoint settings such as custom response, webhook secret, signature\nprovider, custom slug, or inactivity threshold. Only the endpoint owner can\nmodify it. Some fields require specific plans:\n- Custom response body/headers/status: Hook plan or above\n- Custom slug: Hook plan or above\n- Webhook secret / signature provider: any paid plan\n- Inactivity threshold: Hook plan or above\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "customResponseStatus": {
                    "type": "integer"
                  },
                  "customResponseBody": {
                    "type": "string",
                    "nullable": true
                  },
                  "customResponseHeaders": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "webhookSecret": {
                    "type": "string",
                    "nullable": true
                  },
                  "signatureProvider": {
                    "type": "string",
                    "nullable": true,
                    "enum": [
                      "stripe",
                      "github",
                      "shopify",
                      "custom",
                      null
                    ]
                  },
                  "slug": {
                    "type": "string",
                    "description": "Custom slug (3-32 chars, lowercase alphanumeric and hyphens)",
                    "minLength": 3,
                    "maxLength": 32
                  },
                  "inactivityThreshold": {
                    "type": "integer",
                    "description": "Minutes before an inactivity alert fires",
                    "enum": [
                      30,
                      60,
                      120,
                      360,
                      720,
                      1440
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Slug already in use",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/claim": {
      "post": {
        "operationId": "claimEndpoint",
        "tags": [
          "Endpoints"
        ],
        "summary": "Claim an anonymous endpoint",
        "description": "Claim ownership of an anonymous endpoint after logging in. The endpoint\nmust not already be owned. Sets the expiry based on the user's plan retention.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Endpoint claimed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Endpoint already owned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/domain": {
      "patch": {
        "operationId": "setCustomDomain",
        "tags": [
          "Endpoints"
        ],
        "summary": "Set or clear a custom domain",
        "description": "Assign a custom domain to an endpoint or clear it by sending `null`.\nRequires the Sense plan. Returns a DNS verification token when setting a domain.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "nullable": true,
                    "description": "The custom domain to set, or null to clear"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain updated. When setting a domain, includes verificationToken.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Endpoint"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "verificationToken": {
                          "type": "string",
                          "description": "DNS TXT verification token (only present when setting a domain)"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid domain format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Requires Sense plan or not authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/endpoints/{slug}/domain/verify": {
      "post": {
        "operationId": "verifyCustomDomain",
        "tags": [
          "Endpoints"
        ],
        "summary": "Verify custom domain DNS records",
        "description": "Checks TXT and CNAME DNS records for the custom domain. Rate limited to\n3 per minute per IP. Returns the verified endpoint on success.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain verified",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Endpoint"
                }
              }
            }
          },
          "400": {
            "description": "DNS verification failed or no custom domain set",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "txtVerified": {
                          "type": "boolean"
                        },
                        "cnameVerified": {
                          "type": "boolean"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/api/endpoints/{slug}/requests": {
      "get": {
        "operationId": "listRequests",
        "tags": [
          "Requests"
        ],
        "summary": "List captured requests for an endpoint",
        "description": "Returns captured webhook requests for the given endpoint, with pagination and optional text search.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 0
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Free-text search filter",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of captured requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookRequest"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/endpoints/{slug}/export": {
      "get": {
        "operationId": "exportRequests",
        "tags": [
          "Requests"
        ],
        "summary": "Export requests as JSON or CSV",
        "description": "Export all captured requests for an endpoint. Requires Hook plan or above.\nSupports JSON and CSV formats.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv"
              ],
              "default": "json"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Exported data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookRequest"
                  }
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Requires Hook plan or above",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/requests/{id}": {
      "get": {
        "operationId": "getRequest",
        "tags": [
          "Requests"
        ],
        "summary": "Get a single captured request",
        "description": "Returns full details of a specific captured webhook request by ID.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Request detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookRequest"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/requests/{id}/replay": {
      "post": {
        "operationId": "replayRequest",
        "tags": [
          "Requests"
        ],
        "summary": "Replay a captured request",
        "description": "Re-send a captured webhook request to a target URL. Optionally override\nthe HTTP method, headers, or body. Subject to replay limits based on plan.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "targetUrl"
                ],
                "properties": {
                  "targetUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "method": {
                    "type": "string",
                    "description": "Override the original HTTP method"
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Override the original headers"
                  },
                  "body": {
                    "type": "string",
                    "description": "Override the original request body"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replay result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReplayResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing targetUrl or replay failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Replay limit reached or not authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/endpoints/{slug}/replays": {
      "get": {
        "operationId": "listReplayLogs",
        "tags": [
          "Requests"
        ],
        "summary": "List replay logs for an endpoint",
        "description": "Returns the last 50 replay logs for all requests belonging to this endpoint.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Replay log entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ReplayLog"
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/endpoints/{slug}/verify/{requestId}": {
      "get": {
        "operationId": "verifyRequestSignature",
        "tags": [
          "Requests"
        ],
        "summary": "Verify HMAC signature for a request",
        "description": "Verify the HMAC signature of a captured request against the endpoint's\nwebhook secret. Requires a paid plan and a configured webhook secret.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "requestId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Signature verification result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignatureVerification"
                }
              }
            }
          },
          "400": {
            "description": "No webhook secret configured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Requires a paid plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/requests/diagnose": {
      "post": {
        "operationId": "diagnoseRequest",
        "tags": [
          "Requests"
        ],
        "summary": "Auto-diagnose a request",
        "description": "Analyze request parameters (status code, error, latency, HMAC validity)\nand return a diagnosis with category, severity, and actionable suggestion.\nRequires the Sense plan and the auto_diagnosis feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "statusCode": {
                    "type": "integer"
                  },
                  "error": {
                    "type": "string"
                  },
                  "durationMs": {
                    "type": "number"
                  },
                  "hmacValid": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Diagnosis result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Diagnosis"
                }
              }
            }
          },
          "403": {
            "description": "Requires Sense plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/analytics": {
      "get": {
        "operationId": "getEndpointAnalytics",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get endpoint analytics",
        "description": "Returns analytics data for a webhook endpoint including method breakdown,\nrequest volume over time, top source IPs, and peak hour. The available\ntime period depends on the user's plan retention limits.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "24h",
                "7d",
                "30d"
              ],
              "default": "24h"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Analytics data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndpointAnalytics"
                }
              }
            }
          },
          "400": {
            "description": "Invalid period",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Period exceeds plan retention limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/endpoints/{slug}/metrics": {
      "get": {
        "operationId": "getEndpointMetrics",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get health dashboard metrics",
        "description": "Returns health metrics with timeline data for the specified period.\nIncludes status (healthy/warning/down), summary stats, and time-series data.\nRequires Hook plan or above and the health_dashboard feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "period",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "24h",
                "7d",
                "30d"
              ],
              "default": "24h"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Health metrics with timeline",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthMetrics"
                }
              }
            }
          },
          "400": {
            "description": "Invalid period",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Requires Hook plan or above, or period exceeds retention",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found or feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/metrics/summary": {
      "get": {
        "operationId": "getEndpointMetricsSummary",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get lightweight health summary",
        "description": "Returns a quick health check for the last 24 hours. Lighter weight than\nthe full metrics endpoint. Requires Hook plan or above and the\nhealth_dashboard feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Health summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthSummary"
                }
              }
            }
          },
          "403": {
            "description": "Requires Hook plan or above",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found or feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/alerts": {
      "get": {
        "operationId": "getEndpointAlerts",
        "tags": [
          "Endpoints"
        ],
        "summary": "Get alert history for an endpoint",
        "description": "Returns all alert states for an endpoint. Requires Hook plan or above\nand the email_alerts feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Alert states",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AlertState"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Requires Hook plan or above",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found or feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/endpoints/{slug}/retries": {
      "get": {
        "operationId": "listRetryJobs",
        "tags": [
          "Requests"
        ],
        "summary": "List retry jobs for an endpoint",
        "description": "Returns retry job history for an endpoint. Requires the Sense plan\nand the auto_retry feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Retry jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RetryJob"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Requires Sense plan",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found or feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createRetryJob",
        "tags": [
          "Requests"
        ],
        "summary": "Create a retry job for a failed request",
        "description": "Schedule automatic retries for a failed webhook delivery. Requires the\nSense plan, endpoint ownership, and the auto_retry feature flag.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "requestId",
                  "targetUrl"
                ],
                "properties": {
                  "requestId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "targetUrl": {
                    "type": "string",
                    "format": "uri"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Retry job created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RetryJob"
                }
              }
            }
          },
          "400": {
            "description": "Missing fields or could not create retry job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Requires Sense plan or not authorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint or request not found, or feature not available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/checkout": {
      "post": {
        "operationId": "createCheckout",
        "tags": [
          "Billing"
        ],
        "summary": "Create a checkout session",
        "description": "Creates a LemonSqueezy checkout URL for upgrading to a paid plan.\nReturns a URL to redirect the user to the payment page.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "hook",
                      "sense"
                    ],
                    "default": "hook"
                  },
                  "yearly": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid plan selection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "description": "Billing not configured or checkout creation failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/portal": {
      "post": {
        "operationId": "createPortalSession",
        "tags": [
          "Billing"
        ],
        "summary": "Get customer portal URL",
        "description": "Returns the LemonSqueezy customer portal URL where the user can manage\ntheir subscription. Requires an active subscription.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Portal URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No active subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/billing/redeem": {
      "post": {
        "operationId": "redeemPromo",
        "tags": [
          "Billing"
        ],
        "summary": "Redeem a promo code",
        "description": "Apply a promotional code to upgrade the user's plan for a limited duration.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Promo redeemed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string"
                    },
                    "expiresAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, expired, or already redeemed promo code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/lemonsqueezy/webhook": {
      "post": {
        "operationId": "lemonSqueezyWebhook",
        "tags": [
          "Billing"
        ],
        "summary": "LemonSqueezy webhook handler",
        "description": "Receives subscription lifecycle events from LemonSqueezy. Verified via\nHMAC-SHA256 signature in the `x-signature` header. Handles subscription\ncreation, updates, cancellations, expirations, and payment failures.\n",
        "parameters": [
          {
            "name": "x-signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256 hex signature of the request body",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "LemonSqueezy webhook event payload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook processed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/notifications": {
      "get": {
        "operationId": "listNotificationChannels",
        "tags": [
          "Notifications"
        ],
        "summary": "List notification channels",
        "description": "Returns all notification channels owned by the authenticated user.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Notification channels",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationChannel"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createNotificationChannel",
        "tags": [
          "Notifications"
        ],
        "summary": "Create a notification channel",
        "description": "Create a new notification channel (email, Slack webhook, or Discord webhook).\nCan optionally be scoped to a specific endpoint. Subject to plan-based\nchannel limits.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "target"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "email",
                      "slack",
                      "discord"
                    ]
                  },
                  "target": {
                    "type": "string",
                    "description": "Email address or webhook URL (must be https:// for slack/discord)"
                  },
                  "endpointId": {
                    "type": "string",
                    "format": "uuid",
                    "nullable": true,
                    "description": "Scope notifications to a specific endpoint"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Channel created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationChannel"
                }
              }
            }
          },
          "400": {
            "description": "Invalid channel type, target, or email format",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Channel limit reached or endpoint not owned",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "current": {
                          "type": "integer"
                        },
                        "max": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/notifications/{id}": {
      "delete": {
        "operationId": "deleteNotificationChannel",
        "tags": [
          "Notifications"
        ],
        "summary": "Delete a notification channel",
        "description": "Delete a notification channel owned by the authenticated user.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Channel deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "toggleNotificationChannel",
        "tags": [
          "Notifications"
        ],
        "summary": "Toggle notification channel enabled state",
        "description": "Enable or disable a notification channel.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Channel updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationChannel"
                }
              }
            }
          },
          "400": {
            "description": "enabled must be a boolean",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/notifications/{id}/test": {
      "post": {
        "operationId": "testNotificationChannel",
        "tags": [
          "Notifications"
        ],
        "summary": "Send a test notification",
        "description": "Send a test message through the specified notification channel to verify it works.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Test notification sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "description": "Test notification failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/teams": {
      "get": {
        "operationId": "listTeams",
        "tags": [
          "Teams"
        ],
        "summary": "List user's teams",
        "description": "Returns all teams the authenticated user is a member of.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Teams list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Team"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createTeam",
        "tags": [
          "Teams"
        ],
        "summary": "Create a new team",
        "description": "Create a team with a unique slug. The creator becomes the owner.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "slug"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "slug": {
                    "type": "string",
                    "description": "URL-friendly identifier (3-32 chars, lowercase alphanumeric and hyphens)",
                    "minLength": 3,
                    "maxLength": 32,
                    "pattern": "^[a-z0-9-]+$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Team created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Team"
                }
              }
            }
          },
          "400": {
            "description": "Invalid name or slug",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "Team slug already taken",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/teams/{slug}": {
      "get": {
        "operationId": "getTeamDetail",
        "tags": [
          "Teams"
        ],
        "summary": "Get team detail with members and endpoints",
        "description": "Returns full team details including members and endpoints.\nOnly accessible to team members.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Team detail",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Not a team member",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/teams/{slug}/invite": {
      "post": {
        "operationId": "inviteToTeam",
        "tags": [
          "Teams"
        ],
        "summary": "Invite a user to the team by email",
        "description": "Send an email invitation to join the team. Only team owners and admins\ncan invite new members. The invite includes a token link.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "admin",
                      "member",
                      "viewer"
                    ],
                    "default": "member"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invite sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamInvite"
                }
              }
            }
          },
          "400": {
            "description": "Invalid email or role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Only owners and admins can invite",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/teams/{slug}/join": {
      "post": {
        "operationId": "joinTeam",
        "tags": [
          "Teams"
        ],
        "summary": "Accept a team invite",
        "description": "Accept an invitation to join a team using the invite token.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "token": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Joined team",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "team": {
                      "$ref": "#/components/schemas/Team"
                    },
                    "member": {
                      "$ref": "#/components/schemas/TeamMember"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, expired, or already accepted invite",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/teams/{slug}/members/{userId}": {
      "delete": {
        "operationId": "removeTeamMember",
        "tags": [
          "Teams"
        ],
        "summary": "Remove a team member",
        "description": "Remove a member from the team. Owners and admins can remove other members.\nUsers can always remove themselves (leave the team). The team owner cannot be removed.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Member removed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "400": {
            "description": "Cannot remove the team owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Not authorized to remove members",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Team or member not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateTeamMemberRole",
        "tags": [
          "Teams"
        ],
        "summary": "Change a team member's role",
        "description": "Update the role of a team member. Only the team owner can change roles.\nThe owner's own role cannot be changed.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "role"
                ],
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "admin",
                      "member",
                      "viewer"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamMember"
                }
              }
            }
          },
          "400": {
            "description": "Invalid role or cannot change owner's role",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Only the team owner can change roles",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Team or member not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/admin/stats": {
      "get": {
        "operationId": "getAdminStats",
        "tags": [
          "Admin"
        ],
        "summary": "Get aggregate statistics",
        "description": "Returns total counts of users, endpoints, and requests. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate stats",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdminStats"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/api/admin/promos": {
      "get": {
        "operationId": "listAdminPromos",
        "tags": [
          "Admin"
        ],
        "summary": "List all promo codes",
        "description": "Returns all promo codes with their redemption counts. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Promo codes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PromoCode"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createAdminPromo",
        "tags": [
          "Admin"
        ],
        "summary": "Create a promo code",
        "description": "Create a new promotional code. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code",
                  "plan",
                  "durationDays"
                ],
                "properties": {
                  "code": {
                    "type": "string"
                  },
                  "plan": {
                    "type": "string",
                    "enum": [
                      "hook",
                      "sense"
                    ]
                  },
                  "durationDays": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "maxRedemptions": {
                    "type": "integer",
                    "nullable": true
                  },
                  "expiresAt": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Promo code created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PromoCode"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Promo code already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/admin/promos/{id}": {
      "patch": {
        "operationId": "updateAdminPromo",
        "tags": [
          "Admin"
        ],
        "summary": "Update or toggle a promo code",
        "description": "Update promo code fields or toggle its active status. Send `{ active: boolean }`\nto toggle, or send other fields to update. Admin only.\n",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "boolean"
                  },
                  "plan": {
                    "type": "string",
                    "enum": [
                      "hook",
                      "sense"
                    ]
                  },
                  "durationDays": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "maxRedemptions": {
                    "type": "integer",
                    "nullable": true
                  },
                  "expiresAt": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Promo code updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PromoCode"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fields",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/admin/promos/{id}/redemptions": {
      "get": {
        "operationId": "getAdminPromoRedemptions",
        "tags": [
          "Admin"
        ],
        "summary": "List redemptions for a promo code",
        "description": "Returns which users redeemed a specific promo code. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Redemption list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PromoRedemption"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/api/admin/features": {
      "get": {
        "operationId": "listAdminFeatureFlags",
        "tags": [
          "Admin"
        ],
        "summary": "List all feature flags",
        "description": "Returns all feature flags with their metadata. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Feature flags",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FeatureFlag"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/api/admin/features/{key}": {
      "patch": {
        "operationId": "toggleAdminFeatureFlag",
        "tags": [
          "Admin"
        ],
        "summary": "Toggle a feature flag",
        "description": "Enable or disable a feature flag by its key. Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Flag updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureFlag"
                }
              }
            }
          },
          "400": {
            "description": "enabled (boolean) is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/w/{slug}": {
      "get": {
        "operationId": "captureWebhookGet",
        "tags": [
          "Webhooks"
        ],
        "summary": "Capture a webhook (GET)",
        "description": "Capture an incoming webhook request. This is the URL you give to external\nservices. Supports all HTTP methods. The captured request is stored and\nbroadcast to connected WebSocket clients in real time.\n\nRate limited to 60 requests per minute per IP per endpoint. Payload size\nis limited based on the endpoint owner's plan (1MB free, 10MB paid).\n",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook captured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "Endpoint has expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Payload too large",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "limit": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily request limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "captureWebhookPost",
        "tags": [
          "Webhooks"
        ],
        "summary": "Capture a webhook (POST)",
        "description": "Capture an incoming POST webhook request. See GET for full documentation.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Any webhook payload",
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object"
              }
            },
            "text/plain": {
              "schema": {
                "type": "string"
              }
            },
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook captured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "Endpoint has expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Payload too large",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "limit": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit or daily request limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "captureWebhookPut",
        "tags": [
          "Webhooks"
        ],
        "summary": "Capture a webhook (PUT)",
        "description": "Capture an incoming PUT webhook request. See GET for full documentation.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Any webhook payload",
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook captured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "Endpoint has expired"
          },
          "413": {
            "description": "Payload too large"
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      },
      "patch": {
        "operationId": "captureWebhookPatch",
        "tags": [
          "Webhooks"
        ],
        "summary": "Capture a webhook (PATCH)",
        "description": "Capture an incoming PATCH webhook request. See GET for full documentation.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Any webhook payload",
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook captured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "Endpoint has expired"
          },
          "413": {
            "description": "Payload too large"
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      },
      "delete": {
        "operationId": "captureWebhookDelete",
        "tags": [
          "Webhooks"
        ],
        "summary": "Capture a webhook (DELETE)",
        "description": "Capture an incoming DELETE webhook request. See GET for full documentation.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook captured",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ok"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "410": {
            "description": "Endpoint has expired"
          },
          "413": {
            "description": "Payload too large"
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "healthCheck",
        "tags": [
          "Health"
        ],
        "summary": "Server health check",
        "description": "Returns server status and current timestamp. No authentication required.",
        "responses": {
          "200": {
            "description": "Server is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}