openapi: 3.1.0
info:
  title: TRT.GE API
  description: |
    Testosterone Replacement Therapy (TRT) and Estradiol (E2) Pharmacokinetic Simulator API.
    
    **Educational model only. Not medical advice.**
    
    This API provides programmatic access to the TRT.GE simulation engine, allowing:
    - Single and batch simulations
    - Personalization via calibration
    - Time-series T and E2 predictions
    - Summary statistics and risk bands
    
    ## Authentication
    
    All endpoints require an API key in the `Authorization` header:
    ```
    Authorization: Bearer trt_live_xxx...
    ```
    
    ## Rate Limits
    
    | Tier  | RPM | Batch Limit |
    |-------|-----|-------------|
    | Free  | 10  | N/A         |
    | Pro   | 100 | 10          |
    | Clinic| 1000| 100         |
    
    ## Versioning
    
    - API version in URL path: `/v1/...`
    - Engine version in response: `engineVersion`
  version: 1.0.0
  contact:
    name: TRT.GE Support
    url: https://trt.ge
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.trt.ge/v1
    description: Production
  - url: http://localhost:8787/v1
    description: Local development

tags:
  - name: simulation
    description: TRT/E2 simulation endpoints
  - name: calibration
    description: Personalization endpoints
  - name: meta
    description: API metadata

