openapi: 3.1.0
info:
  title: Bumpkit API
  version: 1.0.0
  description: >
    Automated changelogs and semantic versioning for every release.
    Submit your commit history and get back a structured changelog and
    semver bump decision — with confidence scoring designed for agents
    and CI pipelines.
  contact:
    name: Bumpkit Support
    url: https://bumpkit.dev/support
  license:
    name: MIT

servers:
  - url: https://bumpkit.dev/v1
    description: Production

security:
  - ApiKeyAuth: []

tags:
  - name: Analysis
    description: Core changelog and semver analysis endpoints
  - name: Meta
    description: API metadata and configuration

paths:
  /analyze:
    post:
      tags: [Analysis]
      summary: Analyze commits — returns changelog and semver bump
      description: >
        The primary endpoint. Submit a list of commits and receive both
        a formatted changelog and a semantic version bump recommendation
        in a single response.
      operationId: analyze
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnalyzeRequest'
            example:
              commits:
                - message: "feat: add dark mode toggle"
                  author: "paul"
                  timestamp: "2026-05-20T10:00:00Z"
                  hash: "a1b2c3d"
                - message: "fix: resolve null pointer in auth flow"
                  author: "paul"
                  timestamp: "2026-05-19T09:00:00Z"
                  hash: "b2c3d4e"
                - message: "wip"
                  author: "paul"
                  timestamp: "2026-05-18T08:00:00Z"
                  hash: "c3d4e5f"
              previous_version: "1.4.2"
              repository:
                url: "https://github.com/org/repo"
                provider: "github"
              options:
                format: "markdown"
                include_ignored: false
      responses:
        '200':
          description: Success or partial result
          headers:
            X-RateLimit-Limit-Minute:
              $ref: '#/components/headers/X-RateLimit-Limit-Minute'
            X-RateLimit-Remaining-Minute:
              $ref: '#/components/headers/X-RateLimit-Remaining-Minute'
            X-RateLimit-Limit-Month:
              $ref: '#/components/headers/X-RateLimit-Limit-Month'
            X-RateLimit-Remaining-Month:
              $ref: '#/components/headers/X-RateLimit-Remaining-Month'
            X-RateLimit-Reset-Minute:
              $ref: '#/components/headers/X-RateLimit-Reset-Minute'
            X-RateLimit-Reset-Month:
              $ref: '#/components/headers/X-RateLimit-Reset-Month'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AnalyzeResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'

  /changelog:
    post:
      tags: [Analysis]
      summary: Generate changelog only
      description: >
        Returns a formatted changelog from the provided commits.
        Does not return a semver bump recommendation.
      operationId: changelog
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnalyzeRequest'
      responses:
        '200':
          description: Success or partial result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChangelogOnlyResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /semver:
    post:
      tags: [Analysis]
      summary: Recommend semver bump only
      description: >
        Returns a semantic version bump recommendation from the provided
        commits. Does not return a formatted changelog.
      operationId: semver
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnalyzeRequest'
      responses:
        '200':
          description: Success or partial result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SemverOnlyResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'

  /formats:
    get:
      tags: [Meta]
      summary: List supported output formats
      operationId: listFormats
      responses:
        '200':
          description: List of supported formats
          content:
            application/json:
              schema:
                type: object
                properties:
                  formats:
                    type: array
                    items:
                      type: string
                    example: ["markdown", "json", "keepachangelog", "slack"]

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >
        API key in the format `sk_live_...` for production or `sk_test_...`
        for sandbox. Keys are generated from your Bumpkit dashboard and
        displayed only once at creation time.

  headers:
    X-RateLimit-Limit-Minute:
      description: Maximum requests allowed per minute for your plan
      schema:
        type: integer
      example: 60
    X-RateLimit-Remaining-Minute:
      description: Requests remaining in the current minute window
      schema:
        type: integer
      example: 43
    X-RateLimit-Limit-Month:
      description: Maximum requests allowed per month for your plan
      schema:
        type: integer
      example: 5000
    X-RateLimit-Remaining-Month:
      description: Requests remaining in the current monthly window
      schema:
        type: integer
      example: 4876
    X-RateLimit-Reset-Minute:
      description: Unix timestamp when the per-minute window resets
      schema:
        type: integer
      example: 1716249660
    X-RateLimit-Reset-Month:
      description: Unix timestamp when the monthly window resets
      schema:
        type: integer
      example: 1717200000

  schemas:
    Commit:
      type: object
      required: [message]
      properties:
        message:
          type: string
          description: The commit message. Required.
          example: "feat: add dark mode toggle"
        author:
          type: string
          description: The commit author. Optional.
          example: "paul"
        timestamp:
          type: string
          format: date-time
          description: ISO 8601 commit timestamp. Optional.
          example: "2026-05-20T10:00:00Z"
        hash:
          type: string
          description: >
            Short or full commit hash. Optional. Used to generate
            deep links to commits when a repository URL is provided.
          example: "a1b2c3d"

    Repository:
      type: object
      required: [url, provider]
      properties:
        url:
          type: string
          format: uri
          description: Full URL of the repository.
          example: "https://github.com/org/repo"
        provider:
          type: string
          enum: [github, gitlab, bitbucket]
          description: Git hosting provider. Used to generate commit deep links.
          example: "github"

    AnalyzeOptions:
      type: object
      properties:
        format:
          type: string
          enum: [markdown, json, keepachangelog, slack]
          default: markdown
          description: Output format for the formatted changelog string.
        include_ignored:
          type: boolean
          default: false
          description: >
            Whether to include low-signal ignored commits in the response.
            Useful for debugging commit quality.

    AnalyzeRequest:
      type: object
      required: [commits]
      properties:
        commits:
          type: array
          minItems: 1
          maxItems: 250
          items:
            $ref: '#/components/schemas/Commit'
          description: >
            Array of commit objects. Minimum 1, maximum 250 per request.
        previous_version:
          type: string
          description: >
            The current version in valid semver format (e.g. "1.4.2").
            If omitted, defaults to "0.0.0" and a warning is returned.
          example: "1.4.2"
        repository:
          $ref: '#/components/schemas/Repository'
        options:
          $ref: '#/components/schemas/AnalyzeOptions'

    ChangelogEntry:
      type: object
      properties:
        message:
          type: string
          example: "add dark mode toggle"
        hash:
          type: string
          example: "a1b2c3d"
        author:
          type: string
          example: "paul"
        timestamp:
          type: string
          format: date-time
          example: "2026-05-20T10:00:00Z"
        url:
          type: string
          format: uri
          description: >
            Deep link to the commit. Only present when repository
            details were provided in the request.
          example: "https://github.com/org/repo/commit/a1b2c3d"

    UncategorizedEntry:
      type: object
      properties:
        message:
          type: string
          example: "wip"
        hash:
          type: string
          example: "c3d4e5f"
        reason:
          type: string
          example: "insufficient signal"

    ChangelogSections:
      type: object
      properties:
        breaking:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        added:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        changed:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        fixed:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        deprecated:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        removed:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        security:
          type: array
          items:
            $ref: '#/components/schemas/ChangelogEntry'
        uncategorized:
          type: array
          description: >
            Low-signal commits that could not be categorized.
            Only present when status is "partial".
          items:
            $ref: '#/components/schemas/UncategorizedEntry'

    Changelog:
      type: object
      properties:
        formatted:
          type: string
          description: >
            Human-readable changelog string in the requested format.
          example: "## [1.5.0] - 2026-05-20\n### Added\n- Dark mode toggle\n### Fixed\n- Null pointer in auth flow"
        sections:
          $ref: '#/components/schemas/ChangelogSections'

    Version:
      type: object
      properties:
        previous:
          type: string
          nullable: true
          example: "1.4.2"
        suggested:
          type: string
          example: "1.5.0"
        bump:
          type: string
          enum: [major, minor, patch]
          example: "minor"
        reasoning:
          type: string
          example: "2 new features added, 3 bugs fixed, no breaking changes detected"

    Meta:
      type: object
      properties:
        commits_received:
          type: integer
          example: 8
        commits_used:
          type: integer
          example: 7
        commits_ignored:
          type: integer
          example: 1
        warnings:
          type: array
          items:
            type: string
          example: ["No previous_version provided. Defaulted to 0.0.0."]

    AnalyzeResponse:
      type: object
      properties:
        status:
          type: string
          enum: [success, partial]
          example: "success"
        confidence:
          type: number
          format: float
          minimum: 0
          maximum: 1
          example: 0.92
        version:
          $ref: '#/components/schemas/Version'
        changelog:
          $ref: '#/components/schemas/Changelog'
        meta:
          $ref: '#/components/schemas/Meta'

    ChangelogOnlyResponse:
      type: object
      properties:
        status:
          type: string
          enum: [success, partial]
        confidence:
          type: number
          format: float
        changelog:
          $ref: '#/components/schemas/Changelog'
        meta:
          $ref: '#/components/schemas/Meta'

    SemverOnlyResponse:
      type: object
      properties:
        status:
          type: string
          enum: [success, partial]
        confidence:
          type: number
          format: float
        version:
          $ref: '#/components/schemas/Version'
        meta:
          $ref: '#/components/schemas/Meta'

    ErrorResponse:
      type: object
      properties:
        status:
          type: string
          enum: [error]
          example: "error"
        confidence:
          type: integer
          enum: [0]
          example: 0
        error:
          type: object
          properties:
            code:
              type: string
              example: "INVALID_VERSION_FORMAT"
            message:
              type: string
              example: "The provided previous_version '1.4.x' is not valid semver."
            field:
              type: string
              nullable: true
              description: The request field that caused the error, if applicable.
              example: "previous_version"
            suggestion:
              type: string
              example: "Use a valid semver string e.g. '1.4.2'. See https://semver.org"
        meta:
          $ref: '#/components/schemas/Meta'

  responses:
    BadRequest:
      description: Invalid request body or parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            MISSING_COMMITS:
              value:
                status: error
                confidence: 0
                error:
                  code: MISSING_COMMITS
                  message: "The commits field is required."
                  field: commits
                  suggestion: "Provide an array of commit objects with at least one entry."
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []
            INVALID_VERSION_FORMAT:
              value:
                status: error
                confidence: 0
                error:
                  code: INVALID_VERSION_FORMAT
                  message: "The provided previous_version '1.4.x' is not valid semver."
                  field: previous_version
                  suggestion: "Use a valid semver string e.g. '1.4.2'. See https://semver.org"
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []
            COMMITS_LIMIT_EXCEEDED:
              value:
                status: error
                confidence: 0
                error:
                  code: COMMITS_LIMIT_EXCEEDED
                  message: "Request contains 312 commits. Maximum allowed per request is 250."
                  field: commits
                  suggestion: "Split large releases into multiple requests or upgrade to an Enterprise plan for higher limits."
                meta:
                  commits_received: 312
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []

    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            MISSING_API_KEY:
              value:
                status: error
                confidence: 0
                error:
                  code: MISSING_API_KEY
                  message: "No API key provided. Include your key in the x-api-key header."
                  field: null
                  suggestion: "Generate a key at https://bumpkit.dev/dashboard"
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []
            REVOKED_API_KEY:
              value:
                status: error
                confidence: 0
                error:
                  code: REVOKED_API_KEY
                  message: "This API key has been revoked."
                  field: null
                  suggestion: "Generate a new key at https://bumpkit.dev/dashboard"
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []

    UnprocessableEntity:
      description: Valid request but insufficient signal to process
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            confidence: 0
            error:
              code: INSUFFICIENT_SIGNAL
              message: "No usable commits found. All 12 commits had insufficient signal to generate a changelog."
              field: commits
              suggestion: "Adopt Conventional Commits format for reliable results. See https://conventionalcommits.org"
            meta:
              commits_received: 12
              commits_used: 0
              commits_ignored: 12
              warnings: []

    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Reset-Minute:
          $ref: '#/components/headers/X-RateLimit-Reset-Minute'
        X-RateLimit-Reset-Month:
          $ref: '#/components/headers/X-RateLimit-Reset-Month'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          examples:
            RATE_LIMIT_EXCEEDED:
              value:
                status: error
                confidence: 0
                error:
                  code: RATE_LIMIT_EXCEEDED
                  message: "Minute rate limit reached. 60 requests allowed per minute."
                  field: null
                  suggestion: "Retry after 1716249660. Consider batching commits to reduce call frequency."
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []
            MONTHLY_LIMIT_EXCEEDED:
              value:
                status: error
                confidence: 0
                error:
                  code: MONTHLY_LIMIT_EXCEEDED
                  message: "Monthly limit reached. Upgrade your plan for more requests."
                  field: null
                  suggestion: "Upgrade at https://bumpkit.dev/pricing"
                meta:
                  commits_received: 0
                  commits_used: 0
                  commits_ignored: 0
                  warnings: []

    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            confidence: 0
            error:
              code: INTERNAL_ERROR
              message: "Something went wrong on our end. Please try again."
              field: null
              suggestion: "If this persists, contact support at https://bumpkit.dev/support"
            meta:
              commits_received: 0
              commits_used: 0
              commits_ignored: 0
              warnings: []

    ServiceUnavailable:
      description: Service temporarily unavailable
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            status: error
            confidence: 0
            error:
              code: SERVICE_UNAVAILABLE
              message: "Bumpkit is temporarily unavailable. Please try again shortly."
              field: null
              suggestion: "Check status at https://status.bumpkit.dev"
            meta:
              commits_received: 0
              commits_used: 0
              commits_ignored: 0
              warnings: []
