openapi: 3.0.3
info:
  title: SwiftLynx API
  version: "1.0"
  description: >
    Public API for SwiftLynx. OAuth 2.0 (Authorization Code). JSON responses.
servers:
  - url: https://swiftlynx.ai
paths:
  /api/oauth/authorize:
    get:
      summary: OAuth authorization endpoint (browser)
      parameters:
        - in: query
          name: client_id
          required: true
          schema: { type: string }
        - in: query
          name: redirect_uri
          required: true
          schema: { type: string, format: uri }
        - in: query
          name: state
          required: false
          schema: { type: string }
        - in: query
          name: code_challenge
          required: false
          schema: { type: string }
        - in: query
          name: code_challenge_method
          required: false
          schema: { type: string, default: S256 }
      responses:
        '302':
          description: Redirect back with ?code=...
  /api/oauth/token:
    post:
      summary: Exchange authorization code or refresh token
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  enum: [authorization_code, refresh_token]
                code: { type: string }
                redirect_uri: { type: string, format: uri }
                refresh_token: { type: string }
                code_verifier: { type: string }
                client_id: { type: string }
      responses:
        '200':
          description: Access and refresh tokens
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token: { type: string }
                  token_type: { type: string, example: Bearer }
                  expires_in: { type: integer, example: 3600 }
                  refresh_token: { type: string }
        '4XX': { description: Error }
        '5XX': { description: Server error }
  /api/me:
    get:
      summary: Validate token and get account info
      security: [{ bearerAuth: [] }]
      responses:
        '200':
          description: Account summary
          content:
            application/json:
              schema:
                type: object
                properties:
                  email: { type: string, format: email }
                  plan: { type: string, example: free }
                  creditsRemaining: { type: integer }
        '401': { description: Invalid token }
  /api/analyze:
    post:
      summary: Analyze a resume against a job description
      security: [{ bearerAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                jobTitle: { type: string }
                jobDescription: { type: string }
                jobDescriptionUrl: { type: string, format: uri }
                resumeText: { type: string }
                resumeUrl: { type: string, format: uri }
                candidateName: { type: string }
                fileName: { type: string }
              anyOf:
                - required: [jobDescription, resumeText]
                - required: [jobDescriptionUrl, resumeUrl]
      responses:
        '200':
          description: Analysis result
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId: { type: string }
                  matchScore: { type: integer, minimum: 0, maximum: 100 }
                  strengths:
                    type: array
                    items: { type: string }
                  risks:
                    type: array
                    items: { type: string }
                  summary: { type: string }
                  recommendation: { type: string }
                  scoreExplanation: { type: string }
        '401': { description: Invalid token }
        '402': { description: Insufficient credits }
        '4XX': { description: Validation error }
  /api/analyses/{id}:
    get:
      summary: Retrieve a stored analysis record
      security: [{ bearerAuth: [] }]
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Analysis record
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404': { description: Not found }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
