openapi: 3.0.0
info:
  title: AgentLedger Compliance Scanner API
  version: 1.0.0
  description: |
    EU AI Act compliance scanning and agent risk assessment API.
    
    The AgentLedger API provides three core workflows:
    1. **Scan API** — Anonymous risk classification for AI systems (no auth required)
    2. **Agents API** — Register and manage AI agents with continuous risk monitoring
    3. **Decisions API** — Log and audit AI decision outputs for compliance tracking
    
    ## Risk Score Calculation
    
    ### Agent-Level Risk Score (0–99)
    The agent risk score is calculated via `classifyAgentRisk()` in the Agent Risk module:
    
    - **Base factors:**
      - `q2_human_impact = "high"`: +25 points
      - `q2_human_impact = "medium"`: +10 points
      - `q3_autonomy = "fully_autonomous"`: +20 points
      - `q3_autonomy = "semi_autonomous"`: +10 points
    
    - **Data sensitivity:** Each sensitive data type (biometric, health, financial, criminal, political, religious, ethnic) adds +8 points (max 24)
    
    - **Human oversight:** Missing human oversight adds +15 points
    
    - **Affected persons:** High-risk groups (job applicants, employees, students, loan applicants, patients, suspects, asylum seekers, benefits applicants) add +20 points
    
    - **High-risk sector** (HR, hiring, employment, education, credit, insurance, law enforcement, border control, critical infrastructure, judiciary, healthcare, medical): +20 points
    
    - **Non-reversible decisions:** +10 points
    
    - **Score mapping to risk class:**
      - 0–34: `minimal`
      - 35–69: `limited`
      - 70–99: `high`
      - 100: `unacceptable` (Article 5 — Prohibited AI Practices)
    
    ### Decision-Level Risk Score (0–1.0)
    Decision-level risk is calculated independently from agent risk:
    
    ```
    score = base_score + confidence_penalty + review_penalty
    ```
    
    Where:
    - **base_score:** Derived from agent's risk_class (minimal: 0.1, limited: 0.4, high: 0.7, unacceptable: 1.0)
    - **confidence_penalty:** +0.2 if confidence < 0.7
    - **review_penalty:** +0.1 if human_reviewed = false
    - **Final score:** Capped at 1.0
    
    ## Human Review Statuses
    - `human_reviewed = true`: Decision was reviewed by a human
    - `human_reviewed = false`: Decision was made autonomously
    - `risk_flag = true`: Flagged for review (high-risk agent + high confidence + no human review)
    
    ## Confidence Levels
    - Range: 0.0–1.0 (decimal)
    - Values < 0.7 are considered "low confidence" and trigger additional review
    - Optional in API (defaults to null)
    
    ## EU AI Act Article Mapping
    
    | Article | Rule | When Applied |
    |---------|------|--------------|
    | Article 5 | Prohibited AI Practice | Any prohibited purpose (social scoring, emotion recognition, real-time biometric, subliminal manipulation, exploitation) |
    | Article 10 | Data and Data Governance | Any sensitive data type is processed |
    | Article 14 | Human Oversight | No human oversight mechanism configured |
    | Annex III | High-Risk AI System | Agent in high-risk sector or affects high-risk persons |
    | Article 9 | Risk Management System | Risk score ≥ 70 |
    | Article 11 | Technical Documentation | Risk score ≥ 70 |
    | Article 13 | Transparency and Provision of Information | Risk score ≥ 70 |
    | Article 17 | Quality Management System | Risk score ≥ 70 |
    | Article 51 | EU AI Act Database Registration | Risk score ≥ 70 (high-risk) |
    | Article 52 | Transparency Obligations (Limited-Risk) | Risk score 35–69 |
    | Article 3 | Definitions (EU Operated) | EU deployment flag set |
  
  ## Webhook Configuration
  
  Users can configure webhooks to receive real-time notifications when high-risk events occur.
  
  **Endpoints:**
  - `GET /api/v1/account/webhooks` — Retrieve webhook configuration
  - `POST /api/v1/account/webhooks` — Save or update webhook URL and secret
  - `DELETE /api/v1/account/webhooks` — Remove webhook configuration
  
  **Webhook Events Sent:**
  
  Events are sent as POST requests with JSON body to the configured webhook URL.
  
  ### Event: decision.high_risk
  
  Triggered when a new decision is logged with `risk_score > 70`.
  
  ```json
  {
    "type": "decision.high_risk",
    "timestamp": "2026-04-03T12:34:56Z",
    "account_id": "acc_...",
    "data": {
      "decision_id": "dec_...",
      "agent_id": "agt_...",
      "risk_score": 85,
      "confidence": 0.92
    }
  }
  ```
  
  ### Event: scan.high_risk
  
  Triggered when a new scan is created with `risk_class = "high"` or `"critical"`.
  
  ```json
  {
    "type": "scan.high_risk",
    "timestamp": "2026-04-03T12:34:56Z",
    "account_id": "acc_...",
    "data": {
      "scan_id": "scan_...",
      "risk_class": "high",
      "risk_score": 75
    }
  }
  ```
  
  **Security:**
  
  - All webhook requests include an `X-Webhook-Signature` header with HMAC-SHA256 signature
  - Signature is computed using the webhook secret you provide
  - Signature format: `hex(HMAC-SHA256(secret, request_body))`
  - Validate the signature before processing the event
  - All webhook URLs must be HTTPS and cannot point to localhost or private IP ranges (SSRF protection)
  
  contact:
    name: AgentLedger Support
    url: https://agentledgerhq.com
  license:
    name: Proprietary
    url: https://agentledgerhq.com/terms.html

