{
 "openapi": "3.1.0",
 "info": {
  "title": "Koapanel Partner API",
  "version": "1.0.0",
  "description": "API per i provider che rivendono licenze Koapanel (modulo WHMCS koapanel_license o qualsiasi sistema di fatturazione). Autenticazione con la chiave partner (`Authorization: Bearer kpp_…`), fornita dallo staff Koapanel e mostrata una sola volta. Al massimo 120 richieste al minuto per chiave. Errori: `{\"error\":{\"code\",\"message\"}}` con messaggio in italiano.\n\nAPI for providers reselling Koapanel licences. Bearer partner key, 120 requests/minute per key, errors as `{\"error\":{\"code\",\"message\"}}`.",
  "contact": {
   "name": "Prime Software S.r.l.s.",
   "url": "https://koapanel.app"
  }
 },
 "servers": [
  {
   "url": "https://console.koapanel.app/api/v1/partner"
  }
 ],
 "security": [
  {
   "partnerKey": []
  }
 ],
 "tags": [
  {
   "name": "Account"
  },
  {
   "name": "Licenze"
  },
  {
   "name": "Fatturazione"
  }
 ],
 "paths": {
  "/me": {
   "get": {
    "tags": [
     "Account"
    ],
    "summary": "Il partner e i piani",
    "description": "Nome e stato del partner, piani abilitati con il prezzo all'ingrosso.",
    "operationId": "getMe",
    "responses": {
     "200": {
      "description": "Partner",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "partner": {
           "$ref": "#/components/schemas/Partner"
          },
          "plans": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Plan"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/plans": {
   "get": {
    "tags": [
     "Account"
    ],
    "summary": "Piani abilitati",
    "description": "I piani che il partner può vendere, con siti inclusi e prezzo all'ingrosso mensile.",
    "operationId": "listPlans",
    "responses": {
     "200": {
      "description": "Piani",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "plans": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Plan"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/licenses": {
   "get": {
    "tags": [
     "Licenze"
    ],
    "summary": "Elenco licenze",
    "description": "Le licenze del partner, 100 per pagina (senza codice). Filtri: externalId, status.",
    "operationId": "listLicenses",
    "responses": {
     "200": {
      "description": "Licenze",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "licenses": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/License"
           }
          },
          "next": {
           "type": "string",
           "description": "Da passare come `page` per la pagina successiva; vuoto se è l'ultima."
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "parameters": [
     {
      "name": "externalId",
      "in": "query",
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "status",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "active",
        "suspended",
        "revoked"
       ]
      }
     },
     {
      "name": "page",
      "in": "query",
      "schema": {
       "type": "string"
      }
     }
    ]
   },
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Crea una licenza",
    "description": "Emette una licenza del piano indicato per un cliente del partner. Rispetta `Idempotency-Key` (conservata 7 giorni): stessa chiave e stessa richiesta → 200 con la licenza già creata e `replayed: true`; stessa chiave e richiesta diversa → 409 `idempotency_mismatch`. `externalId` è unico tra le licenze non revocate del partner.",
    "operationId": "createLicense",
    "responses": {
     "201": {
      "description": "Creata",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          },
          "replayed": {
           "type": "boolean"
          }
         }
        }
       }
      }
     },
     "200": {
      "description": "Richiesta ripetuta (idempotenza)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          },
          "replayed": {
           "type": "boolean",
           "const": true
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/CreateLicense"
       }
      }
     }
    },
    "parameters": [
     {
      "name": "Idempotency-Key",
      "in": "header",
      "schema": {
       "type": "string",
       "maxLength": 200
      },
      "example": "whmcs-1234"
     }
    ]
   }
  },
  "/licenses/{id}": {
   "get": {
    "tags": [
     "Licenze"
    ],
    "summary": "Una licenza",
    "description": "La licenza con il codice di attivazione (`token`).",
    "operationId": "getLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/suspend": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Sospendi",
    "description": "Il pannello torna ai limiti gratuiti al controllo successivo; i siti restano online. Alias: nessuno.",
    "operationId": "suspendLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "reason": {
          "type": "string",
          "maxLength": 300
         }
        },
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/reactivate": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Riattiva",
    "description": "Riattiva una licenza sospesa. Alias: `/unsuspend`.",
    "operationId": "reactivateLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/revoke": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Revoca (definitiva)",
    "description": "Revoca la licenza; la fatturazione si ferma alla fine del giorno. Alias: `/terminate`.",
    "operationId": "revokeLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "reason": {
          "type": "string",
          "maxLength": 300
         }
        },
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/plan": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Cambia piano",
    "description": "Upgrade o downgrade, con pro rata sul rendiconto all'ingrosso. Il pannello riceve il codice aggiornato al controllo successivo. Solo licenze attive (409 altrimenti).",
    "operationId": "changePlan",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "plan": {
          "type": "string"
         }
        },
        "required": [
         "plan"
        ],
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/release": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Libera dal server",
    "description": "Scollega il server: il codice si può attivare su un altro server. Al massimo 3 volte in 30 giorni (poi 409).",
    "operationId": "releaseLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/licenses/{id}/reissue": {
   "post": {
    "tags": [
     "Licenze"
    ],
    "summary": "Riemetti il codice",
    "description": "Firma di nuovo il codice con i dati attuali (dopo un cambio di piano, o se il codice va sostituito) e lo restituisce.",
    "operationId": "reissueLicense",
    "responses": {
     "200": {
      "description": "La licenza",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "license": {
           "$ref": "#/components/schemas/License"
          }
         },
         "required": [
          "license"
         ]
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "additionalProperties": false
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      },
      "example": "LIC-8C1D2E3F4A5B"
     }
    ]
   }
  },
  "/usage": {
   "get": {
    "tags": [
     "Fatturazione"
    ],
    "summary": "Consumo del mese",
    "description": "Il rendiconto del mese indicato (predefinito: il mese in corso, fino a ora): una riga per licenza e periodo di piano, giorni e importo netto.",
    "operationId": "getUsage",
    "responses": {
     "200": {
      "description": "Consumo",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "usage": {
           "$ref": "#/components/schemas/Statement"
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "parameters": [
     {
      "name": "month",
      "in": "query",
      "schema": {
       "type": "string",
       "pattern": "^\\d{4}-\\d{2}$"
      },
      "example": "2026-09"
     }
    ]
   }
  },
  "/statements": {
   "get": {
    "tags": [
     "Fatturazione"
    ],
    "summary": "Rendiconti mensili",
    "description": "I rendiconti chiusi (senza righe), con il numero della fattura elettronica.",
    "operationId": "listStatements",
    "responses": {
     "200": {
      "description": "Rendiconti",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "statements": {
           "type": "array",
           "items": {
            "$ref": "#/components/schemas/Statement"
           }
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    }
   }
  },
  "/statements/{month}": {
   "get": {
    "tags": [
     "Fatturazione"
    ],
    "summary": "Un rendiconto",
    "description": "Il rendiconto di un mese con le righe.",
    "operationId": "getStatement",
    "responses": {
     "200": {
      "description": "Rendiconto",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "statement": {
           "$ref": "#/components/schemas/Statement"
          }
         }
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/Error"
     },
     "401": {
      "$ref": "#/components/responses/Error"
     },
     "403": {
      "$ref": "#/components/responses/Error"
     },
     "404": {
      "$ref": "#/components/responses/Error"
     },
     "409": {
      "$ref": "#/components/responses/Error"
     },
     "429": {
      "$ref": "#/components/responses/Error"
     }
    },
    "parameters": [
     {
      "name": "month",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "pattern": "^\\d{4}-\\d{2}$"
      }
     }
    ]
   }
  }
 },
 "components": {
  "securitySchemes": {
   "partnerKey": {
    "type": "http",
    "scheme": "bearer",
    "bearerFormat": "kpp_<64 hex>"
   }
  },
  "responses": {
   "Error": {
    "description": "Errore: unauthorized (401), forbidden (403, partner sospeso), not_found (404, anche per licenze di altri partner), validation (400), conflict o idempotency_mismatch (409), rate_limited (429 con Retry-After).",
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  },
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "error": {
      "type": "object",
      "properties": {
       "code": {
        "type": "string",
        "enum": [
         "unauthorized",
         "forbidden",
         "not_found",
         "validation",
         "conflict",
         "idempotency_mismatch",
         "rate_limited",
         "internal"
        ]
       },
       "message": {
        "type": "string"
       }
      },
      "required": [
       "code",
       "message"
      ]
     }
    },
    "required": [
     "error"
    ]
   },
   "Partner": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "prt_3f9a1c2b7d"
     },
     "name": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "suspended"
      ]
     }
    }
   },
   "Plan": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "pro"
     },
     "name": {
      "type": "string"
     },
     "maxSites": {
      "type": "integer",
      "description": "0 = illimitati"
     },
     "wholesaleCents": {
      "type": "integer",
      "description": "Il tuo prezzo per server al mese, IVA esclusa (riservato: fascia di volume attuale o prezzo concordato)"
     },
     "currency": {
      "type": "string",
      "example": "EUR"
     },
     "publicCents": {
      "type": "integer",
      "description": "Prezzo pubblico mensile del piano"
     },
     "custom": {
      "type": "boolean",
      "description": "Prezzo concordato (non la fascia)"
     },
     "discountBp": {
      "type": "integer",
      "description": "Sconto della fascia in punti base (0 con prezzo concordato)"
     }
    }
   },
   "Customer": {
    "type": "object",
    "properties": {
     "name": {
      "type": "string",
      "maxLength": 120
     },
     "email": {
      "type": "string",
      "format": "email"
     },
     "country": {
      "type": "string",
      "pattern": "^[A-Z]{2}$"
     }
    }
   },
   "CreateLicense": {
    "type": "object",
    "required": [
     "plan"
    ],
    "additionalProperties": false,
    "properties": {
     "plan": {
      "type": "string"
     },
     "externalId": {
      "type": "string",
      "maxLength": 100,
      "example": "whmcs-1234"
     },
     "customer": {
      "$ref": "#/components/schemas/Customer"
     },
     "hostname": {
      "type": "string",
      "maxLength": 253
     }
    }
   },
   "License": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string",
      "example": "LIC-8C1D2E3F4A5B"
     },
     "plan": {
      "type": "string"
     },
     "planName": {
      "type": "string"
     },
     "maxSites": {
      "type": "integer"
     },
     "status": {
      "type": "string",
      "enum": [
       "active",
       "suspended",
       "revoked"
      ]
     },
     "effective": {
      "type": "string",
      "enum": [
       "active",
       "suspended",
       "revoked",
       "expired",
       "never_activated"
      ]
     },
     "statusReason": {
      "type": "string"
     },
     "externalId": {
      "type": "string"
     },
     "customer": {
      "$ref": "#/components/schemas/Customer"
     },
     "token": {
      "type": "string",
      "description": "Codice di attivazione (Koapanel › Piano e licenza › Inserisci codice). Solo in creazione, lettura singola, cambio piano e riemissione."
     },
     "hostname": {
      "type": "string"
     },
     "boundServerId": {
      "type": "string"
     },
     "lastSeenAt": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "panelVersion": {
      "type": "string"
     },
     "siteCount": {
      "type": [
       "integer",
       "null"
      ]
     },
     "issuedAt": {
      "type": "string",
      "format": "date-time"
     },
     "expiresAt": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time",
      "description": "Sempre null: le licenze dei partner non scadono finché sono attive"
     },
     "revokedAt": {
      "type": "string",
      "format": "date-time"
     }
    }
   },
   "StatementLine": {
    "type": "object",
    "properties": {
     "licenseId": {
      "type": "string"
     },
     "externalId": {
      "type": "string"
     },
     "customer": {
      "type": "string"
     },
     "plan": {
      "type": "string"
     },
     "priceCents": {
      "type": "integer"
     },
     "from": {
      "type": "string",
      "format": "date-time"
     },
     "to": {
      "type": "string",
      "format": "date-time"
     },
     "days": {
      "type": "integer"
     },
     "netCents": {
      "type": "integer"
     },
     "custom": {
      "type": "boolean"
     }
    }
   },
   "Statement": {
    "type": "object",
    "properties": {
     "month": {
      "type": "string",
      "example": "2026-09"
     },
     "lines": {
      "type": [
       "array",
       "null"
      ],
      "items": {
       "$ref": "#/components/schemas/StatementLine"
      }
     },
     "netCents": {
      "type": "integer",
      "description": "Imponibile, IVA esclusa"
     },
     "currency": {
      "type": "string"
     },
     "licenses": {
      "type": "integer"
     },
     "final": {
      "type": "boolean",
      "description": "Il mese è finito"
     },
     "status": {
      "type": "string",
      "enum": [
       "invoiced",
       "empty",
       "error"
      ]
     },
     "invoiceNumber": {
      "type": "string",
      "example": "KP-2026-0042"
     },
     "invoiceStatus": {
      "type": "string"
     },
     "tier": {
      "type": "object",
      "description": "Fascia applicata al mese: licenze attive (su un server) a fine mese",
      "properties": {
       "minActive": {
        "type": "integer"
       },
       "discountBp": {
        "type": "integer"
       },
       "activeLicenses": {
        "type": "integer"
       },
       "source": {
        "type": "string",
        "enum": [
         "month_end",
         "current"
        ]
       }
      }
     }
    }
   }
  }
 }
}