paths:
  /simulate:
    post:
      tags: [simulation]
      summary: Run a single simulation
      description: Execute a TRT/E2 simulation with the provided parameters
      operationId: simulate
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SimulationInput'
            examples:
              cypionate_weekly:
                summary: Weekly Cypionate IM
                value:
                  sex: male
                  injectionMethod: im
                  dose: 120
                  freq: 7
                  duration: 84
                  weight: 80
                  activeEster: cypionate
                  hcg:
                    enabled: false
                    dose: 250
                    freq: 3.5
                  fat: 18
                  genes:
                    cyp: slow
                    shbg: high
                  geneMult: 1.0
                  aiMult: 1.0
                  responderManual: 1.0
                  compounds:
                    primo: { enabled: false, dose: 200 }
                    mast: { enabled: false, dose: 200 }
                    eq: { enabled: false, dose: 200 }
                  calibration:
                    enabled: false
                    factors: null
              cypionate_subq:
                summary: SubQ Cypionate E3.5D
                value:
                  sex: male
                  injectionMethod: subq
                  dose: 60
                  freq: 3.5
                  duration: 84
                  weight: 80
                  activeEster: cypionate
                  hcg: { enabled: false, dose: 0, freq: 3.5 }
                  fat: 18
                  genes: { cyp: slow, shbg: high }
                  geneMult: 1.0
                  aiMult: 1.0
                  responderManual: 1.0
                  compounds:
                    primo: { enabled: false, dose: 200 }
                    mast: { enabled: false, dose: 200 }
                    eq: { enabled: false, dose: 200 }
                  calibration: { enabled: false, factors: null }
      responses:
        '200':
          description: Successful simulation
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SimulationResult'
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnauthorizedError'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /simulate/batch:
    post:
      tags: [simulation]
      summary: Run multiple simulations
      description: Execute multiple simulations in a single request (Pro+ tiers only)
      operationId: simulateBatch
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchSimulationRequest'
      responses:
        '200':
          description: Batch results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchSimulationResult'
        '403':
          description: Batch not available for tier
        '429':
          description: Rate limit exceeded

  /calibrate:
    post:
      tags: [calibration]
      summary: Compute calibration factors
      description: Calculate personalized response factors from lab measurements
      operationId: calibrate
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CalibrationInput'
            examples:
              standard:
                summary: Standard calibration
                value:
                  dose: 120
                  freq: 7
                  ester: cypionate
                  weight: 80
                  labTiming: 1.0
                  labT: 650
                  labE2: 32
                  labFat: 18
                  injectionMethod: im
                  hcg: { enabled: false, dose: 0, freq: 3.5 }
      responses:
        '200':
          description: Calibration factors computed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalibrationResult'

  /meta:
    get:
      tags: [meta]
      summary: API metadata
      description: Get supported esters, bounds, and capabilities
      operationId: getMeta
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MetaResponse'

  /health:
    get:
      tags: [meta]
      summary: Health check
      description: Uptime monitoring endpoint
      operationId: getHealth
      responses:
        '200':
          description: Healthy
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HealthResponse'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API key with prefix "trt_live_" or "trt_test_"

  schemas:
    SimulationInput:
      type: object
      required:
        - sex
        - injectionMethod
        - dose
        - freq
        - duration
        - weight
        - activeEster
        - hcg
        - fat
        - genes
        - geneMult
        - aiMult
        - responderManual
        - compounds
      properties:
        sex:
          type: string
          enum: [male, female]
        injectionMethod:
          type: string
          enum: [im, subq]
        dose:
          type: number
          minimum: 0
          maximum: 2000
          description: Dose in mg
        freq:
          type: number
          minimum: 0.1
          maximum: 365
          description: Injection frequency in days
        duration:
          type: number
          minimum: 7
          maximum: 365
          description: Simulation duration in days
        weight:
          type: number
          minimum: 30
          maximum: 300
          description: Body weight in kg
        activeEster:
          type: string
          enum: [propionate, enanthate, cypionate, sustanon, undecanoate, undecanoate_castor]
        hcg:
          $ref: '#/components/schemas/HCGConfig'
        fat:
          type: number
          minimum: 3
          maximum: 60
          description: Body fat percentage
        genes:
          $ref: '#/components/schemas/Genes'
        geneMult:
          type: number
          minimum: 0.1
          description: Gene multiplier override
        aiMult:
          type: number
          minimum: 0.1
          description: AI effect multiplier
        responderManual:
          type: number
          minimum: 0.1
          description: Manual responder factor
        compounds:
          $ref: '#/components/schemas/Compounds'
        calibration:
          $ref: '#/components/schemas/Calibration'
        options:
          $ref: '#/components/schemas/SimulationOptions'

    HCGConfig:
      type: object
      required: [enabled, dose, freq]
      properties:
        enabled:
          type: boolean
        dose:
          type: number
          minimum: 0
        freq:
          type: number
          minimum: 0.1

    Genes:
      type: object
      required: [cyp, shbg]
      properties:
        cyp:
          type: string
          enum: [slow, fast]
        shbg:
          type: string
          enum: [high, low]

    Compounds:
      type: object
      properties:
        primo:
          $ref: '#/components/schemas/CompoundConfig'
        mast:
          $ref: '#/components/schemas/CompoundConfig'
        eq:
          $ref: '#/components/schemas/CompoundConfig'

    CompoundConfig:
      type: object
      required: [enabled, dose]
      properties:
        enabled:
          type: boolean
        dose:
          type: number
          minimum: 0

    Calibration:
      type: object
      properties:
        enabled:
          type: boolean
        factors:
          $ref: '#/components/schemas/CalibrationFactors'

    CalibrationFactors:
      type: object
      properties:
        tResponse:
          type: number
        baseE2Ratio:
          type: number
        baselineFatMod:
          type: number
        baselineGeneMult:
          type: number
        hcgTMax:
          type: number
        hcgED50:
          type: number

    SimulationOptions:
      type: object
      properties:
        timeStepDays:
          type: number
          default: 0.2
        includeNoise:
          type: boolean
          default: true
        seed:
          type: number
          default: 1337
        includeUncertaintyBand:
          type: boolean
          default: true

    DataPoint:
      type: object
      properties:
        x:
          type: number
        y:
          type: number

    ConfidenceBand:
      type: object
      properties:
        lower:
          type: array
          items:
            $ref: '#/components/schemas/DataPoint'
        upper:
          type: array
          items:
            $ref: '#/components/schemas/DataPoint'

    SimulationSummary:
      type: object
      properties:
        peakT:
          type: number
        troughT:
          type: number
        avgT:
          type: number
        steadyDay:
          type: number
          nullable: true
        peakE2:
          type: number
        avgE2:
          type: number
        riskBand:
          type: string
          enum: [Low, Optimal, High, Excessive]
        weeklyLoadMg:
          type: number
        weeklyActiveMg:
          type: number

    SimulationResult:
      type: object
      properties:
        engineVersion:
          type: string
        tCurve:
          type: array
          items:
            $ref: '#/components/schemas/DataPoint'
        e2Curve:
          type: array
          items:
            $ref: '#/components/schemas/DataPoint'
        tBand:
          $ref: '#/components/schemas/ConfidenceBand'
        e2Band:
          $ref: '#/components/schemas/ConfidenceBand'
        summary:
          $ref: '#/components/schemas/SimulationSummary'
        warnings:
          type: array
          items:
            type: string
        requestId:
          type: string

    CalibrationInput:
      type: object
      required:
        - dose
        - freq
        - ester
        - weight
        - labTiming
        - labT
        - labE2
        - labFat
        - injectionMethod
      properties:
        dose:
          type: number
        freq:
          type: number
        ester:
          type: string
        weight:
          type: number
        labTiming:
          type: number
          description: Days before next injection when labs were drawn
        labT:
          type: number
          description: Measured total testosterone in ng/dL
        labE2:
          type: number
          description: Measured estradiol in pg/mL
        labFat:
          type: number
          description: Body fat percentage at time of labs
        injectionMethod:
          type: string
          enum: [im, subq]
        hcg:
          $ref: '#/components/schemas/HCGConfig'

    CalibrationResult:
      type: object
      properties:
        factors:
          $ref: '#/components/schemas/CalibrationFactors'
        warnings:
          type: array
          items:
            type: string
        clamped:
          type: boolean
        clampMessage:
          type: string
        requestId:
          type: string

    BatchSimulationRequest:
      type: object
      required: [items]
      properties:
        items:
          type: array
          maxItems: 100
          items:
            type: object
            required: [id, input]
            properties:
              id:
                type: string
              input:
                $ref: '#/components/schemas/SimulationInput'

    BatchSimulationResult:
      type: object
      properties:
        results:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
              success:
                type: boolean
              result:
                $ref: '#/components/schemas/SimulationResult'
              error:
                type: string
        requestId:
          type: string

    MetaResponse:
      type: object
      properties:
        engineVersion:
          type: string
        apiVersion:
          type: string
        supportedEsters:
          type: array
          items:
            type: object
            properties:
              key: { type: string }
              name: { type: string }
              description: { type: string }
        supportedSexes:
          type: array
          items:
            type: object
            properties:
              key: { type: string }
              label: { type: string }
              ref: { type: string }
        bounds:
          type: object
        features:
          type: object
          properties:
            batchSimulation: { type: boolean }
            calibration: { type: boolean }
            uncertaintyBands: { type: boolean }

    HealthResponse:
      type: object
      properties:
        status:
          type: string
          enum: [ok, degraded, down]
        engineVersion:
          type: string
        timestamp:
          type: string
          format: date-time
        uptime:
          type: number

    ValidationError:
      type: object
      properties:
        error:
          type: string
          example: validation_error
        message:
          type: string
        details:
          type: array
          items:
            type: object
            properties:
              field: { type: string }
              message: { type: string }

    UnauthorizedError:
      type: object
      properties:
        error:
          type: string
          example: unauthorized
        message:
          type: string

    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: rate_limit_exceeded
        message:
          type: string
        retryAfter:
          type: number
