{
  "openapi": "3.1.0",
  "info": {
    "title": "Opendata.cat API",
    "description": "API publica per accedir al cataleg de +2.800 datasets de dades obertes de Catalunya. 9 portals (Generalitat, Barcelona, Diba, AOC, Reus, Girona, FGC, Idescat, Renfe) + dades de +1.000 municipis. Queryable via Socrata, CKAN, Opendatasoft, Idescat API, GTFS-RT i Renfe GTFS-RT JSON.",
    "version": "1.0.0",
    "contact": {
      "name": "opendata.cat",
      "url": "https://opendata.cat",
      "email": "xavi.vinaixa@gmail.com"
    },
    "license": {
      "name": "MIT",
      "url": "https://opensource.org/licenses/MIT"
    }
  },
  "servers": [
    {
      "url": "https://opendata.cat/api",
      "description": "Produccio"
    }
  ],
  "tags": [
    { "name": "Datasets", "description": "Cerca i consulta de datasets de dades obertes" },
    { "name": "Portals", "description": "Portals de transparencia i dades obertes" },
    { "name": "MCP", "description": "Model Context Protocol — servidor JSON-RPC" },
    { "name": "Estadistiques", "description": "Estadistiques d'us i cataleg" }
  ],
  "paths": {
    "/all-datasets.php": {
      "get": {
        "tags": ["Datasets"],
        "summary": "Llista tots els datasets",
        "description": "Llista TOTS els datasets indexats al MCP amb paginacio. Permet filtrar per portal i categoria, i ordenar per nom, data d'actualitzacio o portal.",
        "operationId": "listAllDatasets",
        "parameters": [
          {
            "name": "portal",
            "in": "query",
            "description": "Filtrar per portal d'origen.",
            "schema": { "type": "string", "enum": ["generalitat", "barcelona", "diba", "aoc", "reus", "girona", "fgc", "idescat", "renfe"] }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filtrar per categoria tematica (coincidencia parcial).",
            "schema": { "type": "string" }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Nombre maxim de resultats per pagina.",
            "schema": { "type": "integer", "default": 100, "minimum": 1, "maximum": 500 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Desplacament per paginacio.",
            "schema": { "type": "integer", "default": 0, "minimum": 0 }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Ordenacio: 'name' (per defecte), 'updated' (data actualitzacio), 'portal'.",
            "schema": { "type": "string", "enum": ["name", "updated", "portal"], "default": "name" }
          }
        ],
        "responses": {
          "200": {
            "description": "Llista paginada de tots els datasets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/DatasetSummary" }
                    },
                    "total": { "type": "integer", "description": "Nombre total de datasets" },
                    "limit": { "type": "integer" },
                    "offset": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/datasets.php": {
      "get": {
        "tags": ["Datasets"],
        "summary": "Cerca datasets",
        "description": "Cerca datasets de dades obertes per text lliure (FULLTEXT), amb filtres per portal i categoria. Retorna resultats paginats.",
        "operationId": "searchDatasets",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Text de cerca (FULLTEXT en nom, descripcio i sinonims). Exemples: 'qualitat aire', 'embassament', 'pressupost'.",
            "schema": { "type": "string" }
          },
          {
            "name": "portal",
            "in": "query",
            "description": "Filtrar per portal d'origen.",
            "schema": { "type": "string", "enum": ["generalitat", "barcelona", "diba", "aoc", "reus", "girona", "fgc", "idescat", "renfe"] }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filtrar per categoria tematica (coincidencia parcial).",
            "schema": { "type": "string" }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Nombre maxim de resultats per pagina.",
            "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Desplacament per paginacio.",
            "schema": { "type": "integer", "default": 0, "minimum": 0 }
          }
        ],
        "responses": {
          "200": {
            "description": "Llista de datasets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/DatasetSummary" }
                    },
                    "total": { "type": "integer", "description": "Nombre total de resultats" },
                    "limit": { "type": "integer" },
                    "offset": { "type": "integer" }
                  }
                },
                "example": {
                  "items": [
                    {
                      "dataset_id": "generalitat:gn9e-3qhr",
                      "portal_id": "generalitat",
                      "name": "Quantitat d'aigua als embassaments de les Conques Internes de Catalunya",
                      "description": "Dades setmanals del volum d'aigua embassat...",
                      "category": "Medi Ambient",
                      "formats": ["json", "csv"],
                      "api_type": "socrata"
                    }
                  ],
                  "total": 199,
                  "limit": 20,
                  "offset": 0
                }
              }
            }
          }
        }
      }
    },
    "/dataset.php": {
      "get": {
        "tags": ["Datasets"],
        "summary": "Detall d'un dataset",
        "description": "Retorna totes les metadades d'un dataset: camps amb tipus, endpoint API, llicencia, formats, tags, sinonims de cerca i datasets relacionats.",
        "operationId": "getDataset",
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "ID del dataset (format: portal:resource_id).",
            "schema": { "type": "string" },
            "example": "generalitat:gn9e-3qhr"
          }
        ],
        "responses": {
          "200": {
            "description": "Detall complet del dataset",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DatasetFull" }
              }
            }
          },
          "404": {
            "description": "Dataset no trobat",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/categories.php": {
      "get": {
        "tags": ["Datasets"],
        "summary": "Categories i portals",
        "description": "Retorna el nombre total de datasets, la llista de portals amb comptadors, i totes les categories agrupades per portal.",
        "operationId": "getCategories",
        "responses": {
          "200": {
            "description": "Categories i estadistiques per portal",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total_datasets": { "type": "integer" },
                    "portals": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "portal_id": { "type": "string" },
                          "total": { "type": "integer" }
                        }
                      }
                    },
                    "categories": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "portal_id": { "type": "string" },
                          "category": { "type": "string" },
                          "total": { "type": "integer" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/portals.php": {
      "get": {
        "tags": ["Portals"],
        "summary": "Llista portals de transparencia",
        "description": "Retorna la llista paginada de 1.769 portals de transparencia d'administracions publiques catalanes. Permet cercar per nom i filtrar per tipus d'administracio.",
        "operationId": "listPortals",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Cerca per nom oficial del portal.",
            "schema": { "type": "string" }
          },
          {
            "name": "admin",
            "in": "query",
            "description": "Filtrar per tipus d'administracio (ex: 'Ajuntament', 'Consell Comarcal').",
            "schema": { "type": "string" }
          },
          {
            "name": "page",
            "in": "query",
            "description": "Numero de pagina.",
            "schema": { "type": "integer", "default": 1, "minimum": 1 }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Resultats per pagina.",
            "schema": { "type": "integer", "default": 50, "minimum": 10, "maximum": 100 }
          }
        ],
        "responses": {
          "200": {
            "description": "Llista de portals paginada",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Portal" }
                    },
                    "total": { "type": "integer" },
                    "page": { "type": "integer" },
                    "limit": { "type": "integer" },
                    "pages": { "type": "integer" },
                    "admins": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "tipus_administracio": { "type": "string" },
                          "total": { "type": "integer" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/portal.php": {
      "get": {
        "tags": ["Portals"],
        "summary": "Detall d'un portal",
        "description": "Retorna les dades d'un portal de transparencia per slug.",
        "operationId": "getPortal",
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "required": true,
            "description": "Slug del portal (URL-friendly).",
            "schema": { "type": "string" },
            "example": "ajuntament-de-barcelona"
          }
        ],
        "responses": {
          "200": {
            "description": "Detall del portal",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Portal" }
              }
            }
          },
          "404": {
            "description": "Portal no trobat",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/stats.php": {
      "get": {
        "tags": ["Estadistiques"],
        "summary": "Estadistiques de portals",
        "description": "Retorna estadistiques agregades dels portals de transparencia. Cache d'1 hora.",
        "operationId": "getStats",
        "responses": {
          "200": {
            "description": "Estadistiques",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": { "type": "integer", "description": "Nombre total de portals" },
                    "by_admin": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "tipus_administracio": { "type": "string" },
                          "total": { "type": "integer" }
                        }
                      }
                    },
                    "updated_at": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mcp-stats.php": {
      "get": {
        "tags": ["Estadistiques"],
        "summary": "Estadistiques d'us del MCP",
        "description": "Retorna metriques d'us del servidor MCP: crides totals, tools mes usades, cerques populars, datasets mes consultats i volum diari.",
        "operationId": "getMcpStats",
        "responses": {
          "200": {
            "description": "Estadistiques MCP",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mcp": {
                      "type": "object",
                      "properties": {
                        "total": { "type": "integer" },
                        "last_7_days": { "type": "integer" },
                        "last_24h": { "type": "integer" },
                        "unique_clients": { "type": "integer" }
                      }
                    },
                    "top_tools": { "type": "array", "items": { "type": "object" } },
                    "top_searches": { "type": "array", "items": { "type": "object" } },
                    "top_datasets": { "type": "array", "items": { "type": "object" } },
                    "catalog": {
                      "type": "object",
                      "properties": {
                        "total_datasets": { "type": "integer" },
                        "portals": { "type": "array", "items": { "type": "object" } }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": ["MCP"],
        "summary": "MCP Server (Streamable HTTP)",
        "description": "Servidor MCP via JSON-RPC 2.0 sobre Streamable HTTP. Suporta initialize, tools/list, tools/call, prompts/list, prompts/get, resources/list i ping. Documentacio del protocol: https://modelcontextprotocol.io",
        "operationId": "mcpEndpoint",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["jsonrpc", "id", "method"],
                "properties": {
                  "jsonrpc": { "type": "string", "enum": ["2.0"] },
                  "id": { "type": "integer" },
                  "method": {
                    "type": "string",
                    "enum": ["initialize", "tools/list", "tools/call", "prompts/list", "prompts/get", "resources/list", "ping", "notifications/initialized"]
                  },
                  "params": { "type": "object" }
                }
              },
              "examples": {
                "initialize": {
                  "summary": "Inicialitzar connexio MCP",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "initialize",
                    "params": {
                      "protocolVersion": "2025-03-26",
                      "capabilities": {},
                      "clientInfo": { "name": "test", "version": "1" }
                    }
                  }
                },
                "tools_list": {
                  "summary": "Llistar tools disponibles",
                  "value": { "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }
                },
                "search": {
                  "summary": "Cercar datasets via MCP",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 3,
                    "method": "tools/call",
                    "params": {
                      "name": "search_datasets",
                      "arguments": { "query": "embassament", "limit": 5 }
                    }
                  }
                },
                "prompts_list": {
                  "summary": "Llistar prompts disponibles",
                  "value": { "jsonrpc": "2.0", "id": 4, "method": "prompts/list", "params": {} }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Resposta JSON-RPC 2.0",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "jsonrpc": { "type": "string" },
                    "id": { "type": "integer" },
                    "result": { "type": "object" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "DatasetSummary": {
        "type": "object",
        "properties": {
          "dataset_id": { "type": "string", "description": "ID unic (format: portal:resource_id)", "example": "generalitat:gn9e-3qhr" },
          "portal_id": { "type": "string", "description": "Portal d'origen", "example": "generalitat" },
          "name": { "type": "string", "description": "Nom del dataset", "example": "Quantitat d'aigua als embassaments" },
          "description": { "type": "string", "description": "Descripcio del dataset" },
          "category": { "type": "string", "description": "Categoria tematica", "example": "Medi Ambient" },
          "formats": { "type": "array", "items": { "type": "string" }, "example": ["json", "csv"] },
          "api_type": { "type": "string", "enum": ["socrata", "ckan", "diba", "diba_cido", "opendatasoft", "idescat", "renfe_gtfsrt_json", "file_download", "restricted"], "description": "Tipus d'API del portal origen" }
        }
      },
      "DatasetFull": {
        "type": "object",
        "allOf": [{ "$ref": "#/components/schemas/DatasetSummary" }],
        "properties": {
          "tags": { "type": "array", "items": { "type": "string" } },
          "api_endpoint": { "type": "string", "description": "URL de l'API per consultar dades" },
          "fields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": { "type": "string" },
                "type": { "type": "string" },
                "description": { "type": "string" }
              }
            }
          },
          "row_count": { "type": "integer", "nullable": true },
          "last_updated": { "type": "string" },
          "license": { "type": "string" },
          "search_text": { "type": "string", "description": "Sinonims i termes de cerca expandits" },
          "related": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "score": { "type": "number" }
              }
            },
            "description": "Datasets relacionats amb puntuacio de similitud"
          }
        }
      },
      "Portal": {
        "type": "object",
        "properties": {
          "slug": { "type": "string", "example": "ajuntament-de-barcelona" },
          "tipus_administracio": { "type": "string", "example": "Ajuntament" },
          "tipus_institucio": { "type": "string" },
          "nom_oficial": { "type": "string", "example": "Ajuntament de Barcelona" },
          "url": { "type": "string", "format": "uri" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Missatge d'error" }
        }
      }
    }
  }
}
