openapi: 3.0.3
info:
  title: CORE API
  version: 1.0.0
  description: |
    CORE is a memory sharing platform for LLMs with graph-based storage, temporal facts, and comprehensive search capabilities.

    ## Authentication

    CORE supports multiple authentication methods:
    - **Bearer Token**: Personal API tokens or OAuth2 access tokens
    - **OAuth2**: Full OAuth2 authorization code flow with PKCE support
    - **Session Cookies**: For web interface access

    Most API endpoints support Bearer token authentication via the Authorization header:
    ```
    Authorization: Bearer YOUR_TOKEN_HERE
    ```

    ## Features

    - **Temporal Knowledge Graph**: Store and query facts with temporal validity
    - **Spaces**: Organize knowledge into logical spaces/projects
    - **Search**: Advanced semantic search with graph traversal
    - **Ingestion**: Process and extract facts from various data sources  
    - **Integrations**: Connect with external platforms via OAuth2
    - **MCP Support**: Model Context Protocol for AI assistant integration
    - **Webhooks**: Real-time notifications for data changes

  contact:
    name: Core
    url: https://github.com/redplanethq/core

servers:
  - url: "{protocol}://{domain}"
    description: Configurable CORE server
    variables:
      protocol:
        default: https
        enum: [http, https]
        description: The protocol to use
      domain:
        default: core.heysol.ai
        description: The CORE API domain

