{
  "openapi": "3.1.0",
  "info": {
    "title": "Bando Easy API",
    "version": "1.0.0",
    "description": "Catalogo dei bandi e degli incentivi italiani. Le chiavi API vanno usate solo lato server."
  },
  "servers": [
    {
      "url": "https://api.bandoeasy.it/v1"
    },
    {
      "url": "https://api.bandoeasy.it/api/v1",
      "description": "Alias equivalente"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/grants": {
      "get": {
        "operationId": "listGrants",
        "summary": "Elenco dei bandi",
        "description": "Restituisce i bandi approvati, dal più recente al meno recente (created_at decrescente). Parametri non previsti restituiscono 400 unknown_parameter.",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            },
            "description": "Pagina, a partire da 1."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 50
            },
            "description": "Bandi per pagina, massimo 50."
          },
          {
            "name": "regione",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "Abruzzo",
                "Basilicata",
                "Calabria",
                "Campania",
                "Emilia-Romagna",
                "Europa",
                "Friuli Venezia Giulia",
                "Italia",
                "Lazio",
                "Liguria",
                "Lombardia",
                "Marche",
                "Molise",
                "Mondo",
                "Piemonte",
                "Puglia",
                "Sardegna",
                "Sicilia",
                "Toscana",
                "Trentino-Alto Adige",
                "Umbria",
                "Valle d'Aosta",
                "Veneto"
              ]
            },
            "description": "Filtra per territorio. Include anche i bandi nazionali ed europei collegati a quel territorio. Il confronto ignora maiuscole e minuscole."
          }
        ],
        "responses": {
          "200": {
            "description": "Pagina di bandi",
            "headers": {
              "X-API-Key-Expires-At": {
                "description": "Scadenza della chiave usata (ISO 8601).",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GrantList"
                }
              }
            }
          },
          "400": {
            "description": "400 Parametri non validi",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "unknown_parameter": {
                    "value": {
                      "error": true,
                      "statusCode": 400,
                      "statusMessage": "unknown_parameter",
                      "message": "unknown_parameter",
                      "data": {
                        "code": "unknown_parameter",
                        "unknown": [
                          "ateco"
                        ],
                        "allowed": [
                          "page",
                          "limit",
                          "regione"
                        ]
                      }
                    }
                  },
                  "invalid_parameter": {
                    "value": {
                      "error": true,
                      "statusCode": 400,
                      "statusMessage": "invalid_parameter",
                      "message": "invalid_parameter",
                      "data": {
                        "code": "invalid_parameter",
                        "issues": [
                          {
                            "param": "limit",
                            "message": "Too big: expected number to be <=50"
                          }
                        ]
                      }
                    }
                  },
                  "unknown_regione": {
                    "value": {
                      "error": true,
                      "statusCode": 400,
                      "statusMessage": "unknown_regione",
                      "message": "unknown_regione",
                      "data": {
                        "code": "unknown_regione",
                        "allowed": [
                          "Abruzzo",
                          "Basilicata",
                          "Calabria",
                          "Campania",
                          "Emilia-Romagna",
                          "Europa",
                          "Friuli Venezia Giulia",
                          "Italia",
                          "Lazio",
                          "Liguria",
                          "Lombardia",
                          "Marche",
                          "Molise",
                          "Mondo",
                          "Piemonte",
                          "Puglia",
                          "Sardegna",
                          "Sicilia",
                          "Toscana",
                          "Trentino-Alto Adige",
                          "Umbria",
                          "Valle d'Aosta",
                          "Veneto"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "401 Chiave mancante, non valida o scaduta",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "api_key_missing": {
                    "value": {
                      "error": true,
                      "statusCode": 401,
                      "statusMessage": "api_key_missing",
                      "message": "api_key_missing",
                      "data": {
                        "code": "api_key_missing"
                      }
                    }
                  },
                  "api_key_invalid": {
                    "value": {
                      "error": true,
                      "statusCode": 401,
                      "statusMessage": "api_key_invalid",
                      "message": "api_key_invalid",
                      "data": {
                        "code": "api_key_invalid"
                      }
                    }
                  },
                  "api_key_expired": {
                    "value": {
                      "error": true,
                      "statusCode": 401,
                      "statusMessage": "api_key_expired",
                      "message": "api_key_expired",
                      "data": {
                        "code": "api_key_expired",
                        "expired_at": "2026-01-31T23:59:59+00:00"
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "WWW-Authenticate": {
                "description": "Presente quando la chiave manca.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "429": {
            "description": "429 Limite di richieste superato",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "rate_limit": {
                    "value": {
                      "error": true,
                      "statusCode": 429,
                      "statusMessage": "rate_limit",
                      "message": "rate_limit",
                      "data": {
                        "code": "rate_limit",
                        "limit_per_minute": 60
                      }
                    }
                  }
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Secondi da attendere.",
                "schema": {
                  "type": "integer"
                }
              }
            }
          },
          "502": {
            "description": "502 Errore temporaneo del servizio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "grants_query_failed": {
                    "value": {
                      "error": true,
                      "statusCode": 502,
                      "statusMessage": "grants_query_failed",
                      "message": "grants_query_failed",
                      "data": {
                        "code": "grants_query_failed"
                      }
                    }
                  },
                  "api_key_lookup_failed": {
                    "value": {
                      "error": true,
                      "statusCode": 502,
                      "statusMessage": "api_key_lookup_failed",
                      "message": "api_key_lookup_failed",
                      "data": {
                        "code": "api_key_lookup_failed"
                      }
                    }
                  },
                  "rate_limit_check_failed": {
                    "value": {
                      "error": true,
                      "statusCode": 502,
                      "statusMessage": "rate_limit_check_failed",
                      "message": "rate_limit_check_failed",
                      "data": {
                        "code": "rate_limit_check_failed"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "Grant": {
        "type": "object",
        "required": [
          "id",
          "nome_del_bando",
          "promotore",
          "emanazione",
          "tipo",
          "descrizione_breve",
          "descrizione_del_bando",
          "stato_del_bando",
          "fondi_esauriti",
          "data_di_apertura",
          "scadenza",
          "scadenza_interna",
          "richiesta_minima",
          "richiesta_massima",
          "dotazione",
          "percentuale_fondo_perduto",
          "descrizione_tipo_agevolazione",
          "modalita_di_erogazione",
          "regime_di_aiuto",
          "cumulabilita",
          "a_chi_si_rivolge_descrizione",
          "spese_ammissibili_descrizione",
          "esempi_progetti_ammissibili",
          "iter_presentazione_domanda",
          "documentazione_necessaria",
          "link_al_sito_del_bando",
          "sede_non_richiesta",
          "ateco_non_applicabile",
          "max_company_age_months",
          "min_balance_sheets_required",
          "created_at",
          "updated_at",
          "codici_ateco_2025",
          "allegati",
          "localita",
          "province",
          "categorie",
          "a_chi_si_rivolge",
          "settori",
          "spese_ammissibili",
          "dimensioni_beneficiari"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Identificativo univoco e stabile del bando."
          },
          "nome_del_bando": {
            "type": "string",
            "description": "Titolo del bando."
          },
          "promotore": {
            "type": [
              "string",
              "null"
            ],
            "description": "Ente che promuove il bando."
          },
          "emanazione": {
            "type": [
              "string",
              "null"
            ],
            "description": "Livello dell'ente emanante, testo libero (es. «Regionale», «Nazionale», «CCIAA (camera di commercio)»). Può contenere più valori separati da virgola o essere vuoto."
          },
          "tipo": {
            "type": [
              "string",
              "null"
            ],
            "description": "Modalità di assegnazione, testo libero (es. «Procedura a sportello», «Esaurimento fondi», «Clickday»). Può essere vuoto."
          },
          "descrizione_breve": {
            "type": [
              "string",
              "null"
            ],
            "description": "Sintesi del bando."
          },
          "descrizione_del_bando": {
            "type": [
              "string",
              "null"
            ],
            "description": "Descrizione estesa del bando."
          },
          "stato_del_bando": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stato: Attivo, In scadenza, In uscita, Chiuso oppure Fondi esauriti."
          },
          "fondi_esauriti": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "true se le risorse del bando risultano esaurite."
          },
          "data_di_apertura": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Data di apertura delle domande."
          },
          "scadenza": {
            "type": [
              "string",
              "null"
            ],
            "description": "Scadenza come testo, così come pubblicata dalla fonte."
          },
          "scadenza_interna": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "description": "Scadenza normalizzata come data, da usare per ordinare e confrontare."
          },
          "richiesta_minima": {
            "type": [
              "number",
              "null"
            ],
            "description": "Importo minimo richiedibile, in euro."
          },
          "richiesta_massima": {
            "type": [
              "number",
              "null"
            ],
            "description": "Importo massimo richiedibile, in euro."
          },
          "dotazione": {
            "type": [
              "number",
              "null"
            ],
            "description": "Dotazione complessiva del bando, in euro."
          },
          "percentuale_fondo_perduto": {
            "type": [
              "number",
              "null"
            ],
            "description": "Quota a fondo perduto, in percentuale."
          },
          "descrizione_tipo_agevolazione": {
            "type": [
              "string",
              "null"
            ],
            "description": "Descrizione del tipo di agevolazione."
          },
          "modalita_di_erogazione": {
            "type": [
              "string",
              "null"
            ],
            "description": "Come viene erogata l'agevolazione."
          },
          "regime_di_aiuto": {
            "type": [
              "string",
              "null"
            ],
            "description": "Regime di aiuto, testo libero (es. «De Minimis», «GBER»). Può essere vuoto."
          },
          "cumulabilita": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "true se l'agevolazione è cumulabile con altre."
          },
          "a_chi_si_rivolge_descrizione": {
            "type": [
              "string",
              "null"
            ],
            "description": "Descrizione dei beneficiari."
          },
          "spese_ammissibili_descrizione": {
            "type": [
              "string",
              "null"
            ],
            "description": "Descrizione delle spese ammissibili."
          },
          "esempi_progetti_ammissibili": {
            "type": [
              "string",
              "null"
            ],
            "description": "Esempi di progetti ammissibili."
          },
          "iter_presentazione_domanda": {
            "type": [
              "string",
              "null"
            ],
            "description": "Come si presenta la domanda."
          },
          "documentazione_necessaria": {
            "type": [
              "string",
              "null"
            ],
            "description": "Documenti richiesti per la domanda."
          },
          "link_al_sito_del_bando": {
            "type": [
              "string",
              "null"
            ],
            "description": "Link alla pagina ufficiale del bando."
          },
          "sede_non_richiesta": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "true se il bando non richiede una sede nel territorio."
          },
          "ateco_non_applicabile": {
            "type": "boolean",
            "description": "true se per il bando i codici ATECO non si applicano."
          },
          "max_company_age_months": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Età massima dell'impresa in mesi. Oggi sempre null."
          },
          "min_balance_sheets_required": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Numero minimo di bilanci depositati richiesto."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "2026-09-25T14:19:04.154822"
            ],
            "description": "Inserimento nel catalogo, in UTC senza indicazione del fuso."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "2026-09-25T14:19:04.154822"
            ],
            "description": "Ultimo aggiornamento, in UTC senza indicazione del fuso."
          },
          "codici_ateco_2025": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Codici ATECO 2025 ammessi. Elenco vuoto se il bando non ne indica."
          },
          "allegati": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Allegato"
            },
            "description": "Allegati: tipo_allegato (compilativo, documento, informativo), numero, nome_file, url."
          },
          "localita": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Territori del bando: regioni oppure «Italia», «Europa», «Mondo»."
          },
          "province": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Provincia"
            },
            "description": "Province interessate, con codice e nome."
          },
          "categorie": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tipologie di agevolazione (es. Fondo Perduto, Voucher, Tasso Agevolato)."
          },
          "a_chi_si_rivolge": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Categorie di beneficiari."
          },
          "settori": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Settori economici interessati."
          },
          "spese_ammissibili": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Categorie di spese ammissibili."
          },
          "dimensioni_beneficiari": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Dimensioni d'impresa ammesse."
          }
        }
      },
      "Provincia": {
        "type": "object",
        "required": [
          "codice",
          "nome"
        ],
        "properties": {
          "codice": {
            "type": "string"
          },
          "nome": {
            "type": "string"
          }
        }
      },
      "Allegato": {
        "type": "object",
        "required": [
          "tipo_allegato",
          "numero",
          "nome_file",
          "url"
        ],
        "properties": {
          "tipo_allegato": {
            "type": [
              "string",
              "null"
            ],
            "description": "compilativo, documento oppure informativo."
          },
          "numero": {
            "type": [
              "integer",
              "null"
            ]
          },
          "nome_file": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "page",
          "limit",
          "total",
          "total_pages",
          "has_next"
        ],
        "properties": {
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "has_next": {
            "type": "boolean"
          }
        }
      },
      "ApiKeyInfo": {
        "type": "object",
        "required": [
          "expires_at",
          "max_grants",
          "regione"
        ],
        "properties": {
          "expires_at": {
            "type": "string",
            "description": "Scadenza della chiave (ISO 8601)."
          },
          "max_grants": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Numero di bandi visibili: 10 per gli account di prova (sempre gli stessi 10), null per gli account completi."
          },
          "regione": {
            "type": "null",
            "description": "Sempre null. Il campo resta solo per compatibilità: l'accesso dipende dal piano dell'account (prova o completo), non dalla regione."
          }
        }
      },
      "GrantList": {
        "type": "object",
        "required": [
          "data",
          "pagination",
          "api_key"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Grant"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "api_key": {
            "$ref": "#/components/schemas/ApiKeyInfo"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "statusCode",
          "statusMessage",
          "data"
        ],
        "properties": {
          "error": {
            "type": "boolean"
          },
          "url": {
            "type": "string"
          },
          "statusCode": {
            "type": "integer"
          },
          "statusMessage": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "data": {
            "type": "object",
            "required": [
              "code"
            ],
            "properties": {
              "code": {
                "type": "string"
              }
            },
            "additionalProperties": true
          }
        }
      }
    }
  }
}