servers:
  - url: https://agentledger.dev/api
    description: Production API
  - url: https://localhost:8787/api
    description: Local development

## Rate Limiting

All API endpoints enforce rate limiting based on your subscription plan. Rate limits reset hourly.

### Rate Limits by Plan

| Plan | Requests/Hour |
|------|---------------|
| Free | 100 |
| Starter | 1,000 |
| Professional | 10,000 |
| Enterprise | 100,000 |

### Rate Limit Headers

Every API response includes three headers:

- **X-RateLimit-Limit** — Maximum requests allowed in the current hour
- **X-RateLimit-Remaining** — Number of requests remaining in the current window
- **X-RateLimit-Reset** — Unix timestamp (seconds) when the rate limit window resets

**Example response headers:**
```
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1712145600
```

### Rate Limit Exceeded (429)

When your rate limit is exceeded, the API returns a 429 status with:

```json
{
  "error": "rate_limit_exceeded",
  "message": "Rate limit of 1000 requests per hour exceeded",
  "retry_after": 3600
}
```

The `retry_after` field indicates seconds to wait before retrying.

### Best Practices

- **Monitor headers** — Check `X-RateLimit-Remaining` to know when you're approaching the limit
- **Implement backoff** — Use exponential backoff when you receive 429 responses
- **Cache responses** — Avoid redundant requests by caching results
- **Upgrade plan** — If you consistently hit limits, consider upgrading to a higher tier

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: al_live_* or al_test_*
      description: |
        AgentLedger API key prefixed with `al_live_` (production) or `al_test_` (testing).
        Include in Authorization header: `Bearer <your-api-key>`

  schemas:
    ScanAnswers:
      type: object
      required:
        - q1_purpose
        - q2_human_impact
        - q3_autonomy
        - q4_data_types
        - q5_human_oversight
        - q6_affected_persons
        - q7_eu_operated
        - q8_reversible
        - q9_sector
        - q10_existing_registration
      properties:
        q1_purpose:
          type: string
          description: Primary purpose of the AI system
          example: "hiring"
        q2_human_impact:
          type: string
          enum: [high, medium, low]
          description: Level of impact on human autonomy and rights
        q3_autonomy:
          type: string
          description: Autonomy level (converted from hyphenated to underscore format)
          enum: [human_in_loop, semi_autonomous, fully_autonomous]
        q4_data_types:
          type: array
          items:
            type: string
          description: Data types processed (e.g., biometric, health, financial, criminal, political, religious, ethnic)
          example: ["biometric", "health"]
        q5_human_oversight:
          type: boolean
          description: Whether human oversight mechanism is in place
        q6_affected_persons:
          type: string
          description: Category of persons affected by the AI system
          example: "job_applicants"
        q7_eu_operated:
          type: boolean
          description: Whether the system operates in the EU
        q8_reversible:
          type: boolean
          description: Whether AI decisions can be reversed by humans
        q9_sector:
          type: string
          description: Business sector (e.g., hr, hiring, employment, education, credit, insurance, law_enforcement, healthcare)
        q10_existing_registration:
          type: boolean
          description: Whether the system is already registered in the EU AI Act database

    RiskResult:
      type: object
      properties:
        risk_class:
          type: string
          enum: [unacceptable, high, limited, minimal]
          description: |
            Risk classification per EU AI Act:
            - `unacceptable`: Article 5 — Prohibited AI Practices
            - `high`: Annex III — High-Risk AI System
            - `limited`: Limited-Risk AI System (transparency obligations)
            - `minimal`: Minimal-Risk AI System (no specific requirements)
        risk_score:
          type: integer
          minimum: 0
          maximum: 99
          description: Numerical risk score (0–99). See "Risk Score Calculation" in description.
        eu_ai_act_classification:
          type: string
          description: Human-readable EU AI Act classification string
          example: "Annex III — High-Risk AI System"
        applicable_articles:
          type: array
          items:
            type: string
          description: List of applicable EU AI Act articles
          example: ["Article 9 — Risk Management System", "Article 10 — Data and Data Governance"]
        action_plan:
          type: array
          items:
            $ref: '#/components/schemas/ActionItem'

    ActionItem:
      type: object
      properties:
        priority:
          type: integer
          description: Priority order (1 = highest)
        action:
          type: string
          description: Specific action to take for compliance
        deadline:
          type: string
          description: Deadline for action (e.g., "Immediately", "Within 30 days")
        article:
          type: string
          description: Associated EU AI Act article

    Agent:
      type: object
      required:
        - name
        - description
        - type
        - autonomy_level
        - decision_types
        - data_processed
        - human_oversight
      properties:
        id:
          type: string
          description: Unique agent identifier (format: agent_*)
        name:
          type: string
          maxLength: 100
          description: Agent name
        description:
          type: string
          maxLength: 500
          description: Agent description
        type:
          type: string
          enum: [conversational, decision, automation, classification, generative, other]
          description: Agent type/capability
        autonomy_level:
          type: string
          enum: [human-in-loop, semi-autonomous, fully-autonomous]
          description: Operational autonomy level
        decision_types:
          type: array
          items:
            type: string
          description: Types of decisions made by the agent (e.g., "hiring", "credit", "hiring_rejection")
        data_processed:
          type: array
          items:
            type: string
          description: Data types processed (biometric, health, financial, criminal, political, religious, ethnic, etc.)
        human_oversight:
          type: boolean
          description: Whether human oversight is implemented
        deployment_environment:
          type: string
          enum: [development, staging, production]
          default: production
          description: Deployment environment
        metadata:
          type: object
          description: Optional custom metadata
        risk_class:
          type: string
          enum: [unacceptable, high, limited, minimal]
          description: Agent risk classification
        risk_score:
          type: integer
          minimum: 0
          maximum: 99
          description: Agent risk score (0–99)
        eu_ai_act_articles:
          type: array
          items:
            type: string
          description: Applicable EU AI Act articles
        compliance_status:
          type: string
          enum: [compliant, non_compliant, pending]
          description: Compliance status
        created_at:
          type: string
          format: date-time
          description: Agent registration timestamp
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp

    Decision:
      type: object
      required:
        - agent_id
        - decision_type
        - input_summary
        - output_summary
      properties:
        id:
          type: string
          description: Unique decision identifier (format: dec_*)
        agent_id:
          type: string
          description: Associated agent ID
        decision_type:
          type: string
          maxLength: 100
          description: Type of decision (e.g., "hiring", "credit_approval")
        input_summary:
          type: string
          maxLength: 1000
          description: Summary of input data to the AI system
        output_summary:
          type: string
          maxLength: 1000
          description: Summary of the AI output/decision
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: |
            Model confidence level (0.0–1.0). 
            Values < 0.7 are considered "low confidence".
          nullable: true
        human_reviewed:
          type: boolean
          description: Whether the decision was reviewed by a human
        risk_score:
          type: number
          minimum: 0
          maximum: 1
          description: |
            Decision-level risk score (0.0–1.0).
            Calculated as: base_score (from agent risk_class) + confidence_penalty + review_penalty.
            See "Risk Score Calculation" in description.
        risk_factors:
          type: array
          items:
            type: string
          description: Factors contributing to the risk score
          example: ["risk_class:high", "low_confidence", "no_human_review"]
        risk_flag:
          type: boolean
          description: |
            Flagged for human review if: agent is high-risk AND confidence > 0.9 AND human_reviewed = false.
            Triggers `decision.risk_flagged` webhook.
        context:
          type: object
          description: Optional contextual metadata
        audit_hash:
          type: string
          description: SHA256 hash for audit trail integrity
        logged_at:
          type: string
          format: date-time
          description: Decision logging timestamp

    ComplianceChangelog:
      type: object
      properties:
        id:
          type: string
        date:
          type: string
          format: date
        title:
          type: string
        summary:
          type: string
        articles:
          type: array
          items:
            type: string
        impact:
          type: string
          enum: [high, medium, low]
        action_required:
          type: string

    Error:
      type: object
      properties:
        error:
          type: string
          description: Error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          description: Additional error details (validation errors, etc.)