security:
  - bearerAuth: []
  - oauth2: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Bearer token authentication supports:
        - Personal API tokens (PATs)
        - OAuth2 access tokens
        - JWT tokens

        Example: `Authorization: Bearer your_token_here`

    oauth2:
      type: oauth2
      description: |
        OAuth2 authorization code flow with PKCE support.
        Supports scopes: read, write, mcp, integration, oauth
      flows:
        authorizationCode:
          authorizationUrl: "/oauth/authorize"
          tokenUrl: "/oauth/token"
          refreshUrl: "/oauth/token"
          scopes:
            read: Read access to user data
            write: Write access to user data
            mcp: MCP (Model Context Protocol) access
            integration: Access to integrations
            oauth: OAuth client management

  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error code or message
        error_description:
          type: string
          description: Human-readable error description
        details:
          type: array
          description: Validation error details
          items:
            type: object
      required:
        - error

    OAuth2Error:
      type: object
      properties:
        error:
          type: string
          enum:
            [
              invalid_request,
              invalid_client,
              invalid_grant,
              unauthorized_client,
              unsupported_grant_type,
              invalid_scope,
            ]
        error_description:
          type: string
        error_uri:
          type: string
        state:
          type: string

    OAuth2TokenResponse:
      type: object
      properties:
        access_token:
          type: string
          description: The access token
        token_type:
          type: string
          enum: [Bearer]
        expires_in:
          type: integer
          description: Access token lifetime in seconds
        refresh_token:
          type: string
          description: Refresh token (if applicable)
        scope:
          type: string
          description: Space-separated list of granted scopes

    UserInfo:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        name:
          type: string
        picture:
          type: string
          format: uri

    SearchRequest:
      type: object
      required:
        - query
      properties:
        query:
          type: string
          description: Search query text
        startTime:
          type: string
          format: date-time
          description: Filter facts after this timestamp
        endTime:
          type: string
          format: date-time
          description: Filter facts before this timestamp
        spaceIds:
          type: array
          items:
            type: string
          default: []
          description: Filter results to specific spaces
        limit:
          type: integer
          minimum: 1
          maximum: 1000
          description: Maximum number of results
        maxBfsDepth:
          type: integer
          minimum: 1
          maximum: 10
          description: Maximum graph traversal depth
        includeInvalidated:
          type: boolean
          default: false
          description: Include invalidated facts
        entityTypes:
          type: array
          items:
            type: string
          description: Filter by entity types
        scoreThreshold:
          type: number
          minimum: 0
          maximum: 1
          description: Minimum relevance score
        minResults:
          type: integer
          minimum: 1
          description: Minimum number of results to return

    ExtensionSearchRequest:
      type: object
      required:
        - input
      properties:
        input:
          type: string
          description: Search input text
        limit:
          type: integer
          minimum: 1
          maximum: 1000
        maxBfsDepth:
          type: integer
          minimum: 1
          maximum: 10
        includeInvalidated:
          type: boolean
          default: false
        entityTypes:
          type: array
          items:
            type: string
        scoreThreshold:
          type: number
          minimum: 0
          maximum: 1
        minResults:
          type: integer
          minimum: 1

    ExtensionSummaryRequest:
      type: object
      required:
        - html
        - url
      properties:
        html:
          type: string
          description: HTML content to summarize
        url:
          type: string
          format: uri
          description: URL of the page
        title:
          type: string
          description: Page title

    IngestRequest:
      type: object
      required:
        - episodeBody
        - referenceTime
        - source
      properties:
        episodeBody:
          type: string
          description: Content to ingest and process
        referenceTime:
          type: string
          format: date-time
          description: Reference timestamp for the content
        metadata:
          type: object
          additionalProperties:
            oneOf:
              - type: string
              - type: number
              - type: boolean
          description: Additional metadata
        source:
          type: string
          description: Source identifier
        spaceId:
          type: string
          description: Space to assign the content to
        sessionId:
          type: string
          description: Session identifier

    ActivityRequest:
      type: object
      required:
        - text
        - source
      properties:
        text:
          type: string
          description: Activity text content
        source:
          type: string
          description: Source identifier
        sourceURL:
          type: string
          format: uri
          description: Source URL
        integrationAccountId:
          type: string
          description: Integration account ID
        taskId:
          type: string
          description: Task identifier

    Space:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        userId:
          type: string

    CreateSpaceRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          description: Space name
        description:
          type: string
          description: Space description

    UpdateSpaceRequest:
      type: object
      properties:
        name:
          type: string
          description: Updated space name
        description:
          type: string
          description: Updated space description

    BulkSpaceOperation:
      type: object
      required:
        - intent
      properties:
        intent:
          type: string
          enum:
            [
              assign_statements,
              remove_statements,
              bulk_assign,
              initialize_space_ids,
            ]
          description: Type of bulk operation
        spaceId:
          type: string
          description: Target space ID (required for some operations)
        statementIds:
          type: array
          items:
            type: string
          description: Statement IDs to operate on
        spaceIds:
          type: array
          items:
            type: string
          description: Space IDs for bulk operations

    IngestionRule:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        text:
          type: string
        source:
          type: string
        isActive:
          type: boolean
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    CreateIngestionRuleRequest:
      type: object
      required:
        - text
        - source
      properties:
        name:
          type: string
        text:
          type: string
          description: Rule text/content
        source:
          type: string
          description: Source identifier
        isActive:
          type: boolean
          default: true

    UpdateIngestionRuleRequest:
      type: object
      required:
        - id
      properties:
        id:
          type: string
        name:
          type: string
        text:
          type: string
        source:
          type: string
        isActive:
          type: boolean

    OAuth2Client:
      type: object
      properties:
        id:
          type: string
        clientId:
          type: string
        name:
          type: string
        redirectUris:
          type: array
          items:
            type: string
            format: uri
        createdAt:
          type: string
          format: date-time

    Conversation:
      type: object
      properties:
        id:
          type: string
        title:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    Log:
      type: object
      properties:
        id:
          type: string
          description: Log identifier
        source:
          type: string
          description: Log source name
        ingestText:
          type: string
          description: Text content that was ingested
        time:
          type: string
          format: date-time
          description: Creation timestamp
        processedAt:
          type: string
          format: date-time
          nullable: true
          description: Processing completion timestamp
        episodeUUID:
          type: string
          nullable: true
          description: Associated episode UUID if processed
        status:
          type: string
          enum: [pending, processing, completed, failed]
          description: Processing status
        error:
          type: string
          nullable: true
          description: Error message if processing failed
        sourceURL:
          type: string
          format: uri
          nullable: true
          description: Source URL if applicable
        integrationSlug:
          type: string
          nullable: true
          description: Integration slug identifier
        data:
          type: object
          nullable: true
          description: Additional log data

    DeleteLogRequest:
      type: object
      required:
        - id
      properties:
        id:
          type: string
          description: Log ID to delete

    DeleteLogResponse:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
        deleted:
          type: object
          properties:
            episode:
              type: boolean
            statements:
              type: integer
            entities:
              type: integer
            facts:
              type: integer

