{
  "openapi": "3.1.0",
  "info": {
    "title": "CompCare API",
    "version": "3.2.0",
    "description": "Compensation intelligence API for healthcare professionals in Sweden. Provides consultant market rate lookups based on official framework agreement prices (ramavtalspriser) from 290+ Swedish healthcare providers and the staffing industry's margin model.\n\nThe recommended entry point for AI agents is the unified `/compensation-intelligence` endpoint, which supports entity resolution, policy enforcement, and audit logging.\n\nAll CI responses follow a standardized envelope: `{ query_id, capability, status, data, source, policy, errors }`.\n\nData sources: SKR framework agreements (2026) and the staffing industry's margin model (85–90% of customer price, ×1.38 for employees, 167h/month). Updated continuously as new contract versions are published.\n\nBulk export and enumeration are NOT supported — the API enforces anti-enumeration policies.",
    "contact": {
      "name": "CompCare",
      "url": "https://compcare.se",
      "email": "info@compcare.se"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://ubhhlunhdqbokjvwfebb.supabase.co/functions/v1",
      "description": "Production"
    }
  ],
  "paths": {
    "/compensation-intelligence": {
      "post": {
        "operationId": "compensationIntelligence",
        "summary": "Unified compensation intelligence endpoint (recommended)",
        "description": "Central entry point for all compensation queries. Supports two capabilities: lookup_rate, compare_roles. Includes entity resolution (fuzzy matching of roles and geographies), policy enforcement (rate limiting, anti-enumeration), and full audit logging.\n\nAll responses use a standardized envelope with query_id, capability, status, data, source, policy, and errors fields.",
        "tags": ["Compensation Intelligence"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CIRequest"
              },
              "examples": {
                "lookup_rate": {
                  "summary": "Look up consultant rate",
                  "value": {
                    "capability": "lookup_rate",
                    "params": {
                      "role": "Specialistsjuksköterska intensivvård",
                      "geography": "Lund",
                      "employment_type": "anstalld"
                    }
                  }
                },
                "compare_roles": {
                  "summary": "Compare two roles",
                  "value": {
                    "capability": "compare_roles",
                    "params": {
                      "role_a": "Sjuksköterska",
                      "role_b": "Specialistsjuksköterska",
                      "geography": "Stockholm",
                      "employment_type": "anstalld"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response (status: success)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          },
          "400": {
            "description": "Invalid input (INVALID_INPUT, QUERY_TOO_BROAD)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          },
          "403": {
            "description": "Capability not allowed (CAPABILITY_NOT_ALLOWED)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          },
          "404": {
            "description": "Entity not resolved or no data (ENTITY_NOT_RESOLVED, NO_DATA_FOUND)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          },
          "422": {
            "description": "Insufficient sample size (INSUFFICIENT_SAMPLE)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          },
          "429": {
            "description": "Rate limited or enumeration risk (RATE_LIMITED, ENUMERATION_RISK)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CIResponseEnvelope" }
              }
            }
          }
        }
      }
    },
    "/ci-capabilities": {
      "get": {
        "operationId": "listCapabilities",
        "summary": "List available capabilities, schemas, and error codes",
        "description": "Returns all active capability definitions including their input/output JSON schemas, human-readable labels, agent-optimized labels, and all standard error codes.",
        "tags": ["Discovery"],
        "responses": {
          "200": {
            "description": "Capabilities and error codes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "capabilities": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/CapabilityDefinition" }
                    },
                    "error_codes": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/ErrorCodeDefinition" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ci-roles": {
      "get": {
        "operationId": "listRoles",
        "summary": "List available roles with stable IDs and alias mappings",
        "description": "Returns all canonical roles with stable UUIDs, codes, and known aliases. Use these values in the 'role' parameter.",
        "tags": ["Discovery"],
        "responses": {
          "200": {
            "description": "List of roles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string", "format": "uuid" },
                          "code": { "type": "string" },
                          "name": { "type": "string" },
                          "aliases": { "type": "array", "items": { "type": "string" } }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ci-geographies": {
      "get": {
        "operationId": "listGeographies",
        "summary": "List available geographies grouped by region",
        "description": "Returns all municipalities (kommuner) grouped by region, with zone information and stable IDs.",
        "tags": ["Discovery"],
        "responses": {
          "200": {
            "description": "Geographies grouped by region",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_municipalities": { "type": "integer" },
                    "zones": { "type": "array", "items": { "type": "string" } },
                    "regions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "region": { "type": "string" },
                          "municipalities": { "type": "array", "items": { "type": "string" } }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ci-metrics": {
      "get": {
        "operationId": "listMetrics",
        "summary": "List available metrics and comparison types",
        "description": "Returns all available measurement values (e.g. amount, median_salary, p25_salary, p75_salary) and allowed comparison types with required parameters.",
        "tags": ["Discovery"],
        "responses": {
          "200": {
            "description": "Metrics and comparisons",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "metrics": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/MetricDefinition" }
                    },
                    "comparisons": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/ComparisonDefinition" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/pricing-engine": {
      "post": {
        "operationId": "getConsultantPricing",
        "summary": "Calculate consultant compensation range (legacy wrapper)",
        "description": "Legacy endpoint — delegates to compensation-intelligence internally. Returns recommended hourly and monthly compensation.",
        "tags": ["Pricing (Legacy)"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PricingRequest" },
              "example": { "occupation": "Sjuksköterska", "kommun": "Stockholm", "employment_type": "anstalld" }
            }
          }
        },
        "responses": {
          "200": { "description": "Successful pricing calculation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PricingResponse" } } } },
          "400": { "description": "Missing required fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "404": { "description": "No rate found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/salary-benchmark-engine": {
      "post": {
        "operationId": "getSalaryBenchmark",
        "summary": "Get salary benchmark for permanent employees (legacy wrapper)",
        "description": "Legacy endpoint — delegates to compensation-intelligence internally. Returns salary percentiles (p25, p50, p75).",
        "tags": ["Benchmarks (Legacy)"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/BenchmarkRequest" },
              "example": { "occupation": "Sjuksköterska", "sector": "offentlig", "current_salary": 35000 }
            }
          }
        },
        "responses": {
          "200": { "description": "Successful benchmark lookup", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BenchmarkResponse" } } } },
          "400": { "description": "Missing required fields", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "500": { "description": "No benchmark data available", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/create-report": {
      "post": {
        "operationId": "createCompensationReport",
        "summary": "Generate a full compensation report",
        "tags": ["Reports"],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReportRequest" } } } },
        "responses": {
          "200": { "description": "Report created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReportResponse" } } } },
          "400": { "description": "Missing required fields" },
          "404": { "description": "No rate/benchmark data found" }
        }
      }
    },
    "/get-report": {
      "post": {
        "operationId": "getReport",
        "summary": "Retrieve a compensation report",
        "tags": ["Reports"],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetReportRequest" } } } },
        "responses": {
          "200": { "description": "Report retrieved", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetReportResponse" } } } },
          "404": { "description": "Report not found" }
        }
      }
    },
    "/generate-pdf": {
      "post": {
        "operationId": "generatePdf",
        "summary": "Generate a branded PDF report",
        "tags": ["Reports"],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GeneratePdfRequest" } } } },
        "responses": {
          "200": { "description": "PDF generated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GeneratePdfResponse" } } } },
          "400": { "description": "Missing report_id" },
          "404": { "description": "Report not found" }
        }
      }
    },
    "/run-price-diff": {
      "post": {
        "operationId": "runPriceDiff",
        "summary": "Compare prices between contract versions",
        "tags": ["Market Intelligence"],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PriceDiffRequest" } } } },
        "responses": {
          "200": { "description": "Diff completed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PriceDiffResponse" } } } }
        }
      }
    },
    "/get-public-profile": {
      "get": {
        "operationId": "getPublicProfile",
        "summary": "Machine-readable public consultant profile",
        "description": "Returns a schema.org Person object representing a verified consultant's public 'Vault' profile (verified references, documents, credentials, trust score). Mirrors the human-facing page at https://compcare.se/profil/{id}.\n\nIntended for AI agents and automated systems that need structured access to a consultant's verified credentials and references. Each request is logged to ref_access_logs (resource_type='public_profile_api'). Set the optional headers `x-viewer-name` and `x-viewer-org` to identify the calling agent or organization.\n\nNo bulk enumeration is supported — IDs must be obtained from a profile owner who has shared the link.",
        "tags": ["Public Profiles"],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "Profile UUID (matches /profil/{id} on the website)",
            "schema": { "type": "string", "format": "uuid" }
          },
          {
            "name": "x-viewer-name",
            "in": "header",
            "required": false,
            "description": "Optional viewer/agent identifier (logged for audit)",
            "schema": { "type": "string" }
          },
          {
            "name": "x-viewer-org",
            "in": "header",
            "required": false,
            "description": "Optional organization the viewer represents (logged for audit)",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Public profile (schema.org Person + CompCare extensions)",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PublicProfile" }
              }
            }
          },
          "400": { "description": "Missing or invalid id parameter" },
          "404": { "description": "Profile not found or not publicly accessible" }
        }
      }
    },
    "/radar-public-api": {
      "get": {
        "operationId": "radarDiscover",
        "summary": "Uppdragsradar API discovery",
        "description": "Returns the available Uppdragsradar endpoints, scopes, and authentication methods. No API key required. Use this to discover what data is exposed before issuing authenticated calls. Response follows the CompCare CI envelope (`query_id`, `capability`, `status`, `data`, `source`, `policy`, `errors`, `meta`).",
        "tags": ["Uppdragsradar"],
        "responses": {
          "200": {
            "description": "Discovery payload listing endpoints, scopes, and the envelope format",
            "content": { "application/json": { "schema": { "type": "object" } } }
          }
        }
      }
    },
    "/radar-public-api/predictions": {
      "get": {
        "operationId": "radarPredictions",
        "summary": "Uppdragsradar — assignment predictions",
        "description": "Forecasted call-offs (avrop) per customer / region / profession / month, derived from historical calloff_imports patterns. Requires a per-consumer API key with the `predictions` scope. All responses use the standardized CI envelope. Per-key hourly and daily rate limits apply (see `meta.rate_limit`).",
        "tags": ["Uppdragsradar"],
        "security": [{ "RadarApiKey": [] }],
        "parameters": [
          { "name": "region", "in": "query", "schema": { "type": "string" }, "description": "Filter by region (e.g. 'Stockholm')" },
          { "name": "profession", "in": "query", "schema": { "type": "string", "enum": ["DOCTOR", "NURSE", "PHYSIOTHERAPIST"] } },
          { "name": "specialization", "in": "query", "schema": { "type": "string" } },
          { "name": "month", "in": "query", "schema": { "type": "string", "pattern": "^\\d{4}-\\d{2}$" }, "description": "YYYY-MM" },
          { "name": "confidence", "in": "query", "schema": { "type": "string", "enum": ["low", "med", "high"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } }
        ],
        "responses": {
          "200": { "description": "Predictions in CI envelope" },
          "401": { "description": "Missing or invalid API key" },
          "403": { "description": "API key lacks 'predictions' scope" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/radar-public-api/customer_intelligence": {
      "get": {
        "operationId": "radarCustomerIntelligence",
        "summary": "Uppdragsradar — customer trends and seasonality",
        "description": "Year-over-year volume trends, seasonal peaks/lows, and YTD ratios per customer. Requires `customer_intelligence` scope.",
        "tags": ["Uppdragsradar"],
        "security": [{ "RadarApiKey": [] }],
        "parameters": [
          { "name": "customer", "in": "query", "schema": { "type": "string" } },
          { "name": "region", "in": "query", "schema": { "type": "string" } },
          { "name": "profession", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } }
        ],
        "responses": {
          "200": { "description": "Customer intelligence in CI envelope" },
          "401": { "description": "Missing or invalid API key" },
          "403": { "description": "API key lacks 'customer_intelligence' scope" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    },
    "/radar-public-api/calloff_imports": {
      "get": {
        "operationId": "radarCalloffImports",
        "summary": "Uppdragsradar — raw historical call-offs",
        "description": "Underlying raw call-off (avrop) records imported from public sources, including price ranges and fill status. Requires `calloff_imports` scope.",
        "tags": ["Uppdragsradar"],
        "security": [{ "RadarApiKey": [] }],
        "parameters": [
          { "name": "region", "in": "query", "schema": { "type": "string" } },
          { "name": "role", "in": "query", "schema": { "type": "string" } },
          { "name": "customer", "in": "query", "schema": { "type": "string" } },
          { "name": "since", "in": "query", "schema": { "type": "string", "format": "date" }, "description": "YYYY-MM-DD" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "minimum": 0, "default": 0 } }
        ],
        "responses": {
          "200": { "description": "Raw call-offs in CI envelope" },
          "401": { "description": "Missing or invalid API key" },
          "403": { "description": "API key lacks 'calloff_imports' scope" },
          "429": { "description": "Rate limit exceeded" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CIRequest": {
        "type": "object",
        "required": ["capability", "params"],
        "properties": {
          "capability": {
            "type": "string",
            "enum": ["lookup_rate", "compare_roles", "salary_benchmark", "salary_position"],
            "description": "Which capability to invoke"
          },
          "version": { "type": "integer", "default": 1, "description": "Capability version" },
          "params": {
            "type": "object",
            "description": "Capability-specific parameters. Use /ci-capabilities to discover input schemas.",
            "properties": {
              "role": { "type": "string" },
              "role_a": { "type": "string" },
              "role_b": { "type": "string" },
              "geography": { "type": "string" },
              "geography_b": { "type": "string" },
              "employment_type": { "type": "string", "enum": ["anstalld", "foretagare"] },
              "sector": { "type": "string", "enum": ["privat", "offentlig", "landsting", "kommun"] },
              "current_salary": { "type": "integer" }
            }
          },
          "client_type": {
            "type": "string",
            "enum": ["anonymous_human", "authenticated_human", "internal_agent"],
            "default": "anonymous_human"
          }
        }
      },
      "CIResponseEnvelope": {
        "type": "object",
        "description": "Standardized response envelope for all CI capabilities",
        "required": ["query_id", "capability", "status", "data", "source", "policy", "errors"],
        "properties": {
          "query_id": { "type": "string", "format": "uuid", "nullable": true, "description": "Unique audit trail ID" },
          "capability": { "type": "string" },
          "status": { "type": "string", "enum": ["success", "error"] },
          "data": { "type": "object", "nullable": true, "description": "Capability-specific structured result. null on error." },
          "source": {
            "type": "object",
            "nullable": true,
            "description": "Data source metadata. null on error.",
            "properties": {
              "name": { "type": "string", "examples": ["SKR ramavtal", "SCB/Medlingsinstitutet lönestatistik"] },
              "version": { "type": "string", "examples": ["SKR 2026 v1.0", "2025"] },
              "confidence": { "type": "string", "enum": ["high", "medium", "low"] }
            }
          },
          "policy": {
            "type": "object",
            "description": "Policy evaluation result",
            "properties": {
              "status": { "type": "string", "enum": ["allowed", "fallback", "blocked"] },
              "client_type": { "type": "string" },
              "fallback_applied": { "type": "boolean" },
              "fallback_level": { "type": "string", "nullable": true, "description": "E.g. 'region', 'national', 'ilike_match'" }
            }
          },
          "errors": {
            "type": "array",
            "description": "Empty array on success, structured error objects on failure",
            "items": {
              "type": "object",
              "properties": {
                "code": { "type": "string", "description": "Machine-readable error code" },
                "message": { "type": "string", "description": "Human-readable error message" }
              }
            }
          }
        }
      },
      "CapabilityDefinition": {
        "type": "object",
        "properties": {
          "capability_key": { "type": "string" },
          "version": { "type": "integer" },
          "name": { "type": "string" },
          "description": { "type": "string" },
          "human_label": { "type": "string" },
          "agent_label": { "type": "string" },
          "input_schema": { "type": "object" },
          "output_schema": { "type": "object" }
        }
      },
      "ErrorCodeDefinition": {
        "type": "object",
        "properties": {
          "code": { "type": "string" },
          "description": { "type": "string" },
          "http_status": { "type": "integer" }
        }
      },
      "MetricDefinition": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "label": { "type": "string" },
          "description": { "type": "string" },
          "capabilities": { "type": "array", "items": { "type": "string" } },
          "unit": { "type": "string" },
          "unit_type": { "type": "string" }
        }
      },
      "ComparisonDefinition": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "label": { "type": "string" },
          "description": { "type": "string" },
          "capability": { "type": "string" },
          "required_params": { "type": "array", "items": { "type": "string" } },
          "note": { "type": "string" }
        }
      },
      "PricingRequest": {
        "type": "object",
        "required": ["occupation", "kommun", "employment_type"],
        "properties": {
          "occupation": { "type": "string" },
          "kommun": { "type": "string" },
          "employment_type": { "type": "string", "enum": ["anstalld", "foretagare"] }
        }
      },
      "PricingResponse": {
        "type": "object",
        "properties": {
          "occupation": { "type": "string" },
          "kommun": { "type": "string" },
          "zon": { "type": "string" },
          "region": { "type": "string" },
          "employment_type": { "type": "string" },
          "rate_customer_sek_per_hour": { "type": "integer" },
          "consultant_share_min": { "type": "number" },
          "consultant_share_max": { "type": "number" },
          "employee_factor": { "type": "number" },
          "hours_per_month": { "type": "integer" },
          "recommended_hourly_min": { "type": "integer" },
          "recommended_hourly_max": { "type": "integer" },
          "recommended_monthly_min": { "type": "integer" },
          "recommended_monthly_max": { "type": "integer" }
        }
      },
      "BenchmarkRequest": {
        "type": "object",
        "required": ["occupation", "sector"],
        "properties": {
          "occupation": { "type": "string" },
          "sector": { "type": "string", "enum": ["privat", "offentlig", "landsting", "kommun"] },
          "current_salary": { "type": "integer" }
        }
      },
      "BenchmarkResponse": {
        "type": "object",
        "properties": {
          "occupation": { "type": "string" },
          "sector": { "type": "string" },
          "region": { "type": "string", "nullable": true },
          "year": { "type": "integer" },
          "source": { "type": "string" },
          "percentile_25": { "type": "integer" },
          "percentile_50": { "type": "integer" },
          "percentile_75": { "type": "integer" },
          "current_salary": { "type": "integer" },
          "gap_vs_p75": { "type": "integer" },
          "gap_pct": { "type": "integer" },
          "category": { "type": "string", "enum": ["small", "medium", "large"] }
        }
      },
      "CreateReportRequest": {
        "type": "object",
        "required": ["occupation", "employment_type", "kommun"],
        "properties": {
          "occupation": { "type": "string" },
          "employment_type": { "type": "string", "enum": ["anstalld", "foretagare"] },
          "kommun": { "type": "string" },
          "email": { "type": "string", "format": "email" },
          "lead_id": { "type": "string", "format": "uuid" },
          "experience": { "type": "integer" },
          "current_salary": { "type": "integer" },
          "salary_type": { "type": "string", "enum": ["monthly", "hourly"] },
          "ob_share": { "type": "string" },
          "track": { "type": "string", "enum": ["consultant", "permanent"] },
          "sector": { "type": "string" }
        }
      },
      "CreateReportResponse": {
        "type": "object",
        "properties": {
          "report_id": { "type": "string", "format": "uuid" },
          "ab_variant": { "type": "string" }
        }
      },
      "GetReportRequest": {
        "type": "object",
        "required": ["report_id"],
        "properties": {
          "report_id": { "type": "string", "format": "uuid" },
          "auth_user_id": { "type": "string", "format": "uuid" }
        }
      },
      "GetReportResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "type": "string" },
          "access": { "type": "string", "enum": ["full", "preview"] },
          "occupation": { "type": "string" },
          "employment_type": { "type": "string" },
          "kommun": { "type": "string" },
          "result_json": { "type": "object" }
        }
      },
      "GeneratePdfRequest": {
        "type": "object",
        "required": ["report_id"],
        "properties": { "report_id": { "type": "string", "format": "uuid" } }
      },
      "GeneratePdfResponse": {
        "type": "object",
        "properties": {
          "pdf_base64": { "type": "string" },
          "filename": { "type": "string" }
        }
      },
      "PriceDiffRequest": {
        "type": "object",
        "required": ["new_version_id"],
        "properties": {
          "old_version_id": { "type": "string", "format": "uuid" },
          "new_version_id": { "type": "string", "format": "uuid" }
        }
      },
      "PriceDiffResponse": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean" },
          "summary": { "type": "object" },
          "changes": { "type": "array", "items": { "type": "object" } }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": { "error": { "type": "string" } }
      },
      "PublicProfile": {
        "type": "object",
        "description": "schema.org Person extended with CompCare verification data",
        "properties": {
          "@context": { "type": "string", "example": "https://schema.org" },
          "@type": { "type": "string", "example": "Person" },
          "identifier": { "type": "string", "format": "uuid" },
          "name": { "type": "string" },
          "jobTitle": { "type": "string", "nullable": true },
          "description": { "type": "string", "nullable": true },
          "hasCredential": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "@type": { "type": "string", "example": "EducationalOccupationalCredential" },
                "credentialCategory": { "type": "string" },
                "recognizedBy": {
                  "type": "object",
                  "properties": {
                    "@type": { "type": "string" },
                    "name": { "type": "string" }
                  }
                }
              }
            }
          },
          "compcare": {
            "type": "object",
            "description": "CompCare-specific verification metrics",
            "properties": {
              "trust_score": { "type": "integer", "minimum": 0, "maximum": 100 },
              "trust_tier": { "type": "string", "enum": ["elite", "verified_pro", "basic", "incomplete"] },
              "trust_tier_label": { "type": "string" },
              "score_updated_at": { "type": "string", "format": "date-time", "nullable": true },
              "reference_count": { "type": "integer" },
              "attachable_reference_count": { "type": "integer" },
              "avg_recommendation": { "type": "number" },
              "competencies": { "type": "object", "additionalProperties": { "type": "integer" } },
              "years_licensed": { "type": "integer", "nullable": true }
            }
          },
          "references": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "relationship": { "type": "string" },
                "workplace": { "type": "string" },
                "period_start": { "type": "string" },
                "period_end": { "type": "string", "nullable": true },
                "recommendation_score": { "type": "integer" },
                "competencies": { "type": "array", "items": { "type": "string" } },
                "verification_level": { "type": "string", "enum": ["email", "domain", "ping_confirmed"] },
                "last_confirmed_at": { "type": "string", "format": "date-time" },
                "confirmed_at": { "type": "string", "format": "date-time" }
              }
            }
          },
          "documents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "file_name": { "type": "string" },
                "document_type": { "type": "string" },
                "document_type_label": { "type": "string" },
                "uploaded_at": { "type": "string", "format": "date-time" }
              }
            }
          },
          "meta": {
            "type": "object",
            "properties": {
              "generated_at": { "type": "string", "format": "date-time" },
              "source": { "type": "string", "example": "compcare.se" },
              "api_version": { "type": "string" },
              "canonical_url": { "type": "string", "format": "uri" }
            }
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "apikey",
        "description": "Supabase anon key for public endpoints"
      },
      "RadarApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Per-consumer Uppdragsradar API key (issued by CompCare admin). Also accepted as `Authorization: Bearer <key>` or `?api_key=`."
      }
    }
  },
  "security": [{ "ApiKeyAuth": [] }],
  "tags": [
    { "name": "Compensation Intelligence", "description": "Unified compensation intelligence API with standardized response envelope. Recommended entry point for AI agents." },
    { "name": "Discovery", "description": "Discover available capabilities, roles, geographies, metrics, and error codes without exposing raw data" },
    { "name": "Pricing (Legacy)", "description": "Legacy consultant compensation calculations (delegates to Compensation Intelligence)" },
    { "name": "Benchmarks (Legacy)", "description": "Legacy salary benchmarks (delegates to Compensation Intelligence)" },
    { "name": "Reports", "description": "Full compensation analysis reports and PDF generation" },
    { "name": "Market Intelligence", "description": "Price monitoring and contract version comparisons" },
    { "name": "Public Profiles", "description": "Machine-readable consultant profiles for AI agents and automated systems" },
    { "name": "Uppdragsradar", "description": "Forecasted call-offs (avrop), customer trends, and raw historical data. Per-consumer API keys with scoped access and configurable rate limits." }
  ]
}