paths:
  /v1/scans:
    post:
      summary: Scan AI system for EU AI Act compliance
      operationId: createScan
      description: |
        Classify an AI system's risk level based on questionnaire answers.
        **No authentication required** — public endpoint.
        
        If API key is provided (Bearer token), the scan is logged to your account.
        Without API key, the scan result is returned but not stored.
      tags:
        - Scans
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [answers]
              properties:
                answers:
                  $ref: '#/components/schemas/ScanAnswers'
            examples:
              minimal_risk:
                summary: Minimal-risk system
                value:
                  answers:
                    q1_purpose: "email_filtering"
                    q2_human_impact: "low"
                    q3_autonomy: "semi_autonomous"
                    q4_data_types: []
                    q5_human_oversight: true
                    q6_affected_persons: "unknown"
                    q7_eu_operated: true
                    q8_reversible: true
                    q9_sector: "other"
                    q10_existing_registration: false
              high_risk:
                summary: High-risk HR system
                value:
                  answers:
                    q1_purpose: "hiring"
                    q2_human_impact: "high"
                    q3_autonomy: "fully_autonomous"
                    q4_data_types: ["biometric", "health"]
                    q5_human_oversight: false
                    q6_affected_persons: "job_applicants"
                    q7_eu_operated: true
                    q8_reversible: false
                    q9_sector: "hr"
                    q10_existing_registration: false
      responses:
        '200':
          description: Scan completed successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  scan_id:
                    type: string
                    description: Unique scan identifier
                  risk_class:
                    type: string
                  risk_score:
                    type: integer
                  eu_ai_act_classification:
                    type: string
                  applicable_articles:
                    type: array
                    items:
                      type: string
                  action_plan:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActionItem'
                  report_available:
                    type: boolean
                    description: True if API key was provided and scan was logged
                  report_url:
                    type: string
                    nullable: true
                    description: URL to view scan report (if logged to account)
                  upgrade_url:
                    type: string
                    nullable: true
                    description: Upgrade/signup URL (if not authenticated)
                  scanned_at:
                    type: string
                    format: date-time
              examples:
                minimal:
                  value:
                    scan_id: "scan_8b3f9x1k"
                    risk_class: "minimal"
                    risk_score: 15
                    eu_ai_act_classification: "Minimal-Risk AI System — No Specific Requirements"
                    applicable_articles: ["Article 3 — Definitions (applicable to EU operators)"]
                    action_plan: []
                    report_available: false
                    report_url: null
                    upgrade_url: "https://agentledgerhq.com/#pricing"
                    scanned_at: "2026-03-31T15:52:00Z"
                high_risk:
                  value:
                    scan_id: "scan_9k2x7l4m"
                    risk_class: "high"
                    risk_score: 82
                    eu_ai_act_classification: "Annex III — High-Risk AI System"
                    applicable_articles:
                      - "Article 9 — Risk Management System"
                      - "Article 10 — Data and Data Governance"
                      - "Article 11 — Technical Documentation"
                      - "Article 13 — Transparency and Provision of Information"
                      - "Article 14 — Human Oversight"
                      - "Article 17 — Quality Management System"
                      - "Article 51"
                      - "Article 3 — Definitions (applicable to EU operators)"
                    action_plan:
                      - priority: 1
                        action: "Register AI system in EU AI Act database (Article 51)"
                        deadline: "Before deployment"
                        article: "Article 51"
                      - priority: 1
                        action: "Implement human oversight mechanism with ability to override AI decisions"
                        deadline: "Before deployment in EU"
                        article: "Article 14"
                      - priority: 2
                        action: "Document processing of sensitive data: biometric, health. Conduct DPIA if not done."
                        deadline: "Within 30 days"
                        article: "Article 10"
                    report_available: true
                    report_url: "https://agentledgerhq.com/reports/scan_9k2x7l4m"
                    upgrade_url: null
                    scanned_at: "2026-03-31T15:52:00Z"
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

    get:
      summary: List scans for authenticated account
      operationId: listScans
      security:
        - bearerAuth: []
      tags:
        - Scans
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 25
          description: Maximum number of results
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
          description: Pagination offset
      responses:
        '200':
          description: List of scans
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        risk_class:
                          type: string
                        risk_score:
                          type: integer
                        created_at:
                          type: string
                          format: date-time
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        '401':
          description: Missing or invalid API key

  /v1/scans/{id}:
    get:
      summary: Get scan details
      operationId: getScan
      security:
        - bearerAuth: []
      tags:
        - Scans
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Scan ID (format: scan_*)
      responses:
        '200':
          description: Scan details with full answers and action plan
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  answers:
                    $ref: '#/components/schemas/ScanAnswers'
                  risk_class:
                    type: string
                  risk_score:
                    type: integer
                  eu_ai_act_classification:
                    type: string
                  applicable_articles:
                    type: array
                    items:
                      type: string
                  action_plan:
                    type: array
                    items:
                      $ref: '#/components/schemas/ActionItem'
                  created_at:
                    type: string
                    format: date-time
        '404':
          description: Scan not found

  /v1/agents:
    post:
      summary: Register a new AI agent
      operationId: createAgent
      security:
        - bearerAuth: []
      tags:
        - Agents
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Agent'
            example:
              name: "Resume Screening Bot"
              description: "Automated resume ranking for hiring process"
              type: "automation"
              autonomy_level: "semi-autonomous"
              decision_types: ["resume_shortlist", "role_recommendation"]
              data_processed: ["health", "financial"]
              human_oversight: true
              deployment_environment: "production"
      responses:
        '201':
          description: Agent registered successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  risk_class:
                    type: string
                  risk_score:
                    type: integer
                  eu_ai_act_articles:
                    type: array
                    items:
                      type: string
                  status:
                    type: string
                    enum: [registered]
                  compliance_status:
                    type: string
                    enum: [compliant]
                  created_at:
                    type: string
                    format: date-time
        '400':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or invalid API key

    get:
      summary: List all agents for authenticated account
      operationId: listAgents
      security:
        - bearerAuth: []
      tags:
        - Agents
      responses:
        '200':
          description: List of agents
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Agent'
                  total:
                    type: integer

  /v1/agents/{id}:
    get:
      summary: Get agent details
      operationId: getAgent
      security:
        - bearerAuth: []
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Agent ID (format: agent_*)
      responses:
        '200':
          description: Agent details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '404':
          description: Agent not found

    delete:
      summary: Delete an agent
      operationId: deleteAgent
      security:
        - bearerAuth: []
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Agent deleted successfully
        '404':
          description: Agent not found

    patch:
      summary: Update agent properties
      operationId: updateAgent
      security:
        - bearerAuth: []
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                human_oversight:
                  type: boolean
                deployment_environment:
                  type: string
      responses:
        '200':
          description: Agent updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '409':
          description: Conflict — resource was modified by another request

  /v1/decisions:
    post:
      summary: Log a decision made by an AI agent
      operationId: createDecision
      security:
        - bearerAuth: []
      tags:
        - Decisions
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - agent_id
                - decision_type
                - input_summary
                - output_summary
              properties:
                agent_id:
                  type: string
                decision_type:
                  type: string
                input_summary:
                  type: string
                output_summary:
                  type: string
                confidence:
                  type: number
                  minimum: 0
                  maximum: 1
                  nullable: true
                  description: Model confidence (0.0–1.0). Optional.
                human_reviewed:
                  type: boolean
                  default: false
                  description: Whether decision was reviewed by human
                context:
                  type: object
                  description: Optional metadata (any key-value pairs)
            example:
              agent_id: "agent_xyz123"
              decision_type: "hiring_decision"
              input_summary: "Candidate profile analysis"
              output_summary: "Recommendation: HIRE"
              confidence: 0.89
              human_reviewed: false
              context:
                candidate_id: "cand_123"
                role: "Senior Engineer"
      responses:
        '201':
          description: Decision logged successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  agent_id:
                    type: string
                  logged_at:
                    type: string
                    format: date-time
                  audit_hash:
                    type: string
                    description: SHA256 hash for integrity verification
                  risk_score:
                    type: number
                    description: Decision-level risk score (0.0–1.0)
                  risk_factors:
                    type: array
                    items:
                      type: string
                  warning:
                    type: string
                    nullable: true
                    description: Risk warning if decision flagged for review
              example:
                id: "dec_8x4k1p9"
                agent_id: "agent_xyz123"
                logged_at: "2026-03-31T15:52:00Z"
                audit_hash: "sha256:a1b2c3d4e5f6..."
                risk_score: 0.72
                risk_factors: ["risk_class:high", "high_confidence"]
        '404':
          description: Agent not found
        '401':
          description: Missing or invalid API key

    get:
      summary: List decisions for an agent or account
      operationId: listDecisions
      security:
        - bearerAuth: []
      tags:
        - Decisions
      parameters:
        - name: agent_id
          in: query
          schema:
            type: string
          description: Filter by agent ID
        - name: limit
          in: query
          schema:
            type: integer
            default: 50
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: List of decisions
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Decision'
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer

  /v1/decisions/{id}:
    get:
      summary: Get decision details
      operationId: getDecision
      security:
        - bearerAuth: []
      tags:
        - Decisions
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Decision details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Decision'
        '404':
          description: Decision not found

    patch:
      summary: Mark decision as human-reviewed
      operationId: updateDecisionReview
      security:
        - bearerAuth: []
      tags:
        - Decisions
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [human_reviewed]
              properties:
                human_reviewed:
                  type: boolean
                  description: Set to true to mark as reviewed
      responses:
        '200':
          description: Decision review status updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Decision'
        '404':
          description: Decision not found

  /v1/decisions/export:
    get:
      summary: Export decisions (CSV or JSON)
      operationId: exportDecisions
      security:
        - bearerAuth: []
      tags:
        - Decisions
      parameters:
        - name: format
          in: query
          schema:
            type: string
            enum: [json, csv]
            default: json
        - name: agent_id
          in: query
          schema:
            type: string
        - name: from
          in: query
          schema:
            type: string
            format: date-time
        - name: to
          in: query
          schema:
            type: string
            format: date-time
      responses:
        '200':
          description: Decisions exported in requested format
          headers:
            X-Export-Truncated:
              schema:
                type: boolean
              description: True if results exceeded limit (10,000)
            X-Export-Limit:
              schema:
                type: integer
              description: Export limit applied

  /v1/changelog:
    get:
      summary: Get EU AI Act enforcement milestones
      operationId: getChangelog
      tags:
        - Compliance
      parameters:
        - name: impact
          in: query
          schema:
            type: string
            enum: [high, medium, low]
          description: Filter by impact level
        - name: from
          in: query
          schema:
            type: string
            format: date
          description: Filter from date onwards
      responses:
        '200':
          description: Compliance milestones
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ComplianceChangelog'
                  total:
                    type: integer
                  description:
                    type: string
                  last_updated:
                    type: string
                  source:
                    type: string

  /v1/version:
    get:
      summary: Get API version information
      operationId: getVersion
      tags:
        - Meta
      responses:
        '200':
          description: Version info
          content:
            application/json:
              schema:
                type: object
                properties:
                  version:
                    type: integer
                  status:
                    type: string
                  latest:
                    type: integer

  /v1/agents/{id}/badge.svg:
    get:
      summary: Get compliance badge for agent (public)
      operationId: getAgentBadge
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: SVG compliance badge
          content:
            image/svg+xml:
              schema:
                type: string

  /v1/agents/{id}/profile:
    get:
      summary: Get public agent profile (public)
      operationId: getAgentProfile
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Agent profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  description:
                    type: string
                  risk_class:
                    type: string
                  registered_since:
                    type: string
                    format: date-time
                  compliance:
                    type: object
                    properties:
                      total_decisions:
                        type: integer
                      human_review_rate:
                        type: number
                  profile_url:
                    type: string

    patch:
      summary: Update agent public profile settings
      operationId: updateAgentProfile
      security:
        - bearerAuth: []
      tags:
        - Agents
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                public:
                  type: boolean
                  description: Whether to make profile public
                slug:
                  type: string
                  pattern: '^[a-z0-9-]+$'
                  description: Public URL slug (if public=true)
      responses:
        '200':
          description: Profile updated
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean

  /v1/public/agents/{slug}:
    get:
      summary: Get public agent profile by slug (public)
      operationId: getPublicAgentBySlug
      tags:
        - Agents
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Public agent profile
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  risk_class:
                    type: string
                  compliance_status:
                    type: string
                  eu_ai_act_articles:
                    type: array
                    items:
                      type: string
                  created_at:
                    type: string
                    format: date-time
                  total_decisions:
                    type: integer
        '404':
          description: Agent not found