paths:
  # OAuth2 & Authentication
  /oauth/authorize:
    get:
      summary: OAuth2 Authorization Endpoint
      description: |
        OAuth2 authorization endpoint supporting authorization code flow with PKCE.
        Requires user to be logged in via session cookie.
      security:
        - {} # No security for initial auth request
      parameters:
        - name: client_id
          in: query
          required: true
          schema:
            type: string
          description: OAuth2 client identifier
        - name: redirect_uri
          in: query
          required: true
          schema:
            type: string
            format: uri
          description: Redirect URI after authorization
        - name: response_type
          in: query
          required: true
          schema:
            type: string
            enum: [code]
          description: Must be 'code' for authorization code flow
        - name: scope
          in: query
          schema:
            type: string
          description: Space-separated list of requested scopes
          example: "read write mcp"
        - name: state
          in: query
          schema:
            type: string
          description: State parameter for CSRF protection
        - name: code_challenge
          in: query
          schema:
            type: string
          description: PKCE code challenge
        - name: code_challenge_method
          in: query
          schema:
            type: string
            enum: [S256, plain]
          description: PKCE code challenge method
      responses:
        "200":
          description: Authorization page displayed
        "302":
          description: Redirect to login if not authenticated
        "400":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Error"
          description: Invalid request parameters

    post:
      summary: OAuth2 Authorization Decision
      description: Handle user's allow/deny decision for OAuth2 authorization
      security:
        - {} # Session cookie required but not in security schemes
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - action
              properties:
                action:
                  type: string
                  enum: [allow, deny]
                client_id:
                  type: string
                redirect_uri:
                  type: string
                  format: uri
                scope:
                  type: string
                state:
                  type: string
                code_challenge:
                  type: string
                code_challenge_method:
                  type: string
                  enum: [S256, plain]
      responses:
        "302":
          description: Redirect to redirect_uri with code or error
        "400":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Error"
          description: Invalid request

  /oauth/token:
    post:
      summary: OAuth2 Token Endpoint
      description: |
        Exchange authorization code for access token, or refresh an existing token.
        Supports both JSON and form-encoded requests.
      security:
        - {} # Client authentication via client_secret or PKCE
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - grant_type
                - client_id
              properties:
                grant_type:
                  type: string
                  enum: [authorization_code, refresh_token]
                code:
                  type: string
                  description: Authorization code (for authorization_code grant)
                redirect_uri:
                  type: string
                  format: uri
                  description: Original redirect URI (for authorization_code grant)
                client_id:
                  type: string
                  description: OAuth2 client ID
                client_secret:
                  type: string
                  description: OAuth2 client secret (if not using PKCE)
                code_verifier:
                  type: string
                  description: PKCE code verifier (for PKCE flow)
                refresh_token:
                  type: string
                  description: Refresh token (for refresh_token grant)
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - grant_type
                - client_id
              properties:
                grant_type:
                  type: string
                  enum: [authorization_code, refresh_token]
                code:
                  type: string
                redirect_uri:
                  type: string
                client_id:
                  type: string
                client_secret:
                  type: string
                code_verifier:
                  type: string
                refresh_token:
                  type: string
      responses:
        "200":
          description: Token issued successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2TokenResponse"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Error"

  /oauth/userinfo:
    get:
      summary: OAuth2 User Info Endpoint
      description: Get authenticated user information
      security:
        - oauth2: [read]
      responses:
        "200":
          description: User information
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UserInfo"
        "401":
          description: Invalid or expired token
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /oauth/tokeninfo:
    get:
      summary: OAuth2 Token Introspection
      description: Get information about the current access token
      security:
        - oauth2: []
      responses:
        "200":
          description: Token information
          content:
            application/json:
              schema:
                type: object
                properties:
                  active:
                    type: boolean
                  scope:
                    type: string
                  client_id:
                    type: string
                  exp:
                    type: integer
                  sub:
                    type: string
        "401":
          description: Invalid token

  # Profile & User Data
  /api/profile:
    get:
      summary: Get User Profile
      description: Get user profile information via OAuth2 authentication
      security:
        - oauth2: [read]
      responses:
        "200":
          description: User profile data
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    $ref: "#/components/schemas/UserInfo"
                  client:
                    type: object
                    properties:
                      clientId:
                        type: string
                      name:
                        type: string
                  scopes:
                    type: array
                    items:
                      type: string

  # Search & Knowledge Graph
  /api/v1/search:
    post:
      summary: Search Knowledge Graph
      description: |
        Perform advanced semantic search with graph traversal capabilities.
        Supports temporal filtering, entity type filtering, and relevance scoring.
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SearchRequest"
      responses:
        "200":
          description: Search results
          content:
            application/json:
              schema:
                type: object
                properties:
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        content:
                          type: string
                        score:
                          type: number
                        metadata:
                          type: object
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized

  # Data Ingestion
  /api/v1/add:
    post:
      summary: Add Data to Ingestion Queue
      description: |
        Add data to the ingestion queue for processing. Content will be analyzed
        and facts will be extracted into the knowledge graph.
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/IngestRequest"
      responses:
        "200":
          description: Data queued for ingestion
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  queueId:
                    type: string

  /api/v1/activity:
    post:
      summary: Create Activity
      description: |
        Create activity and trigger ingestion with webhook notifications.
        Used for real-time data processing with external integrations.
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ActivityRequest"
      responses:
        "200":
          description: Activity created and processed

  # Spaces Management
  /api/v1/spaces:
    get:
      summary: List/Search Spaces
      description: Get list of spaces with optional search filtering
      security:
        - bearerAuth: []
      parameters:
        - name: q
          in: query
          schema:
            type: string
          description: Search query for space names
      responses:
        "200":
          description: List of spaces
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Space"

    post:
      summary: Create New Space
      description: Create a new space for organizing knowledge
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSpaceRequest"
      responses:
        "201":
          description: Space created successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Space"

    put:
      summary: Bulk Space Operations
      description: |
        Perform bulk operations on spaces including:
        - assign_statements: Assign statements to a space
        - remove_statements: Remove statements from a space  
        - bulk_assign: Bulk assign multiple statements
        - initialize_space_ids: Initialize space IDs for statements
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BulkSpaceOperation"
      responses:
        "200":
          description: Bulk operation completed

  /api/v1/spaces/{spaceId}:
    parameters:
      - name: spaceId
        in: path
        required: true
        schema:
          type: string
        description: Space identifier

    get:
      summary: Get Space Details
      description: Retrieve detailed information about a specific space
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Space details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Space"
        "404":
          description: Space not found

    put:
      summary: Update Space
      description: Update space name and/or description
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateSpaceRequest"
      responses:
        "200":
          description: Space updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Space"

    delete:
      summary: Delete Space
      description: Delete a space and optionally reassign its content
      security:
        - bearerAuth: []
      responses:
        "204":
          description: Space deleted successfully

  # Integration Management
  /api/v1/integrations:
    get:
      summary: Get Connected Integrations
      description: Get OAuth client's connected integrations with usage statistics
      security:
        - oauth2: [integration]
      responses:
        "200":
          description: List of connected integrations
          content:
            application/json:
              schema:
                type: object
                properties:
                  integrations:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        type:
                          type: string
                        status:
                          type: string
                  count:
                    type: integer

  /api/v1/integration_account:
    get:
      summary: List Integration Accounts
      description: Get user's integration accounts
      security:
        - bearerAuth: []
      responses:
        "200":
          description: List of integration accounts

    post:
      summary: Create Integration Account
      description: Create new integration account
      security:
        - bearerAuth: []
      responses:
        "201":
          description: Integration account created

  /api/v1/integration_account/disconnect:
    post:
      summary: Disconnect Integration Account
      description: Disconnect an integration account
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Integration disconnected

  /api/v1/integration_account/disconnect_mcp:
    post:
      summary: Disconnect MCP Integration
      description: Disconnect an MCP integration account
      security:
        - bearerAuth: []
      responses:
        "200":
          description: MCP integration disconnected

  # OAuth Client Management
  /api/oauth/clients:
    get:
      summary: List OAuth Clients
      description: Get user's OAuth clients
      security:
        - bearerAuth: []
      responses:
        "200":
          description: List of OAuth clients
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/OAuth2Client"

    post:
      summary: Create OAuth Client
      description: Create new OAuth client application
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - redirectUris
              properties:
                name:
                  type: string
                redirectUris:
                  type: array
                  items:
                    type: string
                    format: uri
      responses:
        "201":
          description: OAuth client created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Client"

  /api/oauth/clients/{clientId}:
    parameters:
      - name: clientId
        in: path
        required: true
        schema:
          type: string

    get:
      summary: Get OAuth Client
      description: Get specific OAuth client details
      security:
        - bearerAuth: []
      responses:
        "200":
          description: OAuth client details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuth2Client"

    put:
      summary: Update OAuth Client
      description: Update OAuth client configuration
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                redirectUris:
                  type: array
                  items:
                    type: string
                    format: uri
      responses:
        "200":
          description: Client updated

    delete:
      summary: Delete OAuth Client
      description: Delete OAuth client application
      security:
        - bearerAuth: []
      responses:
        "204":
          description: Client deleted

  # Episodes & Facts
  /api/v1/episodes/{episodeId}/facts:
    parameters:
      - name: episodeId
        in: path
        required: true
        schema:
          type: string

    get:
      summary: Get Episode Facts
      description: Get facts/statements for a specific episode
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Episode facts
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    content:
                      type: string
                    type:
                      type: string
                    confidence:
                      type: number
                    validFrom:
                      type: string
                      format: date-time
                    validTo:
                      type: string
                      format: date-time

  # System & Monitoring
  /api/v1/logs:
    get:
      summary: Get Ingestion Logs
      description: View ingestion queue status and processing logs
      security:
        - bearerAuth: []
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: source
          in: query
          schema:
            type: string
          description: Filter by source
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, processing, completed, failed]
          description: Filter by status
      responses:
        "200":
          description: Paginated ingestion logs
          content:
            application/json:
              schema:
                type: object
                properties:
                  logs:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        source:
                          type: string
                        status:
                          type: string
                        message:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                  pagination:
                    type: object

  /api/v1/logs/{logId}:
    parameters:
      - name: logId
        in: path
        required: true
        schema:
          type: string
        description: Log identifier

    get:
      summary: Get Specific Log
      description: Retrieve detailed information about a specific ingestion log
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Log details
          content:
            application/json:
              schema:
                type: object
                properties:
                  log:
                    $ref: "#/components/schemas/Log"
        "404":
          description: Log not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

    delete:
      summary: Delete Log Entry
      description: Delete a specific log entry and associated episode if it exists
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeleteLogRequest"
      responses:
        "200":
          description: Log deleted successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeleteLogResponse"
        "404":
          description: Log not found or unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "500":
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/v1/ingestion-queue/status:
    get:
      summary: Get Ingestion Queue Status
      description: Get current status of the ingestion queue
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Queue status information
          content:
            application/json:
              schema:
                type: object
                properties:
                  pending:
                    type: integer
                  processing:
                    type: integer
                  completed:
                    type: integer
                  failed:
                    type: integer
                  totalCapacity:
                    type: integer

  # Webhooks Management
  /api/v1/webhooks:
    post:
      summary: Create Webhook
      description: Create webhook configuration for real-time notifications
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - url
              properties:
                url:
                  type: string
                  format: uri
                  description: Webhook endpoint URL
                secret:
                  type: string
                  description: Optional webhook secret for signature verification
      responses:
        "201":
          description: Webhook created
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  url:
                    type: string
                  secret:
                    type: string
                  createdAt:
                    type: string
                    format: date-time

  /api/v1/webhooks/{id}:
    parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string

    get:
      summary: Get Webhook
      description: Get webhook configuration details
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Webhook details

    put:
      summary: Update Webhook
      description: Update webhook configuration
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                url:
                  type: string
                  format: uri
                secret:
                  type: string
      responses:
        "200":
          description: Webhook updated

    delete:
      summary: Delete Webhook
      description: Delete webhook configuration
      security:
        - bearerAuth: []
      responses:
        "204":
          description: Webhook deleted
